/* 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.camel; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; import org.activiti.engine.ActivitiException; import org.apache.camel.Exchange; import org.apache.camel.TypeConversionException; import org.apache.commons.lang3.StringUtils; /** * This class contains one method - prepareVariables - that is used to copy variables from Camel into Activiti. * * @author Ryan Johnston (@rjfsu), Tijs Rademakers, Arnold Schrijver * @author Saeid Mirzaei */ public class ExchangeUtils { public static final String CAMELBODY = "camelBody"; protected static final String IGNORE_MESSAGE_PROPERTY = "CamelMessageHistory"; static Map<String, Pattern> patternsCache = new HashMap<String, Pattern >(); /** * Copies variables from Camel into Activiti. * * This method will copy the Camel body to the "camelBody" variable. It will copy the Camel body to individual variables within Activiti if it is of type * Map<String, Object> or it will copy the Object as it comes. * <ul> * <li>If the copyVariablesFromProperties parameter is set on the endpoint, the properties are copied instead</li> * <li>If the copyCamelBodyToBodyAsString parameter is set on the endpoint, the camelBody is converted to java.lang.String and added as a camelBody variable, * unless it is a Map<String, Object></li> * <li>If the copyVariablesFromHeader parameter is set on the endpoint, each Camel Header will be copied to an individual variable within Activiti.</li> * </ul> * * @param exchange The Camel Exchange object * @param activitiEndpoint The ActivitiEndpoint implementation * @return A Map<String, Object> containing all of the variables to be used in Activiti */ private static Pattern createPattern(String propertyString, boolean asBoolean) { Pattern pattern = null; if (!asBoolean) { String copyVariablesFromProperties = propertyString; pattern = patternsCache.get(copyVariablesFromProperties); if (pattern == null) { pattern = Pattern.compile(copyVariablesFromProperties); patternsCache.put(copyVariablesFromProperties, pattern); } } return pattern; } private static boolean isBoolean(String booleanString) { if (StringUtils.isEmpty(booleanString)) { return false; } String lower = booleanString.toLowerCase(); return lower.equals("true") || lower.equals("false"); } public static Map<String, Object> prepareVariables(Exchange exchange, ActivitiEndpoint activitiEndpoint) { Map<String, Object> camelVarMap = new HashMap<String, Object>(); String copyProperties = activitiEndpoint.getCopyVariablesFromProperties(); // don't other if the property is null, or is a false if (StringUtils.isNotEmpty(copyProperties) && (!isBoolean(copyProperties) || Boolean.parseBoolean(copyProperties))) { Pattern pattern = createPattern(copyProperties, Boolean.parseBoolean(copyProperties)); Map<String, Object> exchangeVarMap = exchange.getProperties(); // filter camel property that can't be serializable for camel version after 2.12.x+ for (String s : exchangeVarMap.keySet()) { if (IGNORE_MESSAGE_PROPERTY.equalsIgnoreCase(s) == false) { if (pattern == null || pattern.matcher(s).matches()) { camelVarMap.put(s, exchangeVarMap.get(s)); } } } } String copyHeader = activitiEndpoint.getCopyVariablesFromHeader(); if (!StringUtils.isEmpty(copyHeader) && (!isBoolean(copyHeader) || Boolean.parseBoolean(copyHeader))) { Pattern pattern = createPattern(copyHeader, Boolean.parseBoolean(copyHeader)); boolean isSetProcessInitiator = activitiEndpoint.isSetProcessInitiator(); for (Map.Entry<String, Object> header : exchange.getIn().getHeaders().entrySet()) { // Don't pass the process initiator header as a variable. if ((!isSetProcessInitiator || activitiEndpoint.getProcessInitiatorHeaderName().equals(header.getKey())) && (pattern == null || pattern.matcher(header.getKey()).matches())) { camelVarMap.put(header.getKey(), header.getValue()); } } } Object camelBody = null; if (exchange.hasOut()) { camelBody = exchange.getOut().getBody(); } else { camelBody = exchange.getIn().getBody(); } if (camelBody instanceof Map<?,?>) { Map<?,?> camelBodyMap = (Map<?,?>)camelBody; for (@SuppressWarnings("rawtypes") Map.Entry e : camelBodyMap.entrySet()) { if (e.getKey() instanceof String && IGNORE_MESSAGE_PROPERTY.equalsIgnoreCase((String) e.getKey()) == false) { camelVarMap.put((String) e.getKey(), e.getValue()); } } } else { if (activitiEndpoint.isCopyCamelBodyToBodyAsString() && !(camelBody instanceof String)) { camelBody = exchange.getContext().getTypeConverter().convertTo(String.class, exchange, camelBody); } if (camelBody != null) { camelVarMap.put(CAMELBODY, camelBody); } } return camelVarMap; } /** * Gets the value of the Camel header that contains the userId to be set as the process initiator. * Returns null if no header name was specified on the Camel route. * * @param exchange The Camel Exchange object * @param activitiEndpoint The ActivitiEndpoint implementation * @return The userId of the user to be set as the process initiator */ public static String prepareInitiator(Exchange exchange, ActivitiEndpoint activitiEndpoint) { String initiator = null; if (activitiEndpoint.isSetProcessInitiator()) { try { initiator = exchange.getIn().getHeader(activitiEndpoint.getProcessInitiatorHeaderName(), String.class); } catch (TypeConversionException e) { throw new ActivitiException("Initiator header '" + activitiEndpoint.getProcessInitiatorHeaderName() + "': Value must be of type String.", e); } if (StringUtils.isEmpty(initiator)) { throw new ActivitiException("Initiator header '" + activitiEndpoint.getProcessInitiatorHeaderName() + "': Value must be provided"); } } return initiator; } }