package org.orienteer.bpm.camunda.handler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
import org.camunda.bpm.engine.ProcessEngineException;
import org.camunda.bpm.engine.impl.EventSubscriptionQueryValue;
import org.camunda.bpm.engine.impl.ExecutionQueryImpl;
import org.camunda.bpm.engine.impl.ProcessInstanceQueryImpl;
import org.camunda.bpm.engine.impl.QueryOperator;
import org.camunda.bpm.engine.impl.QueryVariableValue;
import org.camunda.bpm.engine.impl.db.ListQueryParameterObject;
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.camunda.bpm.engine.impl.persistence.entity.EventSubscriptionEntity;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;
import org.camunda.bpm.engine.impl.persistence.entity.SuspensionState;
import org.camunda.bpm.engine.runtime.ProcessInstanceQuery;
import org.orienteer.bpm.camunda.OPersistenceSession;
import org.orienteer.bpm.camunda.handler.history.HistoricVariableInstanceEntityHandler;
import org.orienteer.core.util.OSchemaHelper;
import com.github.raymanrt.orientqb.query.Clause;
import com.github.raymanrt.orientqb.query.Operator;
import com.github.raymanrt.orientqb.query.Query;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;
import ru.ydn.wicket.wicketorientdb.utils.GetODocumentFieldValueFunction;
/**
* {@link IEntityHandler} for {@link ExecutionEntity}
*/
public class ExecutionEntityHandler extends AbstractEntityHandler<ExecutionEntity> {
public static final String OCLASS_NAME = "BPMExecution";
public ExecutionEntityHandler() {
super(OCLASS_NAME);
}
@Override
public void applySchema(OSchemaHelper helper) {
super.applySchema(helper);
helper.oProperty("processInstanceId", OType.STRING, 10)
.oProperty("parentId", OType.STRING, 20)
.oProperty("processDefinition", OType.LINK, 30).assignVisualization("listbox")
.markAsLinkToParent()
.markDisplayable()
.markAsDocumentName()
.oProperty("created", OType.DATETIME, 30).defaultValue("sysdate()").markDisplayable()
.oProperty("businessKey", OType.STRING, 30).markDisplayable()
.oProperty("superExecution", OType.LINK, 40).assignVisualization("listbox")
.oProperty("superCaseExecutionId", OType.STRING, 50)
.oProperty("caseInstanceId", OType.STRING, 60)
.oProperty("activityInstanceId", OType.STRING, 70)
.oProperty("activityId", OType.STRING, 80)
.oProperty("active", OType.BOOLEAN, 90)
.oProperty("concurrent", OType.BOOLEAN, 100)
.oProperty("scope", OType.BOOLEAN, 120)
.oProperty("eventScope", OType.BOOLEAN, 120)
.oProperty("suspensionState", OType.INTEGER, 140)
.oProperty("cachedEntityState", OType.INTEGER, 150)
.oProperty("sequenceCounter", OType.LONG, 160)
.oProperty("childExecutions", OType.LINKLIST, 170).assignVisualization("table")
.oProperty("tasks", OType.LINKLIST, 180).assignVisualization("table")
.oProperty("eventSubscriptions", OType.LINKLIST, 190).assignVisualization("table")
.oProperty("variables", OType.LINKLIST, 200).assignVisualization("table")
.oProperty("historyEvents", OType.LINKLIST, 210).assignTab("history").assignVisualization("table")
.oProperty("historyVariableInstances", OType.LINKLIST, 220).assignVisualization("table");
}
public void applyRelationships(OSchemaHelper helper) {
super.applyRelationships(helper);
helper.setupRelationship(ExecutionEntityHandler.OCLASS_NAME, "processDefinition", ProcessDefinitionEntityHandler.OCLASS_NAME, "executions");
helper.setupRelationship(ExecutionEntityHandler.OCLASS_NAME, "superExecution", ExecutionEntityHandler.OCLASS_NAME, "childExecutions");
helper.setupRelationship(ExecutionEntityHandler.OCLASS_NAME, "childExecutions", ExecutionEntityHandler.OCLASS_NAME, "superExecution");
helper.setupRelationship(ExecutionEntityHandler.OCLASS_NAME, "tasks", TaskEntityHandler.OCLASS_NAME, "execution");
helper.setupRelationship(ExecutionEntityHandler.OCLASS_NAME, "eventSubscriptions", EventSubscriptionEntityHandler.OCLASS_NAME, "execution");
helper.setupRelationship(ExecutionEntityHandler.OCLASS_NAME, "variables", VariableInstanceEntityHandler.OCLASS_NAME, "execution");
}
@Statement
public List<ExecutionEntity> selectProcessInstanceByQueryCriteria(OPersistenceSession session, ProcessInstanceQueryImpl query) {
return query(session, query, new IQueryMangler() {
@Override
public Query apply(Query input) {
input.where(Clause.clause("parentId", Operator.NULL, ""));
return input;
}
});
}
@Statement
public List<ExecutionEntity> selectExecutionsByQueryCriteria(final OPersistenceSession session, final ExecutionQueryImpl query) {
/*List<ExecutionEntity> ret = queryList(session, "SELECT FROM BPMExecution WHERE processInstanceId = ?", query.getProcessInstanceId());
LOG.info("Ret!!: "+ret);
return ret;*/
List<ExecutionEntity> ret = query(session, query, new Function<Query, Query>() {
@Override
public Query apply(Query input) {
SuspensionState state = query.getSuspensionState();
if(state!=null) input.where(Clause.clause("suspensionState", Operator.EQ, state.getStateCode()));
String businessKey = query.getBusinessKey();
if(businessKey!=null) {
List<ODocument> proc = session.getDatabase()
.query(new OSQLSynchQuery<>("select processInstanceId from "+getSchemaClass()+" where businessKey=?", 1)
, businessKey);
if(proc!=null && !proc.isEmpty()) {
String processInstanceId = proc.get(0).field("processInstanceId");
input.where(Clause.clause("processInstanceId", Operator.EQ, processInstanceId));
}
}
return input;
}
},"suspensionState", "businessKey");
List<EventSubscriptionQueryValue> subscriptionsQueries = query.getEventSubscriptions();
if(subscriptionsQueries!=null && !subscriptionsQueries.isEmpty()) {
ret = new ArrayList<>(ret);
for(EventSubscriptionQueryValue sub : subscriptionsQueries) {
ListIterator<ExecutionEntity> it = ret.listIterator();
while(it.hasNext()) {
ExecutionEntity entity = it.next();
List<EventSubscriptionEntity> subscriptions = entity.getEventSubscriptions();
boolean hasMatch = false;
for(EventSubscriptionEntity subscription: subscriptions) {
if((sub.getEventName()==null || sub.getEventName().equals(subscription.getEventName()))
&& (sub.getEventType()==null || sub.getEventType().equals(subscription.getEventType()))) {
hasMatch = true;
}
}
if(!hasMatch) it.remove();
}
}
}
List<QueryVariableValue> queryVariableValues = query.getQueryVariableValues();
if(queryVariableValues!=null && !queryVariableValues.isEmpty()) {
ret = new ArrayList<>(ret);
for(QueryVariableValue queryValue : queryVariableValues) {
ListIterator<ExecutionEntity> it = ret.listIterator();
while(it.hasNext()) {
ExecutionEntity entity = it.next();
QueryOperator operator = queryValue.getOperator();
Object value = entity.getVariable(queryValue.getName());
Object refValue = queryValue.getValue();
Comparable<Object> comparable = (value instanceof Comparable && refValue instanceof Comparable)?(Comparable<Object>)value:null;
boolean hasMatch;
switch (operator) {
case GREATER_THAN:
hasMatch = comparable!=null && comparable.compareTo(refValue)>0;
case GREATER_THAN_OR_EQUAL:
hasMatch = comparable!=null && comparable.compareTo(refValue)>=0;
case LESS_THAN:
hasMatch = comparable!=null && comparable.compareTo(refValue)<0;
case LESS_THAN_OR_EQUAL:
hasMatch = comparable!=null && comparable.compareTo(refValue)<=0;
case LIKE:
hasMatch = value!=null && Pattern.matches(refValue.toString(), value.toString());
break;
case NOT_EQUALS:
hasMatch = !Objects.equals(value, refValue);
break;
case EQUALS:
default:
hasMatch = Objects.equals(value, refValue);
break;
}
if(!hasMatch) it.remove();
}
}
}
return ret;
}
@Override
public boolean hasNeedInCache() {
return true;
}
@Statement
public List<ExecutionEntity> selectExecutionsByProcessInstanceId(OPersistenceSession session, ListQueryParameterObject obj) {
return queryList(session, "select from "+getSchemaClass()+" where processInstanceId = ?", obj.getParameter());
}
@Statement
public List<ExecutionEntity> selectExecutionsByParentExecutionId(OPersistenceSession session, ListQueryParameterObject parameter) {
return queryList(session, "select from "+getSchemaClass()+" where parentId = ?", parameter.getParameter());
}
private static final Function<ODocument, String> GET_ID_FUNCTION = new GetODocumentFieldValueFunction<String>("id");
@Statement
public List<String> selectProcessInstanceIdsByProcessDefinitionId(OPersistenceSession session, ListQueryParameterObject parameter) {
ODatabaseDocument db = session.getDatabase();
List<ODocument> resultSet = db.query(new OSQLSynchQuery<>("select id from "+getSchemaClass()+" where processDefinition.id = ?"), parameter.getParameter());
return Lists.transform(resultSet, GET_ID_FUNCTION);
}
}