Search code examples
javaosgiaemslingjcr

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?


Solution

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