Set Active User to AEM background job throws Exception unexpectedly

陌路散爱 提交于 2020-01-07 07:45:11

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!