package sushi.process;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityTransaction;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.Transient;
import sushi.bpmn.element.AbstractBPMNElement;
import sushi.bpmn.element.BPMNProcess;
import sushi.correlation.CorrelationRule;
import sushi.correlation.TimeCondition;
import sushi.event.SushiEventType;
import sushi.event.attribute.SushiAttribute;
import sushi.event.collection.SushiTree;
import sushi.persistence.Persistable;
import sushi.persistence.Persistor;
/**
* This class represents a business process with bounded {@link SushiEventType}s and eventually a associated {@link BPMNProcess}.
* The process knows the correlation rules under which events are assigned to concrete {@link SushiProcessInstance}s of this process.
* @author micha
*/
@Entity
@Table(name = "Process")
public class SushiProcess extends Persistable implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int ID;
@Column(name = "NAME")
private String name;
@ManyToMany(fetch=FetchType.EAGER, cascade = CascadeType.MERGE)
@JoinTable(name="ProcessEventTypes", joinColumns={@JoinColumn(name="Id")})
@JoinColumn(name="EventTypes")
private Set<SushiEventType> eventTypes = new HashSet<SushiEventType>();
@OneToMany(fetch=FetchType.EAGER)
private List<SushiProcessInstance> processInstances = new ArrayList<SushiProcessInstance>();
@OneToOne(cascade = CascadeType.MERGE)
private TimeCondition timeCondition;
@OneToOne(cascade = CascadeType.MERGE)
private BPMNProcess bpmnProcess;
@OneToMany(fetch=FetchType.EAGER)
private List<SushiAttribute> correlationAttributes = new ArrayList<SushiAttribute>();
@OneToMany(cascade = CascadeType.ALL, mappedBy = "process")
private Set<CorrelationRule> correlationRules = new HashSet<CorrelationRule>();
// @OneToOne(cascade = CascadeType.MERGE)
@Transient
private SushiTree<AbstractBPMNElement> processDecompositionTree = new SushiTree<AbstractBPMNElement>();
/**
* Default-Constructor for JPA.
*/
public SushiProcess(){
this.name = "";
}
public SushiProcess(String name){
this.name = name;
}
public SushiProcess(String name, List<SushiEventType> eventTypes){
this.name = name;
this.eventTypes.addAll(eventTypes);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
public ArrayList<SushiEventType> getEventTypes() {
return new ArrayList<SushiEventType> (eventTypes);
}
public List<SushiProcessInstance> getProcessInstances() {
return processInstances;
}
public void setProcessInstances(List<SushiProcessInstance> processInstances) {
this.processInstances = processInstances;
}
public List<SushiAttribute> getCorrelationAttributes() {
return correlationAttributes;
}
public void setCorrelationAttributes(List<SushiAttribute> correlationAttributes) {
this.correlationAttributes = correlationAttributes;
}
public boolean isCorrelationWithCorrelationRules() {
return !correlationRules.isEmpty();
}
public void addCorrelationAttribute(SushiAttribute correlationAttribute){
if(!correlationAttributes.contains(correlationAttribute)){
correlationAttributes.add(correlationAttribute);
}
}
public void addCorrelationAttributes(List<SushiAttribute> correlationAttributes){
for(SushiAttribute correlationAttribute : correlationAttributes){
addCorrelationAttribute(correlationAttribute);
}
}
public void removeCorrelationAttribute(SushiAttribute correlationAttribute){
correlationAttributes.remove(correlationAttribute);
}
public Set<CorrelationRule> getCorrelationRules() {
return correlationRules;
}
public void setCorrelationRules(Set<CorrelationRule> correlationRules) {
this.correlationRules = correlationRules;
}
public void addCorrelationRule(CorrelationRule correlationRule){
if(!correlationRules.contains(correlationRule)){
correlationRules.add(correlationRule);
correlationRule.setProcess(this);
}
}
public void addCorrelationRules(Set<CorrelationRule> correlationRules){
for(CorrelationRule rule : correlationRules){
addCorrelationRule(rule);
}
}
public void removeCorrelationRule(CorrelationRule correlationRule){
correlationRules.remove(correlationRule);
correlationRule.setProcess(null);
}
public boolean addProcessInstance(SushiProcessInstance processInstance) {
if(!processInstances.contains(processInstance)){
return processInstances.add(processInstance);
}
return false;
}
public boolean removeProcessInstance(SushiProcessInstance processInstance) {
return processInstances.remove(processInstance);
}
public void setEventTypes(Set<SushiEventType> eventTypes) {
this.eventTypes = eventTypes;
}
public boolean addEventType(SushiEventType eventType) {
if(!eventTypes.contains(eventType)){
eventType.save();
eventTypes.add(eventType);
return true;
}
return false;
}
public boolean removeEventType(SushiEventType eventType) {
if (!eventTypes.remove(eventType)){
// EventType als Notfallvariante per Typename und ID suchen und löschen,
// da durch JPA teilweise unterschiedliche ObjektIDs entstehen können
for(SushiEventType containedEventType : eventTypes){
if(containedEventType.getID() == eventType.getID() && containedEventType.getTypeName().equals(eventType.getTypeName())){
return eventTypes.remove(containedEventType);
}
}
}
return false;
}
@Override
public String toString() {
String processText = this.name + "(" + this.ID + ")";
return processText;
}
/**
* Returns all {@link SushiProcess}es from the database.
* @return
*/
@SuppressWarnings("unchecked")
public static List<SushiProcess> findAll() {
Query q = Persistor.getEntityManager().createQuery("SELECT t FROM SushiProcess t");
return q.getResultList();
}
/**
* Returns all {@link SushiProcess}es from the database, which have the given {@link SushiEventType}.
* @return
*/
@SuppressWarnings("unchecked")
public static List<SushiProcess> findByEventType(SushiEventType eventType){
Query query = Persistor.getEntityManager().createNativeQuery("" +
"Select * " +
"FROM Process " +
"WHERE ID IN (" +
"Select Id " +
"FROM ProcessEventTypes " +
"WHERE eventTypes_ID = '" + eventType.getID()+ "')", SushiProcess.class);
return query.getResultList();
}
/**
* Returns all {@link SushiProcess}es from the database, which have the given attribute and associated value.
* @return
*/
@SuppressWarnings("unchecked")
public static List<SushiProcess> findByAttribute(String columnName, String value){
Query query = Persistor.getEntityManager().createNativeQuery("SELECT * FROM Process WHERE " + columnName + " = '" + value + "'", SushiProcess.class);
return query.getResultList();
}
/**
* Returns all {@link SushiProcess}es from the database, which have the given ID.
* @return
*/
public static SushiProcess findByID(int ID){
List<SushiProcess> processes = findByAttribute("ID", Integer.toString(ID));
if(!processes.isEmpty()){
return processes.get(0);
}else{
return null;
}
}
/**
* Returns all {@link SushiProcess}es from the database, which have an ID greater than the given.
* @return
*/
public static List<SushiProcess> findByIDGreaterThan(int ID){
return findByAttributeGreaterThan("ID", Integer.toString(ID));
}
/**
* Returns all {@link SushiProcess}es from the database, which have an ID less than the given.
* @return
*/
public static List<SushiProcess> findByIDLessThan(int ID){
return findByAttributeLessThan("ID", Integer.toString(ID));
}
@SuppressWarnings("unchecked")
private static List<SushiProcess> findByAttributeGreaterThan(String columnName, String value) {
Query query = Persistor.getEntityManager().createNativeQuery("" +
"SELECT * FROM Process " +
"WHERE " + columnName + " > '" + value + "'", SushiProcess.class);
return query.getResultList();
}
@SuppressWarnings("unchecked")
private static List<SushiProcess> findByAttributeLessThan(String columnName, String value) {
Query query = Persistor.getEntityManager().createNativeQuery("" +
"SELECT * FROM Process " +
"WHERE " + columnName + " < '" + value + "'", SushiProcess.class);
return query.getResultList();
}
public static List<SushiProcess> findByName(String name){
return findByAttribute("NAME", name);
}
/**
* Returns all {@link SushiProcess}es from the database, which have the given {@link SushiProcessInstance}.
* @return
*/
@SuppressWarnings("unchecked")
public static List<SushiProcess> findByProcessInstance (SushiProcessInstance processInstance){
Query query = Persistor.getEntityManager().createNativeQuery("" +
"Select * " +
"FROM Process " +
"WHERE ID IN (" +
"Select SushiProcess_ID " +
"FROM Process_ProcessInstance " +
"WHERE processInstances_ID = '" + processInstance.getID()+ "')", SushiProcess.class);
return query.getResultList();
}
/**
* Returns all {@link SushiProcess}es from the database, which have a {@link SushiProcessInstance} with the given ID.
* @return
*/
@SuppressWarnings("unchecked")
public static List<SushiProcess> findByProcessInstanceID (int ID){
Query query = Persistor.getEntityManager().createNativeQuery("" +
"Select * " +
"FROM Process " +
"WHERE ID IN (" +
"Select SushiProcess_ID " +
"FROM Process_ProcessInstance " +
"WHERE processInstances_ID = '" + ID + "')", SushiProcess.class);
return query.getResultList();
}
@SuppressWarnings("unchecked")
public static List<SushiProcess> findByTimeCondition(TimeCondition timeCondition) {
Query query = Persistor.getEntityManager().createNativeQuery("" +
"Select * " +
"FROM Process " +
"WHERE TIMECONDITION_ID = '" + timeCondition.getID()+ "'", SushiProcess.class);
return query.getResultList();
}
@SuppressWarnings("unchecked")
public static SushiProcess findByBPMNProcess(BPMNProcess bpmnProcess) {
Query query = Persistor.getEntityManager().createNativeQuery("" +
"Select * " +
"FROM Process " +
"WHERE BPMNPROCESS_ID = '" + bpmnProcess.getID()+ "'", SushiProcess.class);
List<SushiProcess> processes = query.getResultList();
if(!processes.isEmpty()){
return processes.get(0);
} else {
return null;
}
}
@SuppressWarnings("unchecked")
public static List<SushiProcess> findProcessesByBPMNProcess(BPMNProcess bpmnProcess) {
Query query = Persistor.getEntityManager().createNativeQuery("" +
"Select * " +
"FROM Process " +
"WHERE BPMNPROCESS_ID = '" + bpmnProcess.getID()+ "'", SushiProcess.class);
return query.getResultList();
}
/**
* Saves this process to the database.
* @return
*/
@Override
public SushiProcess save() {
return (SushiProcess) super.save();
}
/**
* Merges this process to the database.
* @return
*/
@Override
public SushiProcess merge() {
return (SushiProcess) super.merge();
}
public static boolean save(ArrayList<SushiProcess> processes) {
try {
Persistor.getEntityManager().getTransaction().begin();
for (SushiProcess process : processes) {
Persistor.getEntityManager().persist(process);
}
Persistor.getEntityManager().getTransaction().commit();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Deletes this process from the database.
* @return
*/
@Override
public SushiProcess remove() {
SushiProcessInstance.remove(processInstances);
return (SushiProcess) super.remove();
}
/**
* Deletes the specified processes from the database.
* @return
*/
public static boolean remove(ArrayList<SushiProcess> processes) {
boolean removed = true;
for(SushiProcess process : processes){
removed = (process.remove()!=null);
}
return removed;
}
/**
* Deletes all processes from the database.
*/
public static void removeAll() {
try {
EntityTransaction entr = Persistor.getEntityManager().getTransaction();
entr.begin();
Query query = Persistor.getEntityManager().createQuery("DELETE FROM SushiProcess");
int deleteRecords = query.executeUpdate();
entr.commit();
System.out.println(deleteRecords + " records are deleted.");
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
public TimeCondition getTimeCondition() {
return timeCondition;
}
public void setTimeCondition(TimeCondition timeCondition) {
this.timeCondition = timeCondition;
if(timeCondition != null){
this.timeCondition.setProcess(this);
}
}
public BPMNProcess getBpmnProcess() {
return bpmnProcess;
}
public void setBpmnProcess(BPMNProcess bpmnProcess) {
this.bpmnProcess = bpmnProcess;
}
/**
* Searches for the specified process and returns true if it exists.
* @param name
* @return
*/
public static boolean exists(String name) {
return !SushiProcess.findByName(name).isEmpty();
}
/**
* Returns true, if the process has a correlation rule.
* @return
*/
public boolean hasCorrelation(){
return !correlationAttributes.isEmpty() || !correlationRules.isEmpty();
}
/**
* Returns a decompositional tree of the contained BPMN process, if any.
* @return
*/
public SushiTree<AbstractBPMNElement> getProcessDecompositionTree() {
return processDecompositionTree;
}
public void setProcessDecompositionTree(SushiTree<AbstractBPMNElement> processDecompositionTree) {
this.processDecompositionTree = processDecompositionTree;
}
}