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 ?
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);