问题
We have background job running that requires a user to be active. The following way works fine but we have to hard-code the password which is not ideal.
try {
session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
} catch (RepositoryException ex) {
log.error("SessionHelper - login issue", ex);
}
We attempt a better way to set active user without setting password as follows:
Map<String, Object> params = new HashMap<String, Object>();
params.put(ResourceResolverFactory.SUBSERVICE, "theService");
ResourceResolver resolver = null;
try {
resolver = resolverFactory.getServiceResourceResolver(params);
} catch (LoginException e) {
log.error("LoginException", e);
}
Session session = resolver.adaptTo(Session.class);
// Next, create pages and add properties ...
We then try to create pages and set properties. This works fine for couple of milliseconds where some pages are created but then throws Exception to indicate session is closed although never closed and the location where exception gets thrown is unpredictable.
javax.jcr.RepositoryException: This session has been closed. See the chained exception for a trace of where the session was closed.
...
Caused by: java.lang.Exception: Stack trace of where session-admin-20077 was originally closed
We want to know whether there is any way to set the timeout? Any recommendations appreciated.
回答1:
You should obtain the session always through the ResourceResolverFactory using the getServiceResourceResolver method (getAdministrativeResourceResolver method is actually deprecated and should be avoided), execute than your code in the same try/catch block and define a finally block where you can make sure that the obtained resolver/session is closed properly. If you follow this princip, you will probably never experience problems with closed or unclosed sessions.
@org.apache.felix.scr.annotations.Component(...)
public class MyComponent {
@org.apache.felix.scr.annotations.Reference
private org.apache.sling.api.resource.ResourceResolverFactory resourceResolverFactory;
public void myaction() {
org.apache.sling.api.resource.ResourceResolver resolver = null;
try {
Map<String, Object> authInfo = new HashMap<String, Object>();
authInfo.put(ResourceResolverFactory.SUBSERVICE, getClass.getName());
resolver = resourceResolverFactory.getServiceResourceResolver(authInfo);
javax.jcr.Session session = resolver.adaptTo(javax.jcr.Session.class);
javax.jcr.Node node = session.getNode("/jcr/path/to/the-node");
// do something with the node
session.save();
} catch(LoginException e) {
// Handle cannot obtain instance of the resource resolver
} catch(RepositoryException e) {
//handle the repository exception
} finally {
//do not forget to close the resolver, otherwise this can cause huge performance problems
if(resolver != null) {
resolver.close();
}
}
}
}
In order to obtain service resource resolver, you need also to configure the user.mapping in the OSGI-Service org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl for example as follows.:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
user.mapping="[tld.mycompany.mypackage=admin]"
user.default="admin"/>
This way you can set and offer very advanced access control policies for your services.
If you are in a sling servlet, be carefull which resource resolver you are using. In the normal case, you will not need a resource resolver with administrative rights, but take the one provided by the SlingHttpServletRequest. The resource resolver is closed by sling at the end of the request, don't close it manually.
回答2:
If you are using the admin session I suggest to not log it in like you did, but with the following method (asuming from your code you have the SlingRepository already injected with @Reference):
repository.loginAdministrative(null);
And to prevent the error I would use the following pattern:
Session session = null;
try {
session = repository.loginAdministrative(null);
//do what you need to do
} catch (RepositoryException e) {
//handle exception
} finally {
if (session != null && session.isLive()) {
session.logout();
}
}
And one last note, open and close the sessionin the same thread, so not keeping the session alive in a service, except it is an EventListener.
来源:https://stackoverflow.com/questions/29664351/set-active-user-to-aem-background-job-throws-exception-unexpectedly