package com.joshlong.activiti.coordinator.aop;
import com.joshlong.activiti.coordinator.annotations.StartProcess;
import com.joshlong.activiti.coordinator.annotations.ProcessVariable;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.util.Assert;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* {@link org.aopalliance.intercept.MethodInterceptor} that starts a business process
* as a result of a sucessful method invocation.
*
* @author Josh Long
*
*/
public class ProcessStartingMethodInterceptor implements MethodInterceptor {
/**
* injected reference - can be obtained via a {@link org.activiti.spring.ProcessEngineFactoryBean}
*/
protected ProcessEngine processEngine ;
/**
* @param processEngine takes a reference to a {@link org.activiti.engine.ProcessEngine}
*/
public ProcessStartingMethodInterceptor(ProcessEngine processEngine) {
this.processEngine = processEngine;
}
boolean shouldReturnProcessInstance( StartProcess startProcess,MethodInvocation methodInvocation , Object result){
return startProcess.returnProcessInstance() && (result instanceof ProcessInstance ||
methodInvocation.getMethod().getReturnType().isAssignableFrom(ProcessInstance.class));
}
boolean shouldReturnProcessInstanceId( StartProcess startProcess, MethodInvocation methodInvocation, Object result){
return startProcess.returnProcessInstanceId() && (result instanceof String ||
methodInvocation.getMethod().getReturnType().isAssignableFrom(String.class) );
}
@SuppressWarnings("unused")
boolean shouldReturnAsyncResultWithProcessInstanceId (StartProcess startProcess, MethodInvocation methodInvocation , Object result) {
return startProcess.returnProcessInstanceFuture() &&
(result instanceof AsyncResult|| methodInvocation.getMethod().getReturnType().isAssignableFrom(AsyncResult.class));
}
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
StartProcess startProcess = AnnotationUtils.getAnnotation ( method , StartProcess.class );
String processKey = startProcess.processKey();
Assert.hasText( processKey , "you must provide the name of process to start");
Object result ;
try {
result = invocation.proceed() ;
Map<String,Object> vars = this.processVariablesFromAnnotations( invocation );
System.out.println( vars.toString());
RuntimeService runtimeService = this.processEngine.getRuntimeService();
ProcessInstance pi = runtimeService.startProcessInstanceByKey( processKey , vars);
String pId = pi.getId() ;
if( invocation.getMethod().getReturnType().equals(void.class))
return null;
if(shouldReturnProcessInstance(startProcess, invocation , result))
return pi;
if(shouldReturnProcessInstanceId(startProcess, invocation , result))
return pId;
} catch (Throwable th){
throw new RuntimeException( th) ;
}
return result ;
}
/**
* if there any arguments with the {@link com.joshlong.activiti.coordinator.annotations.ProcessVariable} annotation,
* then we feed those parameters into the business process
* @param invocation the invocation of the method as passed to the {@link org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)} method
* @return returns the map of process variables extracted from the parameters
* @throws Throwable thrown anything goes wrong
*/
protected Map<String,Object> processVariablesFromAnnotations( MethodInvocation invocation ) throws Throwable {
Method method = invocation.getMethod() ;
Annotation [][] annotations = method.getParameterAnnotations();
Map<String,Object> vars = new HashMap<String,Object>() ;
int paramIndx = 0 ;
for(Annotation[] annPerParam : annotations ){
for(Annotation annotation : annPerParam){
if(annotation instanceof ProcessVariable){
ProcessVariable processVariable = (ProcessVariable) annotation ;
vars.put( processVariable.value(), invocation.getArguments()[paramIndx] );
}
}
paramIndx+=1 ;
}
return vars;
}
}