/* 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.camunda.bpm.camel.component.producer;
import static org.camunda.bpm.camel.component.CamundaBpmConstants.ACTIVITY_ID_PARAMETER;
import static org.camunda.bpm.camel.component.CamundaBpmConstants.EXCHANGE_HEADER_BUSINESS_KEY;
import static org.camunda.bpm.camel.component.CamundaBpmConstants.EXCHANGE_HEADER_CORRELATION_KEY;
import static org.camunda.bpm.camel.component.CamundaBpmConstants.EXCHANGE_HEADER_CORRELATION_KEY_TYPE;
import static org.camunda.bpm.camel.component.CamundaBpmConstants.EXCHANGE_HEADER_PROCESS_INSTANCE_ID;
import static org.camunda.bpm.camel.component.CamundaBpmConstants.CORRELATION_KEY_NAME_PARAMETER;
import static org.camunda.bpm.camel.component.CamundaBpmConstants.MESSAGE_NAME_PARAMETER;
import static org.camunda.bpm.camel.component.CamundaBpmConstants.PROCESS_DEFINITION_KEY_PARAMETER;
import java.util.HashMap;
import java.util.Map;
import org.apache.camel.Exchange;
import org.camunda.bpm.camel.common.ExchangeUtils;
import org.camunda.bpm.camel.component.CamundaBpmEndpoint;
import org.camunda.bpm.engine.runtime.Execution;
import org.camunda.bpm.engine.runtime.ExecutionQuery;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.runtime.ProcessInstanceQuery;
/**
* Sends a message (or signals a ReceiveTask) to a waiting process instance or
* start a new process instance by message.
*
* Example: camunda-bpm://message?messageName=someMessage
*
* Example: camunda-bpm://message?activityId=receiveTask
*
* @author Rafael Cordones (@rafacm)
* @author Bernd Ruecker
*/
public class MessageProducer extends CamundaBpmProducer {
private final String messageName;
private final String activityId;
private final String processDefinitionKey;
private final String correlationKeyName;
public MessageProducer(CamundaBpmEndpoint endpoint, Map<String, Object> parameters) {
super(endpoint, parameters);
if (parameters.containsKey(MESSAGE_NAME_PARAMETER)) {
this.messageName = (String) parameters.get(MESSAGE_NAME_PARAMETER);
this.activityId = null;
} else if (parameters.containsKey(ACTIVITY_ID_PARAMETER)) {
this.messageName = null;
this.activityId = (String) parameters.get(ACTIVITY_ID_PARAMETER);
} else {
this.messageName = null;
this.activityId = null;
throw new IllegalArgumentException("You need to pass the '" + MESSAGE_NAME_PARAMETER
+ "' parameter! Parameters received: " + parameters);
}
if (parameters.containsKey(PROCESS_DEFINITION_KEY_PARAMETER)) {
this.processDefinitionKey = (String) parameters.get(PROCESS_DEFINITION_KEY_PARAMETER);
} else {
this.processDefinitionKey = null;
}
if (parameters.containsKey(CORRELATION_KEY_NAME_PARAMETER)) {
this.correlationKeyName = (String) parameters.get(CORRELATION_KEY_NAME_PARAMETER);
} else {
this.correlationKeyName = null;
}
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public void process(Exchange exchange) throws Exception {
String processInstanceId = exchange.getProperty(EXCHANGE_HEADER_PROCESS_INSTANCE_ID, String.class);
String businessKey = exchange.getProperty(EXCHANGE_HEADER_BUSINESS_KEY, String.class);
Map<String, Object> processVariables = ExchangeUtils.prepareVariables(exchange, parameters);
if (messageName != null) {
HashMap<String, Object> correlationKeys = new HashMap<String, Object>();
if (correlationKeyName != null) {
Class clazz = String.class;
String correlationKeyType = exchange.getProperty(EXCHANGE_HEADER_CORRELATION_KEY_TYPE, String.class);
if (correlationKeyType != null) {
clazz = Class.forName(correlationKeyType);
}
Object correlationKey = exchange.getProperty(EXCHANGE_HEADER_CORRELATION_KEY, clazz);
if (correlationKey == null) {
throw new RuntimeException("Missing value for correlation key for message '" + messageName + "'");
}
correlationKeys.put(correlationKeyName, correlationKey);
}
// if we have process instance we try to send the message to this
// one:
if (processInstanceId != null) {
ExecutionQuery query = runtimeService.createExecutionQuery() //
.processInstanceId(processInstanceId) //
.messageEventSubscriptionName(messageName);
if (processDefinitionKey != null) {
query.processDefinitionKey(processDefinitionKey);
}
Execution execution = query.singleResult();
if (execution == null) {
throw new RuntimeException("Couldn't find waiting process instance with id '" + processInstanceId
+ "' for message '" + messageName + "'");
}
runtimeService.messageEventReceived(messageName, execution.getId(), processVariables);
} else if (businessKey != null) {
// if we have businessKey, use it to correlate
runtimeService.correlateMessage(messageName, businessKey, correlationKeys, processVariables);
} else {
// otherwise we just send the message to the engine to let the
// engine
// decide what to do
// this can either correlate to a waiting instance or start a
// new
// process Instance
runtimeService.correlateMessage(messageName, correlationKeys, processVariables);
}
} else {
// signal a ReceiveTask needs a processInstance to be addressed
// (hint: this should be best done by a message in the ReceiveTask
// as this is possible from 7.1 on - this was introduced with 7.0
// where this was not yet possible)
if (processInstanceId == null && businessKey != null) {
ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(
businessKey);
if (processDefinitionKey != null) {
query.processDefinitionKey(processDefinitionKey);
}
ProcessInstance processInstance = query.singleResult();
if (processInstance != null) {
processInstanceId = processInstance.getId();
}
}
if (processInstanceId == null) {
throw new RuntimeException("Could not find the process instance via the provided properties ("
+ EXCHANGE_HEADER_PROCESS_INSTANCE_ID + "= '" + processInstanceId + "', " + EXCHANGE_HEADER_BUSINESS_KEY
+ "= '" + businessKey + "'");
}
ExecutionQuery query = runtimeService.createExecutionQuery().processInstanceId(
processInstanceId).activityId(activityId);
if (processDefinitionKey != null) {
query.processDefinitionKey(processDefinitionKey);
}
Execution execution = query.singleResult();
if (execution == null) {
throw new RuntimeException("Couldn't find process instance with id '" + processInstanceId
+ "' waiting in activity '" + activityId + "'");
}
runtimeService.signal(execution.getId(), processVariables);
}
}
}