4

I want to be able to launch the creation of an Alfresco node Asynchronously to prevent a creation bottneck.

For that I'm trying to use ScheduledExecutorService initialized with value 10.

Execution Processed like follow :

from my UploadServlet --> (public) UploadManager#createNodeRef(SOME_PARAMS) --> (private synchronized) UploadManager#createNodeRef(SOME_PARAMS)

Transaction is managed inside UploadServlet

Code :

private synchronized NodeRef createNodeRef(ARGS) {
  //
  // Creation Code using other Alfresco/Spring beans
  //
  return RETURN_VALUE;
}

Async Code (What I'm trying to do)

    private NodeRef makeAsyncNodeCreation(ARGS) {
    final ScheduledFuture<NodeRef> scheduledFuture = nodeCreationExecutor.schedule(new Callable<NodeRef>() {
        @Override
        public NodeRef call() throws Exception {
            // HERE I MAKE THE EFFECTIVE NODE CREATION
            return createNodeRef(filename, type, parentNode, label, kinematic);
        }
    }, MAX_NODE_CREATION_DELAY_IN_SECONDS, SECONDS);

    try {
        return scheduledFuture.get();
    } catch (InterruptedException e) {
        throw new AsyncNodeCreationException(e);
    } catch (ExecutionException e) {
        throw new AsyncNodeCreationException(e);
    }
}

Then the public method

public NodeRef create(ARGS) {
    return makeAsyncNodeCreation(ARGS);
}

The problem

I have the following exception

net.sf.acegisecurity.AuthenticationCredentialsNotFoundException: A valid SecureContext was not provided in the RequestContext

My Question Why SecureContext does no more exist within my async call ?

Abderrazak BOUADMA
  • 1,526
  • 2
  • 16
  • 38

1 Answers1

2

Because the SecurityContext is hold by SecurityContextHolder in a ThreadLocal Variable (the default strategy) thus the current thread, you need to pass the SecurityContext to the Callable because it's running in a different thread and then inject it to it's own ThreadLocal in SecurityContextHolder.

I hope this solution applies to Acegi Security :

 // Get the SecurityContext hold by the main thread
 final SecurityContext securityContext = SecurityContextHolder.getContext();

 final ScheduledFuture<NodeRef> scheduledFuture = nodeCreationExecutor.schedule(new Callable<NodeRef>() {

  @Override
   public NodeRef call() throws Exception {

    // Inject the securityContext 
    SecurityContextHolder.setContext(securityContext);

    // HERE I MAKE THE EFFECTIVE NODE CREATION
    NodeRef noderef = createNodeRef(filename, type, parentNode, label, kinematic);

    // Cleaning...the thread may be recycled
    SecurityContextHolder.setContext(null);

    return noderef;

 }
}, MAX_NODE_CREATION_DELAY_IN_SECONDS, SECONDS);