Java tutorial
/** * This file is part of SIMPL4(http://simpl4.org). * * Copyright [2014] [Manfred Sattler] <manfred@ms123.org> * * SIMPL4 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * SIMPL4 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with SIMPL4. If not, see <http://www.gnu.org/licenses/>. */ package org.ms123.common.camel.components; import java.util.HashMap; import java.util.Map; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import java.lang.reflect.Field; import org.activiti.engine.ActivitiException; import org.activiti.engine.RuntimeService; import org.activiti.engine.ProcessEngineConfiguration; import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.delegate.Expression; import org.activiti.engine.impl.bpmn.behavior.BpmnActivityBehavior; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.pvm.PvmProcessDefinition; import org.activiti.engine.impl.pvm.delegate.ActivityBehavior; import org.activiti.engine.impl.pvm.delegate.ActivityExecution; import org.activiti.engine.ProcessEngine; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.RepositoryService; import org.activiti.engine.impl.persistence.entity.ExecutionEntity; import org.activiti.camel.ExchangeUtils; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.MessageHistory; import org.apache.camel.Message; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultExchange; import org.apache.camel.spi.Registry; import org.apache.camel.core.osgi.OsgiDefaultCamelContext; import org.apache.camel.core.osgi.OsgiServiceRegistry; import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.impl.SimpleRegistry; import org.apache.camel.impl.CompositeRegistry; import org.apache.camel.processor.interceptor.Tracer; import org.apache.camel.processor.interceptor.Tracer; import org.ms123.common.permission.api.PermissionService; import org.ms123.common.datamapper.DatamapperService; import org.ms123.common.data.api.DataLayer; import org.ms123.common.camel.api.CamelService; import org.ms123.common.camel.CamelContextBuilder; import org.ms123.common.camel.trace.*; import org.ms123.common.camel.components.activiti.ActivitiEndpoint; import org.ms123.common.camel.components.activiti.ActivitiProducer; import org.ms123.common.camel.GroovyRegistry; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import groovy.lang.GroovyShell; import flexjson.*; import static org.apache.commons.lang3.StringEscapeUtils.unescapeJava; import org.apache.commons.beanutils.*; /** */ @SuppressWarnings("unchecked") public abstract class BaseCamelBehavior extends BpmnActivityBehavior implements ActivityBehavior { private Expression variablesmapping; private Expression resultvar; public static String PROCESSVAR = "processvar"; public static String CAMELVAR = "camelvar"; public static String DESTINATION = "destination"; public static String DESTINATION_BODY = "body"; public static String DESTINATION_PROP = "property"; public static String DESTINATION_HEADER = "header"; public static String DESTINATION_ROUTING = "routing"; public static String ITEMS = "items"; public static String DOT = "\\."; String m_tenant, m_processDefinitionKey; public Class m_routeBuilderClass = null; private static final long serialVersionUID = 1L; protected JSONDeserializer m_ds = new JSONDeserializer(); protected JSONSerializer m_js = new JSONSerializer(); protected String m_camelActivitiKey; protected CamelContext m_camelContext; protected ActivityExecution m_execution; protected Map m_mapRouting; public void execute(ActivityExecution execution) throws Exception { m_js.prettyPrint(true); m_execution = execution; debug("BaseCamelBehavior.execution:" + isASync(execution)); Map mapBody = getVarMapping(execution, variablesmapping, DESTINATION_BODY); debug("MappingBody:" + m_js.deepSerialize(mapBody)); Map mapProp = getVarMapping(execution, variablesmapping, DESTINATION_PROP); debug("MappingProp:" + m_js.deepSerialize(mapProp)); Map mapHeader = getVarMapping(execution, variablesmapping, DESTINATION_HEADER); debug("MappingHeader:" + m_js.deepSerialize(mapHeader)); m_mapRouting = getVarMapping(execution, variablesmapping, DESTINATION_ROUTING); debug("MappingRouting:" + m_js.deepSerialize(m_mapRouting)); setTenantAndName(execution); m_camelContext = createCamelContext(m_tenant); createRouteBuilderClazz(); addRoute(m_camelContext, execution); m_camelContext.start(); final ActivitiEndpoint endpoint = createEndpoint(execution); final Exchange exchange = createExchange(execution, endpoint); exchange.setProperty("activitikey", m_camelActivitiKey); copyVariablesToProperties(mapProp, exchange); copyVariablesToHeader(mapHeader, exchange); copyVariablesToBodyAsMap(mapBody, exchange); final CamelService camelService = (CamelService) m_camelContext.getRegistry() .lookupByName(CamelService.class.getName()); if (isASync(execution)) { FutureTask<Void> future = new FutureTask<Void>(new Callable<Void>() { public Void call() { try { endpoint.process(exchange); } catch (Exception e) { throw new RuntimeException("Unable to process camel endpoint asynchronously."); } finally { Exception camelException = exchange.getException(); info("camelException:" + camelException); printHistory(exchange); camelService.saveHistory(exchange); try { info("Context stop"); m_camelContext.stop(); } catch (Exception e) { e.printStackTrace(); } } return null; } }); ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(future); handleCamelException(exchange); } else { try { endpoint.process(exchange); handleCamelException(exchange); debug(ExchangeUtils.prepareVariables(exchange, endpoint) + ""); String rs = null; if (resultvar != null) { rs = resultvar.getValue(execution).toString(); } if (isEmpty(rs)) { execution.setVariables(ExchangeUtils.prepareVariables(exchange, endpoint)); } else { execution.setVariable(rs, ExchangeUtils.prepareVariables(exchange, endpoint)); } } finally { printHistory(exchange); camelService.saveHistory(exchange); m_camelContext.stop(); } } performDefaultOutgoingBehavior(execution); } public static void printHistory(Exchange exchange) { info("printHistoryX"); List<MessageHistory> list = exchange.getProperty(Exchange.MESSAGE_HISTORY, List.class); ExchangeFormatter formatter = new ExchangeFormatter(); formatter.setShowExchangeId(true); formatter.setMultiline(true); formatter.setShowHeaders(true); formatter.setStyle(ExchangeFormatter.OutputStyle.Fixed); String routeStackTrace = MessageHelper.dumpMessageHistoryStacktrace(exchange, formatter, true); info(routeStackTrace); } private Map<String, Object> getVarMapping(DelegateExecution execution, Expression variablesmapping, String destination) throws Exception { if (variablesmapping == null) { return new HashMap(); } String vm = variablesmapping.getValue(execution).toString(); debug("getVarMapping:" + vm); if (vm.trim().length() == 0) { return new HashMap(); } Map map = (Map) m_ds.deserialize(vm); debug("getVarMapping.Map:" + map); List<Map> varmap = (List<Map>) map.get(ITEMS); Map<String, Object> values = new HashMap(); for (Map<String, String> m : varmap) { String processVar = m.get(PROCESSVAR); if (isEmpty(processVar)) { continue; } String dest = m.get(DESTINATION); if (!destination.equals(dest)) { continue; } Object o = null; if (processVar.startsWith("#")) { o = processVar.substring(1); } else { o = getValue(execution, processVar); } String camelVar = m.get(CAMELVAR); if (isEmpty(camelVar)) { camelVar = processVar; } values.put(camelVar, o); } return values; } private boolean isEmpty(String s) { return (s == null || "".equals(s.trim())); } private Object getValue(DelegateExecution execution, String processVar) throws Exception { if (processVar.indexOf(".") == -1) { return execution.getVariable(processVar); } String[] parts = processVar.split(DOT); Object o = execution.getVariable(parts[0]); for (int i = 1; i < parts.length; i++) { String part = parts[i]; o = PropertyUtils.getProperty(o, part); } return o; } protected Map getRoutingVariables() { info("getRoutingVariables:" + m_mapRouting); return m_mapRouting; } protected ActivitiEndpoint createEndpoint(ActivityExecution execution) { String uri = "activiti://" + getProcessDefinitionKey(execution) + ":" + execution.getActivity().getId(); info("createEndpoint:" + uri); return getEndpoint(uri); } protected ActivitiEndpoint getEndpoint(String key) { for (Endpoint e : m_camelContext.getEndpoints()) { info("Endpoint:" + e + "|" + e.getEndpointKey()); //if (e.getEndpointKey().equals(key) && (e instanceof ActivitiEndpoint)) { if (e instanceof ActivitiEndpoint) { return (ActivitiEndpoint) e; } } throw new RuntimeException("Activiti endpoint not defined for " + key); } protected Exchange createExchange(ActivityExecution activityExecution, ActivitiEndpoint endpoint) { Exchange ex = new DefaultExchange(m_camelContext); ex.setProperty(ActivitiProducer.PROCESS_ID_PROPERTY, activityExecution.getProcessInstanceId()); return ex; } protected void handleCamelException(Exchange exchange) { Exception camelException = exchange.getException(); boolean notHandledByCamel = exchange.isFailed() && camelException != null; if (notHandledByCamel) { //throw new ActivitiException("Unhandled exception on camel route", camelException); info("Unhandled exception on camel route:" + camelException); } } protected String getProcessDefinitionKey(ActivityExecution execution) { PvmProcessDefinition processDefinition = execution.getActivity().getProcessDefinition(); return processDefinition.getKey(); } protected boolean isASync(ActivityExecution execution) { return execution.getActivity().isAsync(); } protected String getStringFromField(Expression expression, DelegateExecution execution) { if (expression != null) { Object value = expression.getValue(execution); if (value != null) { return value.toString(); } } return null; } public boolean isCopyCamelBodyToBodyAsString() { return true; } public boolean isCopyVariablesFromHeader() { return true; } protected void copyVariablesToProperties(Map<String, Object> variables, Exchange exchange) { if (variables.entrySet().size() == 0) return; for (Map.Entry<String, Object> var : variables.entrySet()) { exchange.setProperty(var.getKey(), var.getValue()); } } protected void copyVariablesToHeader(Map<String, Object> variables, Exchange exchange) { if (variables.entrySet().size() == 0) return; for (Map.Entry<String, Object> var : variables.entrySet()) { exchange.getIn().setHeader(var.getKey(), var.getValue()); } } protected void copyVariablesToBodyAsMap(Map<String, Object> variables, Exchange exchange) { if (variables.entrySet().size() == 0) return; exchange.getIn().setBody(new HashMap<String, Object>(variables)); } protected void copyVariablesToBody(Map<String, Object> variables, Exchange exchange) { if (variables.entrySet().size() == 0) return; Object camelBody = variables.get(ExchangeUtils.CAMELBODY); if (camelBody != null) { exchange.getIn().setBody(camelBody); } } protected synchronized void createRouteBuilderClazz() { if (m_routeBuilderClass != null) return; String routing = unescapeJava(getRoutingDSL()); List<String> paramNames = getParameterNames(); paramNames.addAll(getRoutingVariables().keySet()); String script = buildScript(routing, paramNames); System.out.println("m_routeBuilderScript:" + script); GroovyShell gs = new GroovyShell(); m_routeBuilderClass = (Class) gs.evaluate(script); System.out.println("m_routeBuilderClass:" + m_routeBuilderClass); } private String buildScript(String camelDSL, List<String> paramNames) { String script = "import org.apache.camel.*\n"; script += "import org.apache.camel.impl.*\n"; script += "import org.apache.camel.builder.*\n"; script += "import org.apache.camel.model.dataformat.*\n"; script += "import java.util.*\n"; script += "class DynRouteBuilder extends org.apache.camel.builder.RouteBuilder implements org.ms123.common.workflow.stencil.StencilRouteBuilder{\n"; for (String fName : paramNames) { script += "String " + fName + ";"; } script += "def void init(Map params) {\n"; for (String fName : paramNames) { script += fName + "=params." + fName + ";\n"; } script += "}\n"; script += "def void configure() {\n"; script += camelDSL; script += "}}\n"; script += "return DynRouteBuilder.class\n"; return script; } protected RouteBuilder newRouteBuilder() { try { RouteBuilder rb = (RouteBuilder) m_routeBuilderClass.newInstance(); System.out.println("RouteBuilder:" + rb); return rb; } catch (Exception e) { throw new RuntimeException("BaseCamelBehavior.newRouteBuilder", e); } } public abstract void addRoute(CamelContext cc, ActivityExecution execution) throws Exception; public abstract String getRoutingDSL(); public abstract List<String> getParameterNames(); protected synchronized CamelContext createCamelContext(String namespace) throws Exception { Map beans = Context.getProcessEngineConfiguration().getBeans(); BundleContext bc = (BundleContext) beans.get("bundleContext"); Registry gr = new GroovyRegistry(BaseCamelBehavior.class.getClassLoader(), bc, namespace); CamelContext camelContext = CamelContextBuilder.createCamelContext(namespace, gr, bc, false); return camelContext; } protected void setTenantAndName(ActivityExecution execution) { Map beans = Context.getProcessEngineConfiguration().getBeans(); ProcessEngine pe = (ProcessEngine) beans.get("processEngine"); String processDefinitionId = ((ExecutionEntity) execution).getProcessDefinitionId(); RepositoryService repositoryService = pe.getRepositoryService(); ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionId(processDefinitionId).singleResult(); m_tenant = processDefinition.getTenantId(); m_processDefinitionKey = processDefinition.getKey(); info("TENANT:" + m_tenant); info("EID:" + execution.getId()); info("PID:" + execution.getProcessInstanceId()); info("AID:" + execution.getCurrentActivityId()); info("ANAME:" + execution.getCurrentActivityName()); m_camelActivitiKey = m_tenant + "/" + processDefinition.getName() + "/" + execution.getId() + "/" + execution.getCurrentActivityId(); info("m_camelActivitiKey:" + m_camelActivitiKey); } protected void debug(String msg) { System.out.println(msg); m_logger.debug(msg); } protected static void info(String msg) { System.err.println(msg); m_logger.info(msg); } private static final org.slf4j.Logger m_logger = org.slf4j.LoggerFactory.getLogger(BaseCamelBehavior.class); }