/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * 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.jbpm.process.workitem.jms; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.ServiceLoader; import javax.jms.BytesMessage; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import org.apache.commons.io.input.ClassLoaderObjectInputStream; import org.kie.api.runtime.manager.RuntimeEngine; import org.kie.api.runtime.manager.RuntimeManager; import org.kie.internal.runtime.manager.InternalRuntimeManager; import org.kie.internal.runtime.manager.RuntimeManagerIdFilter; import org.kie.internal.runtime.manager.RuntimeManagerRegistry; import org.kie.internal.runtime.manager.context.ProcessInstanceIdContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JMSSignalReceiver implements MessageListener { private static final Logger logger = LoggerFactory.getLogger(JMSSignalReceiver.class); private static final ServiceLoader<RuntimeManagerIdFilter> runtimeManagerIdFilters = ServiceLoader.load(RuntimeManagerIdFilter.class); @SuppressWarnings({"unchecked", "rawtypes"}) @Override public void onMessage(Message message) { if (message instanceof BytesMessage) { String deploymentId; Long processInstanceId; String signal; Long workItemId; Object data; BytesMessage bytesMessage = (BytesMessage) message; RuntimeManager runtimeManager = null; RuntimeEngine engine = null; try { deploymentId = (String) bytesMessage.getObjectProperty("KIE_SignalDeploymentId"); if (deploymentId == null) { deploymentId = (String) bytesMessage.getObjectProperty("KIE_DeploymentId"); } signal = (String) bytesMessage.getObjectProperty("KIE_Signal"); processInstanceId = (Long) bytesMessage.getObjectProperty("KIE_SignalProcessInstanceId"); workItemId = (Long) bytesMessage.getObjectProperty("KIE_SignalWorkItemId"); logger.debug("Deployment id '{}', signal '{}', processInstanceId '{}', workItemId '{}'", deploymentId, signal, processInstanceId, workItemId); Collection<String> availableRuntimeManagers = matchDeployments(deploymentId, RuntimeManagerRegistry.get().getRegisteredIdentifiers()); for (String matchedDeploymentId : availableRuntimeManagers) { try { runtimeManager = RuntimeManagerRegistry.get().getManager(matchedDeploymentId); if (runtimeManager == null) { throw new IllegalStateException("There is no runtime manager for deployment " + matchedDeploymentId); } logger.debug("RuntimeManager found for deployment id {}, reading message content with custom class loader of the deployment", matchedDeploymentId); data = readData(bytesMessage, ((InternalRuntimeManager)runtimeManager).getEnvironment().getClassLoader()); logger.debug("Data read successfully with output {}", data); engine = runtimeManager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); // perform operation either signal or complete work item if (workItemId != null) { Map<String, Object> results = new HashMap<String, Object>(); if (data != null) { if (data instanceof Map) { results.putAll((Map) data); } else { results.put("Data", data); } } logger.debug("About to complete work item with id {} and data {}", workItemId, results); engine.getKieSession().getWorkItemManager().completeWorkItem(workItemId, results); logger.debug("Successfully completed work item with id {}", workItemId); } else if (signal != null) { if (processInstanceId != null) { logger.debug("About to signal process instance with id {} and event data {} with signal {}", processInstanceId, data, signal); engine.getKieSession().signalEvent(signal, data, processInstanceId); } else { logger.debug("About to broadcast signal {} and event data {}", signal, data); runtimeManager.signalEvent(signal, data); } logger.debug("Signal completed successfully for signal {} with data {}", signal, data); } else { logger.warn("No signal or workitem id is given, skipping this message"); } } catch (Exception e) { logger.error("Unexpected exception while signaling: {}", e.getMessage(), e); } finally { if (runtimeManager != null && engine != null) { runtimeManager.disposeRuntimeEngine(engine); } } } } catch (Exception e) { logger.error("Unexpected exception while processing signal JMS message: {}", e.getMessage(), e); } } } protected Object readData(BytesMessage message, ClassLoader cl) throws JMSException, Exception { Object data = null; if (message.getBodyLength() > 0) { byte[] reqData = new byte[(int) message.getBodyLength()]; message.readBytes(reqData); if (reqData != null) { ObjectInputStream in = null; try { in = new ClassLoaderObjectInputStream(cl, new ByteArrayInputStream(reqData)); data = in.readObject(); } catch (IOException e) { logger.warn("Exception while serializing context data", e); } finally { if (in != null) { in.close(); } } } } return data; } protected Collection<String> matchDeployments(String deploymentId, Collection<String> availableDeployments) { if (availableDeployments == null || availableDeployments.isEmpty()) { return Collections.emptyList(); } Collection<String> matched = new ArrayList<String>(); for (RuntimeManagerIdFilter filter : runtimeManagerIdFilters) { matched = filter.filter(deploymentId, availableDeployments); if (matched != null && !matched.isEmpty()) { return matched; } } // nothing matched return given deployment id return Collections.singletonList(deploymentId); } }