package sushi.monitoring.bpmn;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import sushi.bpmn.element.AbstractBPMNElement;
import sushi.event.collection.SushiTree;
import sushi.process.SushiProcessInstance;
import sushi.query.PatternQueryType;
import sushi.query.SushiPatternQuery;
/**
* @author micha
*/
public class ProcessInstanceMonitor implements Serializable {
private static final long serialVersionUID = 1L;
private int ID;
private SushiProcessInstance processInstance;
//TODO: Tree der QueryMonitors
private List<QueryMonitor> queryMonitors;
private ProcessInstanceStatus status;
private Date startTime;
private Date endTime;
private ViolationMonitor violationMonitor;
public ProcessInstanceMonitor(SushiProcessInstance processInstance){
this.processInstance = processInstance;
this.ID = processInstance.getID();
this.queryMonitors = new ArrayList<QueryMonitor>();
this.violationMonitor = new ViolationMonitor(this);
refreshStatus();
}
public void addQuery(SushiPatternQuery query){
this.queryMonitors.add(new QueryMonitor(query,QueryStatus.Started, processInstance));
refreshStatus();
}
public void addQueries(Set<SushiPatternQuery> queries) {
for(SushiPatternQuery query : queries){
this.addQuery(query);
}
}
public SushiProcessInstance getProcessInstance() {
return processInstance;
}
public void setQueryFinished(SushiPatternQuery query) {
if(findQueryMonitorByQuery(query) != null){
findQueryMonitorByQuery(query).setQueryStatus(QueryStatus.Finished);
}
refreshStatus();
}
public void setQuerySkipped(SushiPatternQuery query) {
if(findQueryMonitorByQuery(query) != null){
findQueryMonitorByQuery(query).setQueryStatus(QueryStatus.Skipped);
}
refreshStatus();
}
public ProcessInstanceStatus getStatus() {
return status;
}
public void setStatus(ProcessInstanceStatus processInstanceStatus) {
this.status = processInstanceStatus;
}
private boolean allQueriesTerminated() {
int executionCount = 0;
if(!queryMonitors.isEmpty()){
executionCount = queryMonitors.get(0).getExecutionCount();
}
for(QueryMonitor queryMonitor : queryMonitors){
if(queryMonitor.isRunning() && queryMonitor.getExecutionCount() == executionCount){
return false;
}
}
return true;
}
private ProcessInstanceStatus refreshStatus(){
this.startTime = calculateStartTime();
this.endTime = calculateEndTime();
if(processInstance == null){
this.status = ProcessInstanceStatus.NotExisting;
} else {
adaptQueryStatus();
if(allQueriesTerminated()){
this.status = ProcessInstanceStatus.Finished;
} else {
this.status = ProcessInstanceStatus.Running;
}
}
return this.status;
}
/**
* Searches for queries for the given process instance, that could be set started, skipped or finished.
*/
private void adaptQueryStatus() {
for(SushiPatternQuery query : getQueriesWithStatus(QueryStatus.Finished)){
//XORQuery finished, SubQueries mit Running auf Skipped setzten
if(query.getPatternQueryType().equals(PatternQueryType.XOR)){
skipStartedSubQueries(query);
}
}
violationMonitor.searchForViolations();
}
private QueryMonitor getRootQueryMonitor(){
for(QueryMonitor queryMonitor : queryMonitors){
if(queryMonitor.getQuery().getParentQuery() == null){
return queryMonitor;
}
}
return null;
}
List<QueryMonitor> getSubQueryMonitors(QueryMonitor queryMonitor) {
Set<SushiPatternQuery> childQueries = queryMonitor.getQuery().getChildQueries();
List<QueryMonitor> subQueryMonitors = new ArrayList<QueryMonitor>();
for(SushiPatternQuery childQuery : childQueries){
subQueryMonitors.add(getQueryMonitorForQuery(childQuery));
}
return subQueryMonitors;
}
QueryMonitor getQueryMonitorForQuery(SushiPatternQuery query) {
for(QueryMonitor queryMonitor : queryMonitors){
if(queryMonitor.getQuery().equals(query)){
return queryMonitor;
}
}
return null;
}
public List<QueryMonitor> getQueryMonitorsWithStatus(QueryStatus status) {
List<QueryMonitor> queryMonitorsWithStatus = new ArrayList<QueryMonitor>();
for(QueryMonitor queryMonitor : queryMonitors){
if(queryMonitor.getQueryStatus().equals(status)){
queryMonitorsWithStatus.add(queryMonitor);
}
}
return queryMonitorsWithStatus;
}
/**
* Searches recursively for child queries with {@link QueryStatus} Started and sets their {@link QueryStatus} to Skipped.
* @param parentQuery
*/
private void skipStartedSubQueries(SushiPatternQuery parentQuery) {
for(SushiPatternQuery query : parentQuery.getChildQueries()){
if(getStatusForQuery(query).equals(QueryStatus.Started)){
setStatusForQuery(query, QueryStatus.Skipped);
if(query.hasChildQueries()){
skipStartedSubQueries(query);
}
}
}
}
public int getID() {
return ID;
}
/**
* Returns all {@link SushiPatternQuery} from the contained {@link QueryMonitor}s.
* @param queryStatus
* @return
*/
public Set<SushiPatternQuery> getQueries() {
Set<SushiPatternQuery> queries = new HashSet<SushiPatternQuery>();
for(QueryMonitor queryMonitor : queryMonitors){
queries.add(queryMonitor.getQuery());
}
return queries;
}
/**
* Returns all {@link SushiPatternQuery} from the contained {@link QueryMonitor}s, which have the specified {@link QueryStatus}.
* @param queryStatus
* @return
*/
public Set<SushiPatternQuery> getQueriesWithStatus(QueryStatus queryStatus) {
Set<SushiPatternQuery> queries = new HashSet<SushiPatternQuery>();
for(QueryMonitor queryMonitor : queryMonitors){
if(queryMonitor.getQueryStatus().equals(queryStatus)){
queries.add(queryMonitor.getQuery());
}
}
return queries;
}
/**
* Returns all {@link QueryMonitor}, which have the specified {@link PatternQueryType}.
* @param queryStatus
* @return
*/
public Set<QueryMonitor> getQueryMonitorsWithQueryType(PatternQueryType patternQueryType) {
Set<QueryMonitor> queryMonitorsWithPatternQueryType = new HashSet<QueryMonitor>();
for(QueryMonitor queryMonitor : this.queryMonitors){
if(queryMonitor.getQuery().getPatternQueryType().equals(patternQueryType)){
queryMonitorsWithPatternQueryType.add(queryMonitor);
}
}
return queryMonitorsWithPatternQueryType;
}
/**
* Returns all {@link QueryMonitor}, which have the specified monitored {@link AbstractBPMNElement}.
* @param queryStatus
* @return
*/
public Set<QueryMonitor> getQueryMonitorsWithMonitoredElements(Collection<AbstractBPMNElement> monitoredElements) {
Set<QueryMonitor> queryMonitorsWithMonitoredElements = new HashSet<QueryMonitor>();
for(QueryMonitor queryMonitor : this.queryMonitors){
List<AbstractBPMNElement> queryMonitoredElements = queryMonitor.getQuery().getMonitoredElements();
if(queryMonitoredElements.containsAll(monitoredElements) && monitoredElements.containsAll(queryMonitoredElements)){
queryMonitorsWithMonitoredElements.add(queryMonitor);
}
}
return queryMonitorsWithMonitoredElements;
}
public QueryStatus getStatusForQuery(SushiPatternQuery query){
if(findQueryMonitorByQuery(query) != null){
return findQueryMonitorByQuery(query).getQueryStatus();
} else {
return QueryStatus.NotExisting;
}
}
public Set<ViolationStatus> getViolationStatusForQuery(SushiPatternQuery query){
if(findQueryMonitorByQuery(query) != null){
return findQueryMonitorByQuery(query).getViolationStatus();
} else {
return null;
}
}
public void setStatusForQuery(SushiPatternQuery query, QueryStatus queryStatus){
QueryMonitor queryMonitor = findQueryMonitorByQuery(query);
if(queryMonitor != null){
queryMonitor.setQueryStatus(queryStatus);
}
}
private QueryMonitor findQueryMonitorByQuery(SushiPatternQuery query){
for(QueryMonitor queryMonitor : queryMonitors){
if(queryMonitor.getQuery().equals(query)){
return queryMonitor;
}
}
return null;
}
public Date getStartTime() {
return (startTime != null) ? startTime : new Date();
}
public Date getEndTime() {
return (endTime != null) ? endTime : new Date();
}
private Date calculateStartTime(){
Date startTime = new Date();
for(QueryMonitor queryMonitor : queryMonitors){
if(queryMonitor.getStartTime().before(startTime)){
startTime = queryMonitor.getStartTime();
}
}
return startTime;
}
private Date calculateEndTime(){
Date endTime = calculateStartTime();
for(QueryMonitor queryMonitor : queryMonitors){
if(queryMonitor.getEndTime().after(endTime)){
endTime = queryMonitor.getStartTime();
}
}
return endTime;
}
public Date getStartTimeForQuery(SushiPatternQuery query){
if(findQueryMonitorByQuery(query) != null){
return findQueryMonitorByQuery(query).getStartTime();
}
return new Date();
}
public Date getEndTimeForQuery(SushiPatternQuery query){
if(findQueryMonitorByQuery(query) != null){
return findQueryMonitorByQuery(query).getEndTime();
}
return new Date();
}
public long getRuntimeForQuery(SushiPatternQuery query){
return getEndTimeForQuery(query).getTime() - getStartTimeForQuery(query).getTime();
}
public SushiTree<DetailedQueryStatus> getDetailedStatus() {
SushiTree<DetailedQueryStatus> detailedQueryStatusTree = new SushiTree<DetailedQueryStatus>();
QueryMonitor rootQueryMonitor = getRootQueryMonitor();
if(rootQueryMonitor != null){
detailedQueryStatusTree.addRootElement(rootQueryMonitor.getDetailedQueryStatus());
addSubQueryMonitorsToTree(rootQueryMonitor, detailedQueryStatusTree);
}
return detailedQueryStatusTree;
}
private void addSubQueryMonitorsToTree(QueryMonitor parentQueryMonitor, SushiTree<DetailedQueryStatus> detailedQueryStatusTree) {
List<QueryMonitor> subQueryMonitors = getSubQueryMonitors(parentQueryMonitor);
if(!subQueryMonitors.isEmpty()){
for(QueryMonitor queryMonitor : subQueryMonitors){
detailedQueryStatusTree.addChild(parentQueryMonitor.getDetailedQueryStatus(), queryMonitor.getDetailedQueryStatus());
addSubQueryMonitorsToTree(queryMonitor, detailedQueryStatusTree);
}
}
}
}