将活动用户设置为AEM后台作业会意外地抛出异常

时间:2015-04-16 02:29:43

标签: cq5 aem

我们正在运行后台作业,要求用户处于活动状态。以下方式工作正常,但我们必须硬编码不理想的密码。

try {
    session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
} catch (RepositoryException ex) {
    log.error("SessionHelper - login issue", ex);
}

我们尝试更好的方法来设置活动用户而不设置密码,如下所示:

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 ...

然后我们尝试创建页面并设置属性。这可以正常工作几毫秒,其中一些页面被创建,但然后抛出异常以指示会话已关闭,但从未关闭,并且异常被抛出的位置是不可预测的。

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

我们想知道是否有办法设置超时?任何建议都赞赏。

2 个答案:

答案 0 :(得分:3)

您应该始终通过ResourceResolverFactory使用getServiceResourceResolver方法获取会话(getAdministrativeResourceResolver方法实际上已被弃用且应该避免),执行比同一个try / catch块中的代码并定义finally块,您可以确保获得的解析器/会话正确关闭。如果您遵循此原则,您可能永远不会遇到关闭或未关闭会话的问题。

      @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();
                }
            }
         }
      }

为了获得服务资源解析器,您还需要在OSGI-Service org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl中配置user.mapping,例如如下所示。:

<?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"/>

通过这种方式,您可以为您的服务设置并提供非常高级的访问控制策略。

如果您使用的是吊索servlet,请注意您正在使用的资源解析程序。在正常情况下,您不需要具有管理权限的资源解析程序,而是使用SlingHttpServletRequest提供的资源解析程序。资源解析器在请求结束时通过吊索关闭,不要手动关闭它。

答案 1 :(得分:0)

如果你正在使用管理员会话,我建议不要像你那样登录,但是使用以下方法(从你的代码中得知你已经注入了@Reference的SlingRepository):

repository.loginAdministrative(null);

为了防止错误,我会使用以下模式:

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();
    }
}

最后一点,在同一个线程中打开和关闭会话,这样就不会在会话中保持会话活动,除非它是一个EventListener。