/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.camel.bam;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.Processor;
import org.apache.camel.bam.model.ActivityDefinition;
import org.apache.camel.bam.model.ProcessDefinition;
import org.apache.camel.bam.model.ProcessInstance;
import org.apache.camel.bam.processor.ActivityMonitorEngine;
import org.apache.camel.bam.processor.JpaBamProcessor;
import org.apache.camel.bam.rules.ProcessRules;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.util.ObjectHelper;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import static org.apache.camel.util.ObjectHelper.notNull;
/**
* A builder of a process definition
*
* @version
*/
public abstract class ProcessBuilder extends RouteBuilder {
private static int processCounter;
private EntityManagerFactory entityManagerFactory;
private EntityManagerTemplate entityManagerTemplate;
private TransactionTemplate transactionTemplate;
private String processName;
private final List<ActivityBuilder> activityBuilders = new ArrayList<ActivityBuilder>();
private Class<ProcessInstance> entityType = ProcessInstance.class;
private final ProcessRules processRules = new ProcessRules();
private volatile ProcessDefinition processDefinition;
private ActivityMonitorEngine engine;
protected ProcessBuilder() {
}
protected ProcessBuilder(EntityManagerFactory entityManagerFactory, TransactionTemplate transactionTemplate) {
this(entityManagerFactory, transactionTemplate, createProcessName());
}
protected ProcessBuilder(EntityManagerFactory entityManagerFactory, TransactionTemplate transactionTemplate, String processName) {
setEntityManagerFactory(entityManagerFactory);
this.transactionTemplate = transactionTemplate;
this.processName = processName;
}
protected static synchronized String createProcessName() {
return "Process-" + (++processCounter);
}
public ActivityBuilder activity(String endpointUri) {
return activity(endpoint(endpointUri));
}
public ActivityBuilder activity(Endpoint endpoint) {
ActivityBuilder answer = new ActivityBuilder(this, endpoint);
activityBuilders.add(answer);
return answer;
}
/**
* Sets the process entity type used to perform state management
*/
public ProcessBuilder entityType(Class<ProcessInstance> entityType) {
this.entityType = entityType;
return this;
}
public Processor createActivityProcessor(ActivityBuilder activityBuilder) {
notNull(entityManagerFactory, "entityManagerFactory");
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
processRules.setProcessDefinition(getProcessDefinition());
}
});
return new JpaBamProcessor(transactionTemplate, entityManagerFactory, activityBuilder.getCorrelationExpression(), activityBuilder.getActivityRules(), getEntityType());
}
// Properties
// -----------------------------------------------------------------------
public List<ActivityBuilder> getActivityBuilders() {
return activityBuilders;
}
public Class<ProcessInstance> getEntityType() {
return entityType;
}
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
this.entityManagerTemplate = new EntityManagerTemplate(entityManagerFactory);
}
public TransactionTemplate getTransactionTemplate() {
return transactionTemplate;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public ProcessRules getProcessRules() {
return processRules;
}
public String getProcessName() {
if (processName == null) {
processName = createProcessName();
}
return processName;
}
public synchronized ProcessDefinition getProcessDefinition() {
if (processDefinition == null) {
processDefinition = findOrCreateProcessDefinition();
}
return processDefinition;
}
public void setProcessDefinition(ProcessDefinition processDefinition) {
this.processDefinition = processDefinition;
}
// Implementation methods
// -------------------------------------------------------------------------
protected void populateRoutes() throws Exception {
ObjectHelper.notNull(entityManagerFactory, "entityManagerFactory", this);
ObjectHelper.notNull(getTransactionTemplate(), "transactionTemplate", this);
// add the monitoring service - should there be an easier way??
if (engine == null) {
engine = new ActivityMonitorEngine(entityManagerFactory, getTransactionTemplate(), getProcessRules());
}
CamelContext camelContext = getContext();
if (camelContext instanceof DefaultCamelContext) {
DefaultCamelContext defaultCamelContext = (DefaultCamelContext) camelContext;
defaultCamelContext.addService(engine);
}
// create the routes for the activities
for (ActivityBuilder builder : activityBuilders) {
from(builder.getEndpoint()).process(builder.getProcessor());
}
super.populateRoutes();
}
// Implementation methods
// -------------------------------------------------------------------------
public ActivityDefinition findOrCreateActivityDefinition(String activityName) {
ProcessDefinition definition = getProcessDefinition();
Map<String, Object> params = new HashMap<String, Object>(2);
params.put("definition", definition);
params.put("name", activityName);
List<ActivityDefinition> list = entityManagerTemplate.find(ActivityDefinition.class, "select x from "
+ QueryUtils.getTypeName(ActivityDefinition.class) + " x where x.processDefinition = :definition and x.name = :name", params);
if (!list.isEmpty()) {
return list.get(0);
} else {
ActivityDefinition answer = new ActivityDefinition();
answer.setName(activityName);
answer.setProcessDefinition(ProcessDefinition.getRefreshedProcessDefinition(entityManagerTemplate, definition));
entityManagerTemplate.persist(answer);
return answer;
}
}
protected ProcessDefinition findOrCreateProcessDefinition() {
Map<String, Object> params = new HashMap<String, Object>(1);
params.put("name", processName);
List<ProcessDefinition> list = entityManagerTemplate.find(ProcessDefinition.class, "select x from "
+ QueryUtils.getTypeName(ProcessDefinition.class) + " x where x.name = :name", params);
if (!list.isEmpty()) {
return list.get(0);
} else {
ProcessDefinition answer = new ProcessDefinition();
answer.setName(processName);
entityManagerTemplate.persist(answer);
return answer;
}
}
}