package sushi.monitoring.bpmn; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import sushi.bpmn.decomposition.Component; import sushi.bpmn.decomposition.IPattern; import sushi.bpmn.element.AbstractBPMNElement; import sushi.bpmn.monitoringpoint.MonitoringPoint; import sushi.bpmn.monitoringpoint.MonitoringPointStateTransition; import sushi.event.SushiEvent; import sushi.event.collection.SushiTree; import sushi.process.SushiProcessInstance; import sushi.query.PatternQueryType; import sushi.query.SushiPatternQuery; /** * @author micha */ public class QueryMonitor implements Serializable { private static final long serialVersionUID = 1L; private SushiPatternQuery query; //TODO: Map für QueryStatus: ExecutionCount --> QueryStatus // private List<QueryStatus> queryStatus; // private Set<ViolationStatus> violationStatus; private SushiProcessInstance processInstance; private Date startTime; private Date endTime; private boolean isInLoop; private List<DetailedQueryStatus> detailedQueryStatus; public QueryMonitor(SushiPatternQuery query, QueryStatus queryStatus, SushiProcessInstance processInstance) { this.query = query; // this.queryStatus = new ArrayList<QueryStatus>(); // this.queryStatus.add(queryStatus); // this.violationStatus = new HashSet<ViolationStatus>(); this.processInstance = processInstance; this.startTime = this.calculateStartTime(); this.isInLoop = determineIsInLoop(); this.detailedQueryStatus = new ArrayList<DetailedQueryStatus>(); this.detailedQueryStatus.add(new DetailedQueryStatus(this.query, queryStatus, new HashSet<ViolationStatus>())); } public SushiPatternQuery getQuery() { return query; } public QueryStatus getQueryStatus() { return getLastDetailedQueryStatus().getQueryStatus(); } public void setQueryStatus(QueryStatus queryStatus) { //TODO: Queries sollten mehrmals beendbar sein, falls sie sich in einer Schleife befinden if(queryStatus.equals(QueryStatus.Finished) || queryStatus.equals(QueryStatus.Skipped)){ this.endTime = new Date(); if(queryStatus.equals(QueryStatus.Finished) && this.detailedQueryStatus.size() > 1 && !isInLoop){ getLastDetailedQueryStatus().getViolationStatus().add(ViolationStatus.Duplication); } } if(getLastDetailedQueryStatus().getQueryStatus().equals(QueryStatus.Started)){ //Bei erstem Finishen der Query, danach ist Start nicht mehr so einfach ermittelbar getLastDetailedQueryStatus().setQueryStatus(queryStatus); } else { //Falls Query nochmal fertiggestellt wird (Schleife) this.detailedQueryStatus.add(new DetailedQueryStatus(this.query, queryStatus, new HashSet<ViolationStatus>())); } } private Date calculateStartTime() { if(!query.getMonitoredElements().isEmpty()){ AbstractBPMNElement firstElement = query.getMonitoredElements().get(0); MonitoringPoint firstMonitoringPoint = getFirstMonitoringPoint(firstElement); if(firstMonitoringPoint != null){ List<SushiEvent> eventsWithMatchingEventType = SushiEvent.findByEventType(firstMonitoringPoint.getEventType()); for(SushiEvent event : eventsWithMatchingEventType){ if(event.getProcessInstances().contains(processInstance)){ return event.getTimestamp(); } } } } return new Date(); } private MonitoringPoint getFirstMonitoringPoint(AbstractBPMNElement firstElement) { if(firstElement.getMonitoringPointByStateTransitionType(MonitoringPointStateTransition.enable) != null){ return firstElement.getMonitoringPointByStateTransitionType(MonitoringPointStateTransition.enable); } else if(firstElement.getMonitoringPointByStateTransitionType(MonitoringPointStateTransition.begin) != null){ return firstElement.getMonitoringPointByStateTransitionType(MonitoringPointStateTransition.begin); } else if(firstElement.getMonitoringPointByStateTransitionType(MonitoringPointStateTransition.terminate) != null){ return firstElement.getMonitoringPointByStateTransitionType(MonitoringPointStateTransition.terminate); } else if(firstElement.getMonitoringPointByStateTransitionType(MonitoringPointStateTransition.skip) != null){ return firstElement.getMonitoringPointByStateTransitionType(MonitoringPointStateTransition.skip); } return null; } public Date getStartTime() { return (startTime != null) ? startTime : new Date(); } public Date getEndTime() { return (endTime != null) ? endTime : new Date(); } public Set<ViolationStatus> getViolationStatus() { Set<ViolationStatus> violations = new HashSet<ViolationStatus>(); for(DetailedQueryStatus detailedQueryStatus : this.detailedQueryStatus){ violations.addAll(detailedQueryStatus.getViolationStatus()); } return violations; } public void setViolationStatus(Set<ViolationStatus> violationStatus) { getLastDetailedQueryStatus().setViolationStatus(violationStatus); } public void addViolationStatus(ViolationStatus violationStatus) { getLastDetailedQueryStatus().getViolationStatus().add(violationStatus); } public void setEndTime(Date endTime) { this.endTime = endTime; } /** * Returns, how often the query was triggered as finished or skipped. * @return */ public int getExecutionCount() { return detailedQueryStatus.size(); } /** * Returns true, if the monitored elements of this queries are contained in a loop. * @return */ public boolean isInLoop(){ return this.isInLoop; } private boolean determineIsInLoop() { if(query.getPatternQueryType().equals(PatternQueryType.STATETRANSITION)){ //Query sollte hier nur ein monitored Element enthalten if(!query.getMonitoredElements().isEmpty()){ AbstractBPMNElement monitoredElement = query.getMonitoredElements().get(0); return monitoredElement.getIndirectSuccessors().contains(monitoredElement); } } else { SushiTree<AbstractBPMNElement> processDecompositionTree = this.processInstance.getProcess().getProcessDecompositionTree(); if(processDecompositionTree != null){ Set<AbstractBPMNElement> indirectParents = processDecompositionTree.getIndirectParents(this.query.getMonitoredElements()); for(AbstractBPMNElement parent : indirectParents){ if(parent instanceof Component && ((Component)parent).getType().equals(IPattern.LOOP)){ return true; } } } } return false; } /** * Returns true, if the {@link QueryStatus} is Finished or Skipped. * @return */ public boolean isTerminated() { QueryStatus currentStatus = getLastDetailedQueryStatus().getQueryStatus(); return currentStatus.equals(QueryStatus.Finished) || currentStatus.equals(QueryStatus.Skipped) || currentStatus.equals(QueryStatus.Aborted); } /** * Returns true, if the {@link QueryStatus} is Finished. * @return */ public boolean isFinished() { return getLastDetailedQueryStatus().getQueryStatus().equals(QueryStatus.Finished); } public DetailedQueryStatus getDetailedQueryStatus() { return getLastDetailedQueryStatus(); } private DetailedQueryStatus getLastDetailedQueryStatus(){ return this.detailedQueryStatus.get(this.detailedQueryStatus.size() - 1); } public boolean isRunning() { return getLastDetailedQueryStatus().getQueryStatus().equals(QueryStatus.Started); } }