package org.aperteworkflow.ext.activiti; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.delegate.Expression; import org.activiti.engine.delegate.JavaDelegate; import org.activiti.engine.runtime.Execution; import org.apache.commons.beanutils.BeanUtils; import pl.net.bluesoft.rnd.processtool.ProcessToolContext; import pl.net.bluesoft.rnd.processtool.dao.ProcessInstanceDAO; import pl.net.bluesoft.rnd.processtool.model.BpmStep; import pl.net.bluesoft.rnd.processtool.model.BpmVariable; import pl.net.bluesoft.rnd.processtool.model.ProcessInstance; import pl.net.bluesoft.rnd.processtool.model.ProcessInstanceAttribute; import pl.net.bluesoft.rnd.processtool.model.nonpersistent.MutableBpmStep; import pl.net.bluesoft.rnd.processtool.steps.ProcessToolProcessStep; import pl.net.bluesoft.rnd.processtool.ui.widgets.annotations.AutoWiredProperty; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import static pl.net.bluesoft.util.lang.FormatUtil.nvl; import static pl.net.bluesoft.util.lang.StringUtil.hasText; /** * @author tlipski@bluesoft.net.pl */ public class ActivitiStepAction implements JavaDelegate { private static final Logger logger = Logger.getLogger(ActivitiStepAction.class.getName()); public Expression stepName; public Expression params = null; @SuppressWarnings("unused") // it's called directly from BPM engine @Override public void execute(DelegateExecution execution) throws Exception { ProcessToolContext ptc = ProcessToolContext.Util.getThreadProcessToolContext(); ProcessInstanceDAO dao = ptc.getProcessInstanceDAO(); String processInstanceId = execution.getProcessInstanceId(); ProcessInstance pi = dao.getProcessInstanceByInternalId(processInstanceId); String res; String stepName = (String) this.stepName.getValue(execution); Map params = new HashMap(); if (this.params != null) { String xml = (String) this.params.getValue(execution); if (xml != null) { XStream xs = new XStream(); xs.alias("map", java.util.Map.class); xs.registerConverter(new Converter() { public boolean canConvert(Class clazz) { return AbstractMap.class.isAssignableFrom(clazz); } public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) { AbstractMap<String, String> map = (AbstractMap<String, String>) value; for (Map.Entry<String, String> entry : map.entrySet()) { writer.startNode(entry.getKey().toString()); writer.setValue(entry.getValue().toString()); writer.endNode(); } } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { Map<String, String> map = new HashMap<String, String>(); while (reader.hasMoreChildren()) { reader.moveDown(); map.put(reader.getNodeName(), reader.getValue()); reader.moveUp(); } return map; } }); params = (Map) xs.fromXML(xml); } } try { ProcessToolProcessStep stepInstance = ptc.getRegistry().getStep(stepName); if (stepInstance == null) { throw new IllegalArgumentException("No step defined by name: " + stepName); } processAutowiredProperties(stepInstance, params); res = stepInstance.invoke(prepareStep(pi, execution), params); } catch (Exception e) { throw new RuntimeException(e); } for (ProcessInstanceAttribute pia : pi.getProcessAttributes()) { if (pia instanceof BpmVariable) { BpmVariable bpmVar = (BpmVariable) pia; if (hasText(bpmVar.getBpmVariableName())) { execution.setVariable(bpmVar.getBpmVariableName(), bpmVar.getBpmVariableValue()); } } } execution.setVariable("RESULT", res); } private BpmStep prepareStep(ProcessInstance pi, DelegateExecution exec) { MutableBpmStep step = new MutableBpmStep(); step.setProcessInstance(pi); step.setExecutionId(exec.getId()); step.setStateName((String) this.stepName.getValue(exec)); // makes no sense in BPMN2.0, anyway step should not rely its logic on its placement on process map // List<String> transitionNames = new ArrayList<String>(); // for (Transition transition : exec.getActivity().getOutgoingTransitions()) { // transitionNames.add(transition.getDestination().getName()); // } // step.setOutgoingTransitions(transitionNames); return step; } private void processAutowiredProperties(Object object, Map<String, String> m) { Class cls = object.getClass(); for (Field f : cls.getDeclaredFields()) { String autoName = null; for (Annotation a : f.getAnnotations()) { if (a instanceof AutoWiredProperty) { AutoWiredProperty awp = (AutoWiredProperty) a; if (AutoWiredProperty.DEFAULT.equals(awp.name())) { autoName = f.getName(); } else { autoName = awp.name(); } } } String value = nvl( m.get(autoName), ProcessToolContext.Util.getThreadProcessToolContext().getSetting("autowire." + autoName) ); if (autoName != null && value != null) { try { logger.fine("Setting attribute " + autoName + " to " + value); BeanUtils.setProperty(object, autoName, value); } catch (Exception e) { logger.log(Level.SEVERE, "Error setting attribute " + autoName + ": " + e.getMessage(), e); } } } } }