org.activiti.spring.components.aop.ProcessStartingMethodInterceptor.java Source code

Java tutorial

Introduction

Here is the source code for org.activiti.spring.components.aop.ProcessStartingMethodInterceptor.java

Source

/*
 * Copyright 2010 the original author or authors
 *
 *     Licensed under the Apache License, Version 2.0 (the "License");
 *     you may not use this file except in compliance with the License.
 *     You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *     Unless required by applicable law or agreed to in writing, software
 *     distributed under the License is distributed on an "AS IS" BASIS,
 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *     See the License for the specific language governing permissions and
 *     limitations under the License.
 */
package org.activiti.spring.components.aop;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.spring.annotations.BusinessKey;
import org.activiti.spring.annotations.ProcessVariable;
import org.activiti.spring.annotations.StartProcess;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Future;

/**
 * {@link org.aopalliance.intercept.MethodInterceptor} that starts a business process
 * as a result of a successful method invocation.
 *
 * @author Josh Long
 */
public class ProcessStartingMethodInterceptor implements MethodInterceptor {

    private Logger log = LoggerFactory.getLogger(getClass());

    /**
     * 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;
        Assert.notNull(this.processEngine, "the processEngine can't be null!");
    }

    protected boolean shouldReturnProcessInstance(StartProcess startProcess, MethodInvocation methodInvocation,
            Object result) {
        return (result instanceof ProcessInstance
                || methodInvocation.getMethod().getReturnType().isAssignableFrom(ProcessInstance.class));
    }

    protected boolean shouldReturnProcessInstanceId(StartProcess startProcess, MethodInvocation methodInvocation,
            Object result) {
        return startProcess.returnProcessInstanceId() && (result instanceof String
                || methodInvocation.getMethod().getReturnType().isAssignableFrom(String.class));
    }

    protected boolean shouldReturnAsyncResultWithProcessInstance(StartProcess startProcess,
            MethodInvocation methodInvocation, Object result) {
        return (result instanceof Future
                || methodInvocation.getMethod().getReturnType().isAssignableFrom(Future.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);

            String businessKey = this.processBusinessKey(invocation);

            log.info("variables for the started process: {}", vars.toString());

            RuntimeService runtimeService = this.processEngine.getRuntimeService();
            ProcessInstance pi;
            if (null != businessKey && StringUtils.hasText(businessKey)) {
                pi = runtimeService.startProcessInstanceByKey(processKey, businessKey, vars);
                log.info("the business key for the started process is '{}'", businessKey);
            } else {
                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;

            if (shouldReturnAsyncResultWithProcessInstance(startProcess, invocation, result)) {
                return new AsyncResult<ProcessInstance>(pi);
            }

        } catch (Throwable th) {
            throw new RuntimeException(th);
        }
        return result;
    }

    protected String processBusinessKey(MethodInvocation invocation) throws Throwable {
        Map<BusinessKey, String> businessKeyAnnotations = this.mapOfAnnotationValues(BusinessKey.class, invocation);
        if (businessKeyAnnotations.size() == 1) {
            BusinessKey processId = businessKeyAnnotations.keySet().iterator().next();
            return businessKeyAnnotations.get(processId);
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    private <K extends Annotation, V> Map<K, V> mapOfAnnotationValues(Class<K> annotationType,
            MethodInvocation invocation) {
        Method method = invocation.getMethod();
        Annotation[][] annotations = method.getParameterAnnotations();
        Map<K, V> vars = new HashMap<K, V>();
        int paramIndx = 0;
        for (Annotation[] annPerParam : annotations) {
            for (Annotation annotation : annPerParam) {
                if (!annotationType.isAssignableFrom(annotation.getClass())) {
                    continue;
                }
                K pv = (K) annotation;
                V v = (V) invocation.getArguments()[paramIndx];
                vars.put(pv, v);

            }
            paramIndx += 1;
        }
        return vars;
    }

    /**
     * if there any arguments with the {@link org.activiti.spring.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 {

        Map<ProcessVariable, Object> vars = this.mapOfAnnotationValues(ProcessVariable.class, invocation);

        Map<String, Object> varNameToValueMap = new HashMap<String, Object>();
        for (ProcessVariable processVariable : vars.keySet()) {
            varNameToValueMap.put(processVariable.value(), vars.get(processVariable));
        }
        return varNameToValueMap;

    }
}