how to get session object from resource resolver factory? - java

#Component
public class AddNode {
#Reference
static ResourceResolverFactory resolverFactory;
static Session session;
public static void main(String[] args) throws Exception {
ResourceResolver resourceResolver = resolverFactory.getServiceResourceResolver(null);
session = resourceResolver.adaptTo(Session.class);
Node root = session.getRootNode();
Node adobe = root.addNode("ProgramNode");
Node day = adobe.addNode("subnode");
day.setProperty("jcr:title", "programNode");
Node node = root.getNode("ProgramNode/subnode");
System.out.println(node.getPath());
System.out.println(node.getProperty("jcr:title").getString());
session.save();
session.logout();
}
}
here resolverFactory.getServiceResourceResolver(null); i need to pass any parameter at null.please give some example to get access of repository.

We should use System Users to access repository when accessing via Factory. You would need to
Create system user, provide appropriate permissions
Map bundle symbolic name to system user
Use system user to get session via ResourceResolverFactory
Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "<sub-service-name>");
ResourceResolver resolver = null;
resolver = resolverFactory.getServiceResourceResolver(param);
session = resolver.adaptTo(Session.class);
You can refer this helpx link article also to get idea about using Service Users to create session

Have a look at the documentation of ResourceResolverFactory.
https://sling.apache.org/apidocs/sling7/org/apache/sling/api/resource/ResourceResolverFactory.html

Related

MongoURI #value variable is getting nulled

In my code below, mongoURI initially pulls the correct URI string from application.properties, and connects to the database successfully. However, once I make a call to getUserByAuth0ID, I'm getting a "java.net.UnknownHostException: null: Name or service not known" error and debug statements show that mongoURI is now set to null.
What's going on? Nowhere in my code do I touch the value of mongoURI. My previous version of the code has mongoURI hardcoded as a variable and it runs with no issues.
#Service
public class DBConnectService {
private static MongoCollection<User> users;
private static Logger logger = LogManager.getLogger(DBConnectService.class);
#Value("${package.mongoURI}")
private String mongoURI;
/** Opens a connection to mongodb for the length of the program operation */
#PostConstruct
public void init() {
logger.info("Connecting to MongoDB");
try {
System.out.println (mongoURI); // URI prints out correctly here
CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build());
CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry);
MongoClientSettings clientSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(mongoURI))
.codecRegistry(codecRegistry)
.build();
MongoClient mongoClient = MongoClients.create(clientSettings);
MongoDatabase database = mongoClient.getDatabase("db");
users = database.getCollection("users", User.class);
} catch(Exception e) {
logger.error("MongoDB connection failure:\n" + e);
}
}
public User getUserByAuth0ID (String authID) {
System.out.println (mongoURI); // URI prints out here as null
User user = getUser(authID, "auth0ID");
if (user == null) {
user = createUserAccount(authID);
}
return user;
}
public static User getUser (String info, String field) {
User user = users.find(eq(field, info)).first();
return user;
}
public static User createUserAccount (String authID) {
JsonObject newUserInfo = Auth0Service.getUserInfo(authID);
if (newUserInfo.get("email_verified").getAsBoolean()) {
User newUser = new User()
.setEmail(newUserInfo.get("email").getAsString())
.setName(newUserInfo.get("name").getAsString())
.setAuth0ID(authID);
users.insertOne(newUser);
return newUser;
} else {
logger.info ("Email NOT verified");
return null;
}
}
Application.properties line:
# --- MongoDB ---
package.mongoURI = mongodb+srv://admin:secretURL/?retryWrites=true&w=majority
Your #Value annotation has incorrect details of mongoURI.Either use #Value("${nornir.mongoURI}") or change to package.mongoURI inside application.properties.
Edit:
It is more likely you are calling getUserByAuth0ID manually something like --
DBConnectService service = new DBConnectService();
service.getUserByAuth0ID();
Because if mongoURI is coming as null, it means, this method getUserByAuth0ID is not getting called via spring way, i.e. by autowiring DBConnectService & then accessing this method; but rather it is getting called manually i.e. by manually creating object of DBConnectService.
If this is case, then it is obvious that your normal java object don't know about #Value annotation & hence it is not setting any value.
#PostConstruct will always works as it will get executed at startup when bean is getting created & hence #Value is working properly there.
To fix this issue, make sure you have spring bean of DBConnectService & you are accessing getUserByAuth0ID via that bean.
Edit 2 : --
Basic pseudo about how to use this in your calling class :
#Autowired
DBConnectService service;
public void yourdbMethod(){
service.getUserByAuth0ID();
}

How to get ResourceResolver in a background thread?

I'm working on a solution in Adobe Experience Manager (AEM) that receives an HTTP request containing a URL to a file, which I want to download and store in the JCR.
So, I have a servlet that receives the request. It spawns a thread so that I can do the download in the background, and then redirects to a confirmation page. This allows me to send the user on their way without waiting while I try to download the file.
I can download the file just fine, but I'm having trouble getting a usable ResourceResolver to store the file in the JCR from my thread.
At first, I simply referenced the request's ResourceResolver in the background thread:
Servlet:
public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
throws ServletException, IOException {
...
signingProvider.getDocFromService(params, request.getResourceResolver());
response.sendRedirect(confirmationPage);
}
And in the provider class:
public void getDocFromService(Map<String, String> params, ResourceResolver resolver) {
new Thread( new Runnable() {
public void run() {
Session session = null;
if (resolver != null) {
session = resolver.adaptTo(Session.class);
Node root = session.getRootNode();
...
}
}
}
}
but that didn't work. After reading up on resolvers vs threads, I thought I would be better off creating a new Resolver instance, so I tried to inject a ResourceResolverFactory:
Servlet:
signingProvider.getDocFromService(params);
Provider:
public void getDocFromService(Map<String, String> params) {
new Thread( new Runnable() {
#Reference
private ResourceResolverFactory resolverFactory;
// security hole, fix later
ResourceResolver resolver = resolverFactory.getAdministrativeResourceResolver(null);
Session session = null;
if (resolver != null) {
session = resolver.adaptTo(Session.class);
Node root = session.getRootNode();
...
}
}
}
but the ResourceResolverFactory is null, so I crash when asking it for a resolver. Apparently, no factory is getting injected into the #Reference
I would really rather not do the work on the main thread; after I download the file I'm going to turn around and read it from the JCR and copy it elsewhere. Both of these operations could be slow or fail. I have a copy of the file at the original URL, so the end-user needn't care if my download/uploads had trouble. I just want to send them a confirmation so they can get on with business.
Any advice on how to get a ResourceResolver in a separate thread?
For things like post\background processing you can use Sling Jobs. Please refer to the documentation to find out some details.
Note: #daniil-stelmakh brings a good point in his answer, sling jobs are much better suited for your purpose, to add to his answer, here is a sling tutorial that demonstrates sling jobs: https://sling.apache.org/documentation/tutorials-how-tos/how-to-manage-events-in-sling.html
To answer your question directly:
The issue, really is the placement of #Reference annotation.
That annotation is handled by Maven SCR Plugin and it should be placed on a private member of a '#Component' annotated class.
Basically move your ResourceResolverFactory declaration to become a private member of your class, not the Thread.
#Component(
label = "sample service",
description = "sample service"
)
#Service
public class ServiceImpl {
#Reference
private ResourceResolverFactory resolverFactory;
public void getDocFromService(Map<String, String> params) {
new Thread( new Runnable() {
// security hole, fix later
ResourceResolver resolver = resolverFactory.getAdministrativeResourceResolver(null);
Session session = null;
if (resolver != null) {
session = resolver.adaptTo(Session.class);
Node root = session.getRootNode();
...
}
}
}
}

AEM Reverse Replication with two publisher

I Have two Publisher and one Author Server.
I use reverse Replication for Usergenerated Content, for modified Content.
So I have also a Forward Replication (Selfmade, because AEM havent).
The Problem is, that the Replication between the Publisher going in an endless loop. So they replicate like playing ping pong.
What can I do about the ping pong play of the publishers?
I'm Using CQ 6.1, Java 1.7
I found a Solution.
Set Replication Options --> watch printscreen
Adapt WorkflowSession in Session class to replicate
Close Sessionafter replication
Never close Workflow Session
Clean outbox on publishers in crx (/var/replication/outbox) [every time, if something fails]
Create Launcher for Reverse replication Create & Modified (with condition: cq:distribute!=)
Create Launcher for Forward replication Create & Modified (code example)
Because I have more than one Forward Replicator, I made an Abstract
Class. If you don't use it, put all in one class
Attention: with ReplicationOption setSynchronous(true), the
replication was fine to replicate from publisher to publisher. But
because I have an administration page on author, I have to unncomment
this attribute. Because the changes on Auhtor were not replicated to
the publishe
#Component(immediate = true)
#Service(value = WorkflowProcess.class)
public class ReplicateUsergeneratedContentToPublishWorkflow extends AbstractAuthorToPublishWorkflow implements WorkflowProcess{
// OSGI properties
#Property(value = "This workflow replicate usergenerated content from author to publisher")
static final String DESCRIPTION = Constants.SERVICE_DESCRIPTION;
#Property(value = "Titel")
static final String VENDOR = Constants.SERVICE_VENDOR;
#Property(value = "Replicate the usergenerated content from one publisher via author to the ohter publisher")
static final String LABEL = "process.label";
private static final Logger LOGGER = LoggerFactory.getLogger(ReplicateUsergeneratedContentToPublishWorkflow.class);
#Reference
private ResourceResolverFactory resolverFactory;
#Reference
protected Replicator replicator;
#Reference
private SlingRepository repository;
#Reference
SlingSettingsService slingSettingsService;
#Override
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaDataMap) throws WorkflowException {
Session session = null;
SimpleCredentials administrator = new SimpleCredentials("username", "password".toCharArray());
try {
java.util.Set<String> runModes = slingSettingsService.getRunModes();
session = repository.login(administrator);
//the replication need to check the payload
String payload = workItem.getWorkflowData().getPayload().toString();
Node node = null;
if (session.itemExists(payload)) {
node = (Node) session.getItem(payload);
}
activateNode(node, workflowSession, replicator);
//save all changes
session.save();
} catch (PathNotFoundException e) {
LOGGER.error("path not found", e);
workflowSession.terminateWorkflow(null);
} catch (ReplicationException e) {
LOGGER.error("error replicating content node", e);
workflowSession.terminateWorkflow(null);
} catch (RepositoryException e) {
LOGGER.error("error reading path to content node", e);
workflowSession.terminateWorkflow(null);
}finally{
if(session != null){
session.logout();
}
}
}
}
public abstract class AbstractAuthorToPublishWorkflow implements WorkflowProcess {
protected void activateNode(Node node, WorkflowSession workflowSession, Replicator replicator) throws RepositoryException, ReplicationException {
ReplicationOptions replicationOptions = new ReplicationOptions();
replicationOptions.setSuppressStatusUpdate(true);
replicationOptions.setSuppressVersions(true);
//replicationOptions.setSynchronous(true);
//the property cq:distribute is settet if the node should be replicated from publisher to author (set it in your own code)
if (node != null) {
node.setProperty("cq:distribute", (Value) null);
//important use WorkflowSession and adapt it to Session class, replication is going to an endless loop, if you doing it without WorkflowSession
replicator.replicate(workflowSession.adaptTo(Session.class), ReplicationActionType.ACTIVATE, node.getPath(), replicationOptions);
}
}
}
Special for User And Group forward Replication, don't interfere the deactivate action from useradmin on author
//Important that you don't interfer the Deactivate Action from useradmin
//do nothing if the action is deactivate!
if( !userNode.getProperty("cq:lastReplicationAction").getString().equals("Deactivate")) {
activateNode(userNode, workflowSession, replicator);
//save all changes
session.save();
}
And for the the codepart were I modifie a node in author, I add this
//quickfix
//FrameworkUtil.getBundle(NodeManageDAO.class).getBundleContext()
BundleContext bundleContext = FrameworkUtil.getBundle(PhotoNodeManagerDAO.class).getBundleContext();
ServiceReference serviceReference = bundleContext.getServiceReference(SlingSettingsService.class.getName( ));
SlingSettingsService slingSettingsService = (SlingSettingsService)bundleContext.getService(serviceReference);
Set<String> runmode= slingSettingsService.getRunModes();
//just in author mode
if(runmode.contains("author")) {
//attention replication from author is not working without nullable / delete the cq:distribute property
node.setProperty("cq:distribute", (Value)null);
}
If you have a updated your workflow model, than you have to restart the worklflow and clean the failures and the cadaverous from old replication configs. Clean on author and on each publisher seperated, go to crx under /etc/workflow/launcher/config.
For the reverse replicator on publisher, set also the condition: cq:distribute!=
and on each part in the code where you change the nodes, add the following three properties
node.setProperty("cq:distribute", ValueFactoryImpl.getInstance().createValue("true"));
node.setProperty("cq:lastModifiedBy", ValueFactoryImpl.getInstance().createValue(session.getUserID()));
node.setProperty("cq:lastModified", ValueFactoryImpl.getInstance().createValue(Calendar.getInstance()));
session.save();
Sample of the Launchers [authorserver]/etc/workflow.html --> launchers

Cannot instantiate class: org.jboss.naming.remote.client.InitialContextFactory in Three Tier Architecture

I am trying to connect jboss 7.1.1 final with Three tier architecture approach keeping connection logic in my business layer and access this business layer from my presentation layer. But it is throwing following exception
Cannot instantiate class: org.jboss.naming.remote.client.InitialContextFactory.
It's working fine if i keep jboss connection logic in same presentation layer.
following is my code in business logic.
public static void Connect()
{
try
{
javax.naming.Context context = null;
ConnectionFactory connectionFactory;
Connection connection;
Session session;
String topicName = "jms/topic/TestedTopic";
Destination dest = null;
MessageConsumer consumer = null;
TextListener listener = null;
java.util.Properties jndiProps = new java.util.Properties();
jndiProps.put(Context.__Fields.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
jndiProps.put(Context.__Fields.PROVIDER_URL, "remote://10.1.7.149:4447");
jndiProps.put(Context.__Fields.SECURITY_PRINCIPAL, "admin");
jndiProps.put(Context.__Fields.SECURITY_CREDENTIALS, "admin123");
jndiProps.put("jboss.naming.client.ejb.context", true);
context = new InitialContext(jndiProps);
connectionFactory = (ConnectionFactory)context.lookup("jms/RemoteConnectionFactory");
connection = connectionFactory.createConnection();
dest = (Destination)context.lookup(topicName);
session = connection.createSession(false, Session.__Fields.AUTO_ACKNOWLEDGE);
consumer = session.createConsumer(dest);
listener = new TextListener();
consumer.setMessageListener(listener);
connection.start();
}
catch (Exception)
{
//throw;
}
}
This is follow exception of a ClassNotFoundException. See the wiki for a solution.
Adding a reference to Visual Studio does not add a reference in the compiled output. Only if you use one class
in your code and not via reflection a reference is added.
There are 3 options:
The best is you use a full qualified .NET classname. This include also the dll name.
Or you use BootClassPathAssemby like in http://sourceforge.net/apps/mediawiki/ikvm/index.php?title=ClassLoader
Or you use one class file from the dll and use the AppDomainAssemblyClassLoader. Details are at http://sourceforge.net/apps/mediawiki/ikvm/index.php?title=ClassLoader

How to keep properties values in session scope?

I am using spring. i have an externalized properties file. i am loading it as below.
<context:property-placeholder location="file:///C:/some.properties"/>
Now how can i keep properties in session as key-value pair ?
i tried writing a listener which extends ServletContextListener.
public class Sample implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
//here i tried to get the values of properties file as below.
InputStream stream = event.getServletContext().getResourceAsStream("C:\\some.properties");
//But here stream is coming as null
}
}
Am i missing anything here?
Thanks!
SetvletContext's contextInitlalized() is called when the servlet context is initialized when the application loads successfully,
If you want to store it properties file in application context you can put it in
event.getServletContext().setAttribute("global_properties", propertiesInstance);
If you want it on per session, then you need to hook it into HttpSessionListener's sessionCreated() method
So put the data that is frequently used and that is shared across the application in applicationscope and the data that is limited to a session but frequently used put it in session
I would suggest use PropertyPlaceHolderConfigurer which communicates with a ServletContextListner. This class PropertyPlaceHolderConfigurer has one method call processProperties in which you could get the map of all the properties.
#Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
Properties props) throws BeansException {
super.processProperties(beanFactoryToProcess, props);
resolvedProps = new HashMap<String, String>();
for (Object key : props.keySet()) {
String keyStr = key.toString();
resolvedProps.put(keyStr, parseStringValue(props.getProperty(keyStr), props,
new HashSet()));
}
}
And in the listner contextInitialized() you could do like:
ServletContext servletContext = sce.getServletContext();
WebApplicationContext context = WebApplicationContextUtils
.getRequiredWebApplicationContext(servletContext);
ExposablePropertyPlaceHolder configurer =(ExposablePropertyPlaceHolder)context.getBean(propertiesBeanName);
sce.getServletContext().setAttribute(contextProperty, configurer.getResolvedProps());
where ExposablePropertyPlaceHolder is the class which extends PropertyPlaceHolderConfigurer.

Categories

Resources