Browse Source

Merge remote-tracking branch 'origin/master'

Joeri Exelmans 2 years ago
parent
commit
9aa23eabcd

+ 1 - 2
src/main/java/ua/be/wee/controller/EnactmentControllerMVC.java

@@ -119,8 +119,7 @@ public class EnactmentControllerMVC {
         	request.getSession().removeAttribute("arts");
         	return "enact";
 		} else if (element.getNode() != null) {
-			String previous = (String)request.getSession().getAttribute("previous");
-			Event endTraceEvent = controller.addEndTraceEvent(pt.getIri(), previous, pm.getIri());
+			Event endTraceEvent = controller.addEndTraceEvent(pt.getIri(), pt.getLastEvent().getIri(), pm.getIri());
 			pt.addEvent(endTraceEvent);
 			controller.updatePT(pt);
 			return "endEnactment";

+ 23 - 4
src/main/java/ua/be/wee/controller/rest/PTController.java

@@ -4,9 +4,11 @@ import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RestController;
 
-import ua.be.wee.model.pt.PT;
+import ua.be.wee.model.pt.Event;
+import ua.be.wee.model.pt.StartTraceEvent;
 import ua.be.wee.model.repository.PTRepository;
 
 @RestController
@@ -15,12 +17,29 @@ public class PTController {
 	@Autowired
 	private PTRepository ptRepository;
 	
+	@GetMapping("/traces")
+	List<StartTraceEvent> allPTs() {
+		return ptRepository.getStartTraceEvents();
+	}
 	
 	
-	@GetMapping("/startTraceEvents")
-	List<PT> allPTs() {
-		return ptRepository.getStartTraceEvents();
+	@GetMapping("/traces/events/{traceiri}")
+	List<Event> getEvents(@PathVariable String traceiri) throws Exception {
+		return ptRepository.getEvents(traceiri);
+	}
+	
+	
+	@GetMapping("/traces/active/{pmiri}")
+	List<StartTraceEvent> getActiveTraces(@PathVariable String pmiri) throws Exception {
+		return ptRepository.getActiveTraces(pmiri);
+	}
+	
+	@GetMapping("/traces/finished/{pmiri}")
+	List<StartTraceEvent> getConcludedTraces(@PathVariable String pmiri) throws Exception {
+		return ptRepository.getConcludedTraces(pmiri);
 	}
+	
+
 
 	
 }

+ 4 - 0
src/main/java/ua/be/wee/model/pt/EndActivityEvent.java

@@ -38,6 +38,10 @@ public class EndActivityEvent extends Event {
 		return producedArtifacts;
 	}
 	
+	public void setProducedArtifacts(List<TraceArtifact> arts) {
+		producedArtifacts = arts;
+	}
+	
 	public TraceArtifact getArtifact(String iri) {
 		for (TraceArtifact traceArtifact : producedArtifacts) {
 			if (iri.equals(traceArtifact.getIri())) {

+ 6 - 0
src/main/java/ua/be/wee/model/pt/Event.java

@@ -21,6 +21,12 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
 @Entity
 public abstract class Event {
 	
+	public static final String START_TRACE_IRI = "http://ua.be/sdo2l/vocabulary/formalisms/processtraces#StartTraceEvent";
+	public static final String END_TRACE_IRI = "http://ua.be/sdo2l/vocabulary/formalisms/processtraces#EndTraceEvent";
+	public static final String START_ACTIVITY_IRI = "http://ua.be/sdo2l/vocabulary/formalisms/processtraces#StartActivityEvent";
+	public static final String END_ACTIVITY_IRI = "http://ua.be/sdo2l/vocabulary/formalisms/processtraces#EndActivityEvent";
+	public static final String ARTIFACT_IRI = "http://ua.be/sdo2l/vocabulary/formalisms/processtraces#Artifact";
+	
 	@Id
 	private String iri;
 	

+ 0 - 16
src/main/java/ua/be/wee/model/pt/PT.java

@@ -1,8 +1,6 @@
 package ua.be.wee.model.pt;
 
 
-import java.sql.Timestamp;
-import java.text.SimpleDateFormat;
 import java.util.List;
 
 import javax.persistence.Entity;
@@ -28,8 +26,6 @@ public class PT {
 	
 	@OneToOne
 	private PM pmEnacted;
-	
-	private Timestamp timestamp;
 
 	public PM getPmEnacted() {
 		return pmEnacted;
@@ -39,14 +35,6 @@ public class PT {
 		this.pmEnacted = pmEnacted;
 	}
 
-	public Timestamp getTimestamp() {
-		return timestamp;
-	}
-
-	public void setTimestamp(Timestamp timestamp) {
-		this.timestamp = timestamp;
-	}
-
 	public String getIri() {
 		return iri;
 	}
@@ -59,10 +47,6 @@ public class PT {
 	public String getName() {
 		return name;
 	}
-	
-	public String getTimestampF() {
-		return new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(timestamp);
-	}
 
 	public List<Event> getEvents() {
 		return events;

+ 5 - 1
src/main/java/ua/be/wee/model/pt/StartActivityEvent.java

@@ -34,10 +34,14 @@ public class StartActivityEvent extends Event {
 		consumedArtifacts.add(art);
 	}
 	
-	public List<TraceArtifact> getProducedArtifacts() {
+	public List<TraceArtifact> getConsumedArtifacts() {
 		return consumedArtifacts;
 	}
 	
+	public void setConsumedArtifacts(List<TraceArtifact> arts) {
+		consumedArtifacts = arts;
+	}
+	
 	public TraceArtifact getArtifact(String iri) {
 		for (TraceArtifact traceArtifact : consumedArtifacts) {
 			if (iri.equals(traceArtifact.getIri())) {

+ 21 - 0
src/main/java/ua/be/wee/model/pt/StartTraceEvent.java

@@ -0,0 +1,21 @@
+package ua.be.wee.model.pt;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+
+import ua.be.wee.model.pm.PM;
+
+@Entity
+public class StartTraceEvent extends Event {
+	
+	@ManyToOne
+	private PM pmEnacted;
+
+	public PM getPmEnacted() {
+		return pmEnacted;
+	}
+
+	public void setPmEnacted(PM pmEnacted) {
+		this.pmEnacted = pmEnacted;
+	}
+}

+ 331 - 16
src/main/java/ua/be/wee/model/repository/PTRepository.java

@@ -10,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 
 import ua.be.wee.model.nodes.Activity;
+import ua.be.wee.model.nodes.Artifact;
 import ua.be.wee.model.nodes.ports.ControlInputPort;
 import ua.be.wee.model.nodes.ports.ControlOutputPort;
 import ua.be.wee.model.pm.PM;
@@ -18,14 +19,21 @@ import ua.be.wee.model.pt.EndTraceEvent;
 import ua.be.wee.model.pt.Event;
 import ua.be.wee.model.pt.PT;
 import ua.be.wee.model.pt.StartActivityEvent;
+import ua.be.wee.model.pt.StartTraceEvent;
 import ua.be.wee.model.pt.TraceArtifact;
 import ua.be.wee.model.util.DateTimeConverter;
+import ua.be.wee.model.util.Pair;
 
 @Repository
 public class PTRepository {
 	
 	@Autowired
 	private PMRepository pmRepo;
+	
+	@Autowired
+	private NodeRespository nodeRepo;
+	
+	
 
 	public PT createTrace(PM pm) throws Exception {
 		int index = getNextIndex(pm);
@@ -49,7 +57,8 @@ public class PTRepository {
 			PT pt = new PT();
 			pt.setPmEnacted(pm);
 			pt.setIri(traceiri);
-			pt.setEvents(new ArrayList<Event>());
+			
+			
 			
 			query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
 					+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
@@ -62,7 +71,14 @@ public class PTRepository {
 			if (results.hasNext()) {
 				QuerySolution next = results.next();
 				RDFNode rdfNode = next.get("?ts");
-				pt.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(rdfNode.toString()));
+				
+				StartTraceEvent ev = new StartTraceEvent();
+				ev.setIri(traceiri);
+				ev.setPmEnacted(pm);
+				ev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(rdfNode.toString()));
+				List<Event> list = new ArrayList<Event>();
+				list.add(ev);
+				pt.setEvents(list);
 			}
 			return pt;
 		} else {
@@ -87,7 +103,7 @@ public class PTRepository {
 	}
 
 	public void createStartEvent(PT pt, ControlInputPort port, Activity act, List<TraceArtifact> arts) throws Exception {
-		int index = pt.getLastEvent() == null ? 0 : (Integer.parseInt(""+pt.getLastEvent().getIri().charAt(pt.getLastEvent().getIri().length()-1))+1); 
+		int index = pt.getEvents().size() == 1 ? 0 : (Integer.parseInt(""+pt.getLastEvent().getIri().charAt(pt.getLastEvent().getIri().length()-1))+1); 
 
 		String iri = pt.getIri().replace('#', '/') + "#" + "start_activity" + index;
 		String endiri = pt.getIri().replace('#', '/') + "#" + "end_activity" + index;
@@ -101,7 +117,6 @@ public class PTRepository {
 				+ "INSERT {\n"
 				+ "	<" + iri + "> rdf:type <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#StartActivityEvent> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#element> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#Event> , owl:Thing , <http://ua.be/sdo2l/vocabulary/base/acyclic#element> ;\n"
 				+ "    base:acyclicForward <" + endiri + "> ;\n"
-				+ "    tr:isFollowedBy <" + endiri + "> ;\n"
 				+ "    tr:hasTimestamp ?now ; \n"
 				+ "    tr:isPrecededBy <" + preiri + "> ;\n"
 				+ "    tr:relatesTo <" + portiri + "> ;\n";
@@ -111,6 +126,7 @@ public class PTRepository {
 			}
 		}
 		query +=  "    owl:sameAs <" + iri + "> .\n"
+				+ " <"+ preiri + "> tr:isFollowedBy <" + iri + "> .\n" 
 				+ "} WHERE {"
 				+ "	SELECT ?now\n"
 				+ "    WHERE\n"
@@ -163,7 +179,11 @@ public class PTRepository {
 	public void updatePT(PT pt) throws Exception {
 		String transitive = "";
 		for (Event ev : pt.getEvents()) {
-			transitive += "<" + ev.getIri()+">,";
+			if (ev instanceof StartTraceEvent) {
+				continue;
+			} else {
+				transitive += "<" + ev.getIri()+">,";
+			}
 		}
 		transitive = transitive.substring(0, transitive.length()-1);
 		
@@ -179,10 +199,10 @@ public class PTRepository {
 				+ "};\n"
 				+ "INSERT DATA {\n"
 				+ "	<" + pt.getIri() + "> rdf:type    <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#Event> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#StartTraceEvent> , owl:Thing , <http://ua.be/sdo2l/vocabulary/base/acyclic#element> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#element> ;\n"
-				+ "    base:acyclicForward <" + pt.getEvents().get(0).getIri() + "> ;\n"
+				+ "    base:acyclicForward <" + pt.getEvents().get(1).getIri() + "> ;\n"
 				+ "    base:transitiveForward "+ transitive + " ;\n"
-				+ "    tr:isFollowedBy <" + pt.getEvents().get(0).getIri() + "> ;\n"
-				+ "    tr:hasTimestamp " + DateTimeConverter.convertTimestampToSPARQLdateTime(pt.getTimestamp()) + " ; \n "
+				+ "    tr:isFollowedBy <" + pt.getEvents().get(1).getIri() + "> ;\n"
+				+ "    tr:hasTimestamp " + DateTimeConverter.convertTimestampToSPARQLdateTime(pt.getEvents().get(0).getTimestamp()) + " ; \n "
 				+ "    tr:relatesTo <" + pt.getPmEnacted().getIri() + "> ;\n"
 				+ "    owl:sameAs <"+ pt.getIri() + "> .\n"
 				+ "};";
@@ -205,9 +225,10 @@ public class PTRepository {
 				break;
 			}
 		}
+		String preiri = pt.getLastEvent() != null ? pt.getLastEvent().getIri() : pt.getIri();
 		int index = (Integer.parseInt(""+source.getIri().charAt(source.getIri().length()-1)));
 		
-		String startiri = pt.getIri().replace('#', '/') + "#" + "start_activity" + index;
+		//String startiri = pt.getIri().replace('#', '/') + "#" + "start_activity" + index;
 		String endiri = pt.getIri().replace('#', '/') + "#" + "end_activity" + index;
 		
 		List<String> artifactsIRI = new ArrayList<String>();
@@ -215,7 +236,7 @@ public class PTRepository {
 			String artifactIRI = pt.getIri().replace('#', '/') + "#" + art.getGUID();
 			art.setIri(artifactIRI);
 			artifactsIRI.add(artifactIRI);
-			createTraceArtifact(endiri,startiri, art, pt);
+			createTraceArtifact(endiri,preiri, art, pt);
 		}
 		
 	
@@ -224,8 +245,8 @@ public class PTRepository {
 				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
 				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/acyclic#>\n"
 				+ "INSERT {\n"
-				+ "	<" + endiri + "> rdf:type <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#StartActivityEvent> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#element> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#Event> , owl:Thing , <http://ua.be/sdo2l/vocabulary/base/acyclic#element> ;\n"
-				+ "    tr:isPrecededBy <" + startiri + "> ;\n"
+				+ "	<" + endiri + "> rdf:type <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#EndActivityEvent> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#element> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#Event> , owl:Thing , <http://ua.be/sdo2l/vocabulary/base/acyclic#element> ;\n"
+				+ "    tr:isPrecededBy <" + preiri + "> ;\n"
 				+ "    tr:relatesTo <" + p.getIri() + "> ;\n"
 				+ "    tr:hasTimestamp ?now ; \n";
 				
@@ -233,7 +254,7 @@ public class PTRepository {
 			query += "    tr:produces <" + iri + "> ;\n" ;
 		}
 		query += "    owl:sameAs <" + endiri + "> .\n"
-			  + " <"+ startiri + "> tr:isFollowedBy <" + endiri + "> .\n"
+			  + " <"+ preiri + "> tr:isFollowedBy <" + endiri + "> .\n"
 			  + "} WHERE {"
 				+ "	SELECT ?now\n"
 				+ "    WHERE\n"
@@ -395,6 +416,7 @@ public class PTRepository {
 
 	public Event createEndTraceEvent(String ptIRI, String previous, String pmIRI) throws Exception {
 		String traceiri = ptIRI + "_end";
+		
 		String query = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
 				+ "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
 				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
@@ -440,8 +462,8 @@ public class PTRepository {
 	}
 
 	
-	public List<PT> getStartTraceEvents() {
-		List<PT> list = new ArrayList<PT>();
+	public List<StartTraceEvent> getStartTraceEvents() {
+		List<StartTraceEvent> list = new ArrayList<StartTraceEvent>();
 		String query = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
 				+ "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
 				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
@@ -456,7 +478,7 @@ public class PTRepository {
 			RDFNode trace = next.get("?trace");
 			RDFNode pm = next.get("?pm");
 			RDFNode ts = next.get("?ts");
-			PT pt = new PT();
+			StartTraceEvent pt = new StartTraceEvent();
 			pt.setIri(trace.toString());
 			pt.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(ts.toString()));
 			pt.setPmEnacted(pmRepo.getPM(pm.toString()));
@@ -465,4 +487,297 @@ public class PTRepository {
 		return list;
 	}
 
+	public List<Event> getEvents(String startEventIRI) throws Exception {
+		List<Event> list = new ArrayList<Event>();
+		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "SELECT ?trace ?pm ?ts ?next ?nexttype WHERE {\n"
+				+ "	?trace owl:sameAs <" + startEventIRI + "> ;\n"
+				+ "    	tr:relatesTo ?pm ;\n"
+				+ "	 	tr:hasTimestamp ?ts .\n"
+				+ "   	OPTIONAL {\n"
+				+ "    	?trace tr:isFollowedBy ?next .\n"
+				+ "		?next a ?nexttype .\n"
+				+ "     	FILTER (?nexttype IN (tr:StartActivityEvent, tr:EndActivityEvent, tr:EndTraceEvent)) .\n"
+				+ "  	}\n"
+				+ "}";
+		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
+		if (rs.hasNext()) {
+			QuerySolution sol = rs.next();
+			RDFNode trace = sol.get("?trace");
+			RDFNode pm = sol.get("?pm");
+			RDFNode ts = sol.get("?ts");
+			RDFNode nextQ = sol.get("?next");
+			RDFNode nexttypeQ = sol.get("?nexttype");
+			
+			StartTraceEvent stev = new StartTraceEvent();
+			stev.setIri(trace.toString());
+			PM pm2 = pmRepo.getPM(pm.toString());
+			pm2.setNodes(nodeRepo.getNodes(pm2.getIri()));
+			stev.setPmEnacted(pm2);
+			stev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(ts.toString()));
+			list.add(stev);
+			
+			String next = nextQ != null ? nextQ.toString() : null;
+			String nexttype = nexttypeQ != null ? nexttypeQ.toString() : null;
+			
+			while (next!= null && !next.toString().equals("")) {
+				if (nexttype.toString().equals(Event.START_ACTIVITY_IRI)) {
+					Pair<String,String> p = getStartActivityEvent(next.toString(), pm2, list);
+					next = p != null ? p.getFst() : null;
+					nexttype = p != null ? p.getSnd() : null;
+				} else if (nexttype.toString().equals(Event.END_ACTIVITY_IRI)) {
+					Pair<String,String> p = getEndActivityEvent(next.toString(), pm2, list);
+					next = p != null ? p.getFst() : null;
+					nexttype = p != null ? p.getSnd() : null;
+				} else if (nexttype.toString().equals(Event.END_TRACE_IRI)) {
+					getEndTraceEvent(next.toString(), pm2, list);
+					next = null;
+				} else {
+					throw new Exception("Unexpected type of event");
+				}
+			}
+			
+		}
+		return list;
+	}
+
+	private void getEndTraceEvent(String iri, PM pmo, List<Event> list) throws Exception {
+		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "SELECT ?trace ?pm ?ts WHERE {\n"
+				+ "	?trace owl:sameAs <" + iri + "> ;\n"
+				+ "    	tr:relatesTo ?pm ;\n"
+				+ "	 	tr:hasTimestamp ?ts ;\n"
+				+ "}";
+		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
+		if (rs.hasNext()) {
+			QuerySolution sol = rs.next();
+			RDFNode trace = sol.get("?trace");
+			RDFNode ts = sol.get("?ts");
+			
+			EndTraceEvent ev = new EndTraceEvent();
+			ev.setIri(trace.toString());
+			ev.setPmEnacted(pmo);
+			ev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(ts.toString()));
+			list.add(ev);
+		} else {
+			throw new Exception("No data returned by query: \n" + query );
+		}
+	}
+	
+	private Pair<String, String> getStartActivityEvent(String iri, PM pm, List<Event> list) throws Exception {
+		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
+				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "SELECT ?trace ?port ?act ?ts ?next ?nexttype WHERE {\n"
+				+ "	?trace owl:sameAs <" + iri + "> ;\n"
+				+ "    	tr:relatesTo ?port ;\n"
+				+ "	 	tr:hasTimestamp ?ts .\n"
+				+ " ?act pm:hasPort ?port .\n"
+				+ "   OPTIONAL {\n"
+				+ "    ?trace tr:isFollowedBy ?next .\n"
+				+ "	   ?next a ?nexttype .\n"
+				+ "    FILTER (?nexttype IN (tr:StartActivityEvent, tr:EndActivityEvent, tr:EndTraceEvent)) . \n"
+				+ "  }\n"
+				+ "}";
+		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
+		if (rs.hasNext()) {
+			QuerySolution sol = rs.next();
+			RDFNode trace = sol.get("?trace");
+			RDFNode port = sol.get("?port");
+			RDFNode act = sol.get("?act");
+			
+			Activity activity = (Activity)pm.getNode(act.toString());
+			List<ControlInputPort> ctrlInPorts = activity.getCtrlInPorts();
+			ControlInputPort ctrlPort = null;
+			for (ControlInputPort ctrl : ctrlInPorts) {
+				if (ctrl.getIri().equals(port.toString())) {
+					ctrlPort = ctrl;
+					break;
+				}
+			}
+			RDFNode ts = sol.get("?ts");
+
+			StartActivityEvent stev = new StartActivityEvent();
+			stev.setIri(trace.toString());
+			stev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(ts.toString()));
+			stev.setRelatesTo(ctrlPort);
+			
+			stev.setConsumedArtifacts(getArtifacts(stev,pm));
+
+			
+			list.add(stev);
+			
+			RDFNode next = sol.get("?next");
+			if (next == null) {
+				return null;
+			} else {
+				return new Pair<String, String>(next.toString(),sol.get("?nexttype").toString());
+			}
+		} else {
+			throw new Exception("No data returned by query: \n" + query );
+		}
+		
+	}
+
+	private List<TraceArtifact> getArtifacts(Event ev, PM pm) {
+		List<TraceArtifact> arts = new ArrayList<TraceArtifact>();
+		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/base#>\n"
+				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "SELECT ?art ?ts ?guid ?location ?tag ?pmArt WHERE {\n"
+				+ "	?art a tr:Artifact .\n"
+				+ (ev instanceof StartActivityEvent ? 
+						"  	<" + ev.getIri() + "> tr:consumes ?art .\n" : 
+							"  	<" + ev.getIri() + "> tr:produces ?art .\n")
+				+ "    ?art tr:addedAt ?ts .\n"
+				+ "    ?art base:hasGUID ?guid .\n"
+				+ "    ?art tr:hasLocation ?location .\n"
+				+ "    ?art base:hasTag ?tag .\n"
+				+ "    ?art tr:relatesTo ?pmArt .\n"
+				+ "}";
+		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
+		while (rs.hasNext()) {
+			QuerySolution next = rs.next();
+			RDFNode art = next.get("?art");
+			RDFNode guid = next.get("?guid");
+			RDFNode ts = next.get("?ts");
+			RDFNode location = next.get("?location");
+			RDFNode tag = next.get("?tag");
+			RDFNode pmArt = next.get("?pmArt");
+			TraceArtifact tArt = new TraceArtifact();
+			tArt.setIri(art.toString());
+			tArt.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(ts.toString()));
+			tArt.setRelatesTo((Artifact)pm.getNode(pmArt.toString()));	
+			tArt.setGUID(guid.toString());
+			tArt.setLocation(location.toString());
+			tArt.setTag(tag.toString());
+			
+			arts.add(tArt);
+		}
+		return arts;				
+	}
+
+	private Pair<String, String> getEndActivityEvent(String iri, PM pm, List<Event> list) throws Exception {
+		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
+				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "SELECT ?trace ?port ?act ?ts ?next ?nexttype WHERE {\n"
+				+ "	?trace owl:sameAs <" + iri + "> ;\n"
+				+ "     tr:relatesTo ?port ;\n"
+				+ "	 	tr:hasTimestamp ?ts .\n"
+				+ " ?act pm:hasPort ?port .\n"
+				+ "   OPTIONAL {\n"
+				+ "    ?trace tr:isFollowedBy ?next .\n"
+				+ "	?next a ?nexttype .\n"
+				+ "    FILTER (?nexttype IN (tr:StartActivityEvent, tr:EndActivityEvent, tr:EndTraceEvent)) . \n"
+				+ "  }\n"
+				+ "}";
+		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
+		if (rs.hasNext()) {
+			QuerySolution sol = rs.next();
+			RDFNode trace = sol.get("?trace");
+			RDFNode port = sol.get("?port");
+			RDFNode act = sol.get("?act");
+			
+			Activity activity = (Activity)pm.getNode(act.toString());
+			List<ControlOutputPort> ctrlOutPorts = activity.getCtrlOutPorts();
+			ControlOutputPort ctrlPort = null;
+			for (ControlOutputPort ctrl : ctrlOutPorts) {
+				if (ctrl.getIri().equals(port.toString())) {
+					ctrlPort = ctrl;
+					break;
+				}
+			}
+			RDFNode ts = sol.get("?ts");
+
+			EndActivityEvent ev = new EndActivityEvent();
+			ev.setIri(trace.toString());
+			ev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(ts.toString()));
+			ev.setRelatesTo(ctrlPort);
+			
+			ev.setProducedArtifacts(getArtifacts(ev,pm));
+						
+			list.add(ev);
+			
+			RDFNode next = sol.get("?next");
+			if (next == null) {
+				return null;
+			} else {
+				return new Pair<String, String>(next.toString(),sol.get("?nexttype").toString());
+			}
+			
+		} else {
+			throw new Exception("No data returned by query: \n" + query );
+		}
+	}
+
+	public List<StartTraceEvent> getActiveTraces(String pm) {
+		List<StartTraceEvent> list = new ArrayList<StartTraceEvent>();
+		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "SELECT ?trace ?ts ?next WHERE {\n"
+				+ "  ?trace tr:hasTimestamp ?ts .\n"
+				+ "  ?trace tr:relatesTo <" + pm + "> .\n"
+				+ "  {  \n"
+				+ "    ?trace a tr:StartTraceEvent .\n"
+				+ "	?trace tr:isFollowedBy+ ?next .\n"
+				+ "    ?next a ?nexttype .\n"
+				+ "	FILTER (?trace != ?next)\n"
+				+ "	FILTER NOT EXISTS {?next tr:isFollowedBy ?other  } .\n"
+				+ "    FILTER (?nexttype IN (tr:StartActivityEvent, tr:EndActivityEvent)) .\n"
+				+ "  }\n"
+				+ "  UNION \n"
+				+ "  {\n"
+				+ "    ?trace a tr:StartTraceEvent .\n"
+				+ "    FILTER NOT EXISTS {?trace tr:isFollowedBy ?next} .\n"
+				+ "  }\n"
+				+ "}";
+		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
+		while (rs.hasNext()) {
+			QuerySolution next = rs.next();
+			RDFNode trace = next.get("?trace");
+			RDFNode ts = next.get("?ts");
+			StartTraceEvent ev = new StartTraceEvent();
+			ev.setIri(trace.toString());
+			ev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(ts.toString()));
+			PM pmo = new PM();
+			pmo.setIri(pm);
+			ev.setPmEnacted(pmo);
+			list.add(ev);
+		}
+		return list;		
+	}
+
+	public List<StartTraceEvent> getConcludedTraces(String pmiri) {
+		List<StartTraceEvent> list = new ArrayList<StartTraceEvent>();
+		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "SELECT ?trace ?ts ?next WHERE {\n"
+				+ "  ?trace a tr:StartTraceEvent .\n"
+				+ "  ?trace tr:hasTimestamp ?ts .\n"
+				+ "  ?trace tr:relatesTo <" + pmiri + "> .\n"
+				+ "  ?trace tr:isFollowedBy+ ?next .\n"
+				+ "  ?next a ?nexttype .\n"
+				+ "  FILTER (?trace != ?next)\n"
+				+ "  FILTER NOT EXISTS {?next tr:isFollowedBy ?other  } .\n"
+				+ "  FILTER (?nexttype IN (tr:EndTraceEvent)) .\n"
+				+ "}";
+		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
+		while (rs.hasNext()) {
+			QuerySolution next = rs.next();
+			RDFNode trace = next.get("?trace");
+			RDFNode ts = next.get("?ts");
+			StartTraceEvent ev = new StartTraceEvent();
+			ev.setIri(trace.toString());
+			ev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(ts.toString()));
+			PM pmo = new PM();
+			pmo.setIri(pmiri);
+			ev.setPmEnacted(pmo);
+			list.add(ev);
+		}
+		return list;		
+	}
+
+	
+
 }

+ 2 - 2
src/main/resources/templates/enact.html

@@ -56,11 +56,11 @@
 
       <div class="details">
         <p th:inline="text"><strong>Trace: </strong><span class="accent">[[${session.trace.name}]]</span></p>
-        <p th:inline="text"><strong>Started at: </strong><span class="accent">[[${session.trace.timestampF}]]</span></p>
+        <p th:inline="text"><strong>Started at: </strong><span class="accent">[[${session.trace.events[0].timestampF}]]</span></p>
         <th:block th:each="ev : ${session.trace.events}">
           <p th:if="${ev.class.name == 'ua.be.wee.model.pt.StartActivityEvent'}"><strong>Begin: </strong><span class="accent" th:text="${ev.relatesTo.activity.name}"></span></p>
           <p th:if="${ev.class.name == 'ua.be.wee.model.pt.EndActivityEvent'}"><strong>End: </strong><span class="accent" th:text="${ev.relatesTo.activity.name}"></span></p>
-          <p><strong>Port: </strong><span class="accent">[[${ev.relatesTo.name}]]</span></p>
+          <p th:if="${ev.class.name == 'ua.be.wee.model.pt.EndActivityEvent' || ev.class.name == 'ua.be.wee.model.pt.StartActivityEvent'}"><strong>Port: </strong><span class="accent">[[${ev.relatesTo.name}]]</span></p>
         </th:block>
       </div>
 

+ 2 - 2
src/main/resources/templates/enactEnd.html

@@ -60,11 +60,11 @@
 
       <div class="details">
         <p th:inline="text"><strong>Trace: </strong><span class="accent">[[${session.trace.name}]]</span></p>
-        <p th:inline="text"><strong>Started at: </strong><span class="accent">[[${session.trace.timestampF}]]</span></p>
+        <p th:inline="text"><strong>Started at: </strong><span class="accent">[[${session.trace.events[0].timestampF}]]</span></p>
         <th:block th:each="ev : ${session.trace.events}">
           <p th:if="${ev.class.name == 'ua.be.wee.model.pt.StartActivityEvent'}"><strong>Begin: </strong><span class="accent" th:text="${ev.relatesTo.activity.name}"></span></p>
           <p th:if="${ev.class.name == 'ua.be.wee.model.pt.EndActivityEvent'}"><strong>End: </strong><span class="accent" th:text="${ev.relatesTo.activity.name}"></span></p>
-          <p><strong>Port: </strong><span class="accent">[[${ev.relatesTo.name}]]</span></p>
+          <p th:if="${ev.class.name == 'ua.be.wee.model.pt.EndActivityEvent' || ev.class.name == 'ua.be.wee.model.pt.StartActivityEvent'}"><strong>Port: </strong><span class="accent">[[${ev.relatesTo.name}]]</span></p>
         </th:block>
       </div>
     </div>

+ 3 - 3
src/main/resources/templates/endEnactment.html

@@ -10,14 +10,14 @@
     <p th:inline="text">Enactment of the Process Model: [[${session.pm.name}]] has ended!</p>
     <a th:href="@{/}">HOME</a>
     <p th:inline="text">Trace: [[${session.trace.name}]]</p>
-    <p th:inline="text">Started at: [[${session.trace.timestampF}]]</p>
+    <p th:inline="text">Started at: [[${session.trace.events[0].timestampF}]]</p>
     <th:block th:each="ev : ${session.trace.events}">
       <p th:if="${ev.class.name == 'ua.be.wee.model.pt.StartActivityEvent'}">Begin:</p>
       <p th:if="${ev.class.name == 'ua.be.wee.model.pt.EndActivityEvent'}">End:</p>
-      <p th:if="${ev.class.name != 'ua.be.wee.model.pt.EndTraceEvent'}" th:text="${ev.relatesTo.activity.name}"></p>
+      <p th:if="${ev.class.name == 'ua.be.wee.model.pt.EndActivityEvent' || ev.class.name == 'ua.be.wee.model.pt.StartActivityEvent'}" th:text="${ev.relatesTo.activity.name}"></p>
       <p th:if="${ev.class.name == 'ua.be.wee.model.pt.EndTraceEvent'}">End of Trace at:</p>
       <p th:if="${ev.class.name == 'ua.be.wee.model.pt.EndTraceEvent'}" th:text="${ev.timestampF}"></p>
-      <p th:if="${ev.class.name != 'ua.be.wee.model.pt.EndTraceEvent'}">port: [[${ev.relatesTo.name}]]</p>
+      <p th:if="${ev.class.name == 'ua.be.wee.model.pt.EndActivityEvent' || ev.class.name == 'ua.be.wee.model.pt.StartActivityEvent'}">port: [[${ev.relatesTo.name}]]</p>
     </th:block>
   </section>
 </main>