Browse Source

Merge branch 'release-0.0.1'

Arkadiusz Ryś 2 years ago
parent
commit
f054c86a3b
55 changed files with 6115 additions and 806 deletions
  1. 6 0
      .dockerignore
  2. 1 0
      .gitignore
  3. 47 0
      .gitlab-ci.yml
  4. 130 0
      flake.lock
  5. 55 0
      flake.nix
  6. 3844 0
      mvn2nix-lock.json
  7. 1 1
      pom.xml
  8. 5 0
      src/main/java/ua/be/wee/WeeApplication.java
  9. 155 48
      src/main/java/ua/be/wee/controller/EnactmentControllerMVC.java
  10. 1 1
      src/main/java/ua/be/wee/controller/PMTrigger.java
  11. 47 0
      src/main/java/ua/be/wee/controller/rest/NodeController.java
  12. 61 0
      src/main/java/ua/be/wee/controller/rest/PMController.java
  13. 58 0
      src/main/java/ua/be/wee/controller/rest/PTController.java
  14. 9 9
      src/main/java/ua/be/wee/model/EnactmentController.java
  15. 17 0
      src/main/java/ua/be/wee/model/nodes/Activity.java
  16. 3 0
      src/main/java/ua/be/wee/model/nodes/Artifact.java
  17. 11 3
      src/main/java/ua/be/wee/model/nodes/FinalNode.java
  18. 8 0
      src/main/java/ua/be/wee/model/nodes/ForkNode.java
  19. 6 0
      src/main/java/ua/be/wee/model/nodes/InitialNode.java
  20. 8 0
      src/main/java/ua/be/wee/model/nodes/JoinNode.java
  21. 16 0
      src/main/java/ua/be/wee/model/nodes/Node.java
  22. 0 260
      src/main/java/ua/be/wee/model/nodes/NodeRespository.java
  23. 9 0
      src/main/java/ua/be/wee/model/nodes/ports/ControlInputPort.java
  24. 9 0
      src/main/java/ua/be/wee/model/nodes/ports/ControlOutputPort.java
  25. 9 0
      src/main/java/ua/be/wee/model/nodes/ports/DataInputPort.java
  26. 10 0
      src/main/java/ua/be/wee/model/nodes/ports/DataOutputPort.java
  27. 16 0
      src/main/java/ua/be/wee/model/nodes/ports/Port.java
  28. 15 10
      src/main/java/ua/be/wee/model/pm/PM.java
  29. 11 0
      src/main/java/ua/be/wee/model/pt/EndActivityEvent.java
  30. 12 12
      src/main/java/ua/be/wee/model/pt/EndTraceEvent.java
  31. 41 1
      src/main/java/ua/be/wee/model/pt/Event.java
  32. 13 17
      src/main/java/ua/be/wee/model/pt/PT.java
  33. 0 325
      src/main/java/ua/be/wee/model/pt/PTRepository.java
  34. 12 1
      src/main/java/ua/be/wee/model/pt/StartActivityEvent.java
  35. 25 0
      src/main/java/ua/be/wee/model/pt/StartTraceEvent.java
  36. 23 0
      src/main/java/ua/be/wee/model/pt/TraceArtifact.java
  37. 6 72
      src/main/java/ua/be/wee/model/repository/FusekiWrapper.java
  38. 442 0
      src/main/java/ua/be/wee/model/repository/NodeRespository.java
  39. 4 4
      src/main/java/ua/be/wee/model/pm/PMRepository.java
  40. 819 0
      src/main/java/ua/be/wee/model/repository/PTRepository.java
  41. 22 0
      src/main/java/ua/be/wee/model/util/DateTimeConverter.java
  42. 1 1
      src/main/resources/application.properties
  43. BIN
      src/main/resources/static/audio/Wee.mp3
  44. BIN
      src/main/resources/static/img/home-button.png
  45. BIN
      src/main/resources/static/img/home.png
  46. BIN
      src/main/resources/static/img/slip-and-fall.png
  47. 17 0
      src/main/resources/static/main.js
  48. 1 1
      src/main/resources/templates/base.html
  49. 8 7
      src/main/resources/templates/enact.html
  50. 4 4
      src/main/resources/templates/enactEnd.html
  51. 15 24
      src/main/resources/templates/endEnactment.html
  52. 13 0
      src/main/resources/templates/error.html
  53. 2 1
      src/main/resources/templates/index.html
  54. 19 4
      src/main/resources/templates/pms.html
  55. 48 0
      tasks.py

+ 6 - 0
.dockerignore

@@ -1,2 +1,8 @@
+.git
+.idea
 target
 HELP.md
+.gitlab-ci.yml
+flake.lock
+flake.nix
+mvn2nix-lock.json

+ 1 - 0
.gitignore

@@ -81,3 +81,4 @@ Temporary Items
 .apdisk
 
 /target/
+.idea

+ 47 - 0
.gitlab-ci.yml

@@ -0,0 +1,47 @@
+image: docker:23.0.5
+
+variables:
+  DOCKER_DRIVER: overlay2
+  DOCKER_TLS_CERTDIR: "/certs"
+  DOCKER_HOST: tcp://docker:2376
+  DOCKER_SHA: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
+  DOCKER_BRANCH: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
+  DOCKER_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
+  DOCKER_LATEST: $CI_REGISTRY_IMAGE:latest
+
+services:
+  - docker:23.0.5-dind
+
+stages:
+  - build
+  - release
+
+before_script:
+  - docker info
+  - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+
+build_docker:
+  stage: build
+  script:
+    - docker pull $DOCKER_BRANCH || true
+    - docker build --cache-from $DOCKER_BRANCH -f ./Dockerfile --tag $DOCKER_BRANCH .
+    - docker push $DOCKER_BRANCH
+  rules:
+    - if: $CI_COMMIT_TAG || $CI_COMMIT_BRANCH == "main"
+    - if: $CI_PIPELINE_SOURCE == "push" || $CI_COMMIT_BRANCH == "dev"
+      when: manual
+      allow_failure: true
+
+build_tagged_docker:
+  stage: release
+  script:
+    - docker pull $DOCKER_BRANCH || true
+    - docker tag $DOCKER_BRANCH $DOCKER_LATEST
+    - docker push $DOCKER_LATEST
+    - docker tag $DOCKER_BRANCH $DOCKER_TAG
+    - docker push $DOCKER_TAG
+  rules:
+    - if: $CI_COMMIT_TAG
+    - if: $CI_PIPELINE_SOURCE == "push" || $CI_COMMIT_BRANCH == "dev"
+      when: manual
+      allow_failure: true

+ 130 - 0
flake.lock

@@ -0,0 +1,130 @@
+{
+  "nodes": {
+    "flake-utils": {
+      "inputs": {
+        "systems": "systems"
+      },
+      "locked": {
+        "lastModified": 1681202837,
+        "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "cfacdce06f30d2b68473a46042957675eebb3401",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "mvn2nix": {
+      "inputs": {
+        "nixpkgs": "nixpkgs",
+        "utils": "utils"
+      },
+      "locked": {
+        "lastModified": 1629170129,
+        "narHash": "sha256-v/HvYqzkPaGin1ujo+Fi59wXC9vWxW3lYVSwElORRi8=",
+        "owner": "fzakaria",
+        "repo": "mvn2nix",
+        "rev": "ea21cfe97069feee55fa307ca9b125616c1fa84f",
+        "type": "github"
+      },
+      "original": {
+        "owner": "fzakaria",
+        "repo": "mvn2nix",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1683014792,
+        "narHash": "sha256-6Va9iVtmmsw4raBc3QKvQT2KT/NGRWlvUlJj46zN8B8=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "1a411f23ba299db155a5b45d5e145b85a7aafc42",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-21.05",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_2": {
+      "locked": {
+        "lastModified": 1683014792,
+        "narHash": "sha256-6Va9iVtmmsw4raBc3QKvQT2KT/NGRWlvUlJj46zN8B8=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "1a411f23ba299db155a5b45d5e145b85a7aafc42",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-utils": "flake-utils",
+        "mvn2nix": "mvn2nix",
+        "nixpkgs": "nixpkgs_2"
+      }
+    },
+    "systems": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "systems_2": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "utils": {
+      "inputs": {
+        "systems": "systems_2"
+      },
+      "locked": {
+        "lastModified": 1681202837,
+        "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "cfacdce06f30d2b68473a46042957675eebb3401",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}

+ 55 - 0
flake.nix

@@ -0,0 +1,55 @@
+{
+  inputs = rec {
+    nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
+    flake-utils.url = "github:numtide/flake-utils";
+    mvn2nix.url = "github:fzakaria/mvn2nix";
+    mvn2nix.inputs = { inherit nixpkgs; utils = flake-utils; };
+  };
+
+  outputs = { nixpkgs, mvn2nix, flake-utils, ... }:
+    flake-utils.lib.eachDefaultSystem (system:
+      let
+        pkgs = (import nixpkgs {
+          overlays = [ mvn2nix.overlay ];
+          inherit system;
+        });
+
+        mavenRepository = pkgs.buildMavenRepositoryFromLockFile {
+          file = ./mvn2nix-lock.json;
+        };
+      in rec {
+        packages = rec {
+          wee = pkgs.stdenv.mkDerivation rec {
+            pname = "wee";
+            version = "0.0.1-SNAPSHOT";
+            name = "${pname}-${version}";
+            src = pkgs.nix-gitignore.gitignoreSource [ "*.nix" ] ./.;
+            nativeBuildInputs = [
+              pkgs.makeWrapper
+            ];
+            buildPhase = ''
+              echo "Building with maven repository ${mavenRepository}"
+              ${pkgs.maven}/bin/mvn package --offline -Dmaven.repo.local=${mavenRepository}
+            '';
+            installPhase = ''
+              # create the bin directory
+              mkdir -p $out/bin
+
+              # create a symbolic link for the lib directory
+              ln -s ${mavenRepository} $out/lib
+
+              # copy out the JAR
+              # Maven already setup the classpath to use m2 repository layout
+              # with the prefix of lib/
+              cp target/${name}.jar $out/
+
+              # create a wrapper that will automatically set the classpath
+              # this should be the paths from the dependency derivation
+              makeWrapper ${pkgs.jdk11_headless}/bin/java $out/bin/${pname} \
+                    --add-flags "-jar $out/${name}.jar"
+            '';
+          };
+        };
+        defaultPackage = packages.wee;
+      });
+}

File diff suppressed because it is too large
+ 3844 - 0
mvn2nix-lock.json


+ 1 - 1
pom.xml

@@ -10,7 +10,7 @@
 	</parent>
 	<groupId>ua.be</groupId>
 	<artifactId>wee</artifactId>
-	<version>0.0.1-SNAPSHOT</version>
+	<version>0.0.1</version>
 	<name>wee</name>
 	<description>Workflow Enactment Engine</description>
 	<properties>

+ 5 - 0
src/main/java/ua/be/wee/WeeApplication.java

@@ -6,8 +6,13 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
 @SpringBootApplication
 public class WeeApplication {
 
+	
 	public static void main(String[] args) {
+		System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
+
+		
 		SpringApplication.run(WeeApplication.class, args);
+		
 	}
 
 }

+ 155 - 48
src/main/java/ua/be/wee/controller/EnactmentControllerMVC.java

@@ -4,7 +4,6 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.sql.Timestamp;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
@@ -18,10 +17,11 @@ import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.ModelAttribute;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 
+import ua.be.wee.controller.rest.PTController;
 import ua.be.wee.model.EnactmentController;
-import ua.be.wee.model.NamedElement;
 import ua.be.wee.model.nodes.Activity;
 import ua.be.wee.model.nodes.Artifact;
 import ua.be.wee.model.nodes.FinalNode;
@@ -32,6 +32,8 @@ import ua.be.wee.model.pm.PM;
 import ua.be.wee.model.pt.EndActivityEvent;
 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.repository.FusekiWrapper;
 import ua.be.wee.model.util.Pair;
@@ -42,6 +44,9 @@ import ua.be.wee.service.FileStorageService;
 public class EnactmentControllerMVC {
 
 	@Autowired private EnactmentController controller;
+	
+	@Autowired
+	private PTController ptController;
   
 	@Autowired
 	private Environment env;
@@ -74,19 +79,37 @@ public class EnactmentControllerMVC {
     	if (FusekiWrapper.getInstance().testEndpoint()) {
     		model.addAttribute("error",false);
     		model.addAttribute("pms", controller.getAllPMs());
+    		model.addAttribute("traces",null);
+    		model.addAttribute("current", "1");
             return "pms";
 		} else {
 			model.addAttribute("error",true);
 			return "index";
 		}
-    	
     }
-
-    @PostMapping("/enactpm")
+    
+    @RequestMapping("/gettraces")
+    public String getTraces(Model model, @RequestParam String iri, HttpServletRequest request) throws Exception {
+    	List<StartTraceEvent> activeTraces = ptController.getActiveTraces(iri);
+    	if (activeTraces != null && activeTraces.size() > 0) {
+			model.addAttribute("traces",activeTraces);
+		} else {
+			model.addAttribute("traces",null);
+		}
+    	model.addAttribute("error",false);
+		model.addAttribute("pms", controller.getAllPMs());
+		model.addAttribute("current", iri);
+        return "pms";
+    }
+    
+    
+    @RequestMapping(value="/enactpm", method=RequestMethod.POST, params="action=new")
     public String getPMtoEnact(Model model, @RequestParam String pmiri, HttpServletRequest request) throws Exception {
-    	if (pmiri.equals("select PM")) {
+    	if ((pmiri.equals("select PM"))) {
 			model.addAttribute("error", true);
 			model.addAttribute("pms", controller.getAllPMs());
+			model.addAttribute("traces",null);
+    		model.addAttribute("current", "1");
 			return "pms";
 		} else {
 			PM pm = controller.getPM(pmiri);			
@@ -96,7 +119,6 @@ public class EnactmentControllerMVC {
 			model.addAttribute("error", false);
 			request.getSession().setAttribute("pm", pm);
 			request.getSession().setAttribute("trace", trace);
-			request.getSession().setAttribute("previous", pm.getInitial().getIri());
 			request.getSession().setAttribute("acts",acts);
 			request.getSession().setAttribute("endacts",new ArrayList<Node>());
 			model.addAttribute("arts", null);
@@ -104,48 +126,90 @@ public class EnactmentControllerMVC {
 	        return "enact";
 		}
     }
+    
+    @RequestMapping(value="/enactpm", method=RequestMethod.POST, params="action=continue")
+    public String continueEnact(Model model, @RequestParam String pmiri, @RequestParam String contTrace, HttpServletRequest request) throws Exception {
+    	if ((pmiri.equals("select PM")) || contTrace != null && contTrace.equals("Select Trace")) {
+			model.addAttribute("error", true);
+			model.addAttribute("pms", controller.getAllPMs());
+			model.addAttribute("traces",null);
+    		model.addAttribute("current", "1");
+			return "pms";
+		} else {
+			PM pm = controller.getPM(pmiri);			
+			List<Event> events = ptController.getEvents(contTrace);
+			PT trace = new PT();
+			trace.setEvents(events);
+			trace.setIri(contTrace);
+			trace.setPmEnacted(pm);
+			List <Node> endActs = new ArrayList<Node>();
+			if (events.size() == 1) {
+				List<Pair<String,String>> iris = controller.findNextNodes(pm.getInitial().getIri());
+				List<PMTrigger> acts = findElements(pm, iris);
+				request.getSession().setAttribute("acts",acts);
+				
+			} else {
+				endActs = findEndActs(events);
+				List<PMTrigger> acts = new ArrayList<PMTrigger>();
+				if (events.get(events.size()-1) instanceof EndActivityEvent) {
+					EndActivityEvent last = (EndActivityEvent)events.get(events.size()-1);
+					List<Pair<String,String>> iris = controller.findNextNodes(last.getRelatesTo().getIri());
+					acts = findElements(pm, iris);
+				}
+				
+				request.getSession().setAttribute("acts",acts);
+				
+			}			
+			model.addAttribute("error", false);
+			request.getSession().setAttribute("pm", pm);
+			request.getSession().setAttribute("trace", trace);
+			request.getSession().setAttribute("endacts",endActs);
+			model.addAttribute("arts", null);
+			model.addAttribute("current", "1");
+	        return "enact";
+		}
+    }
+    
 
-	private List<PMTrigger> findElements(PM pm, List<Pair<String, String>> iris) {
-		List<PMTrigger> acts = new ArrayList<PMTrigger>();
-		for (Pair<String,String> pair : iris) {
-			PMTrigger tr = new PMTrigger();
-			if (pair.getSnd() != null) {
-				List<ControlInputPort> ctrlInPorts = ((Activity)pm.getNode(pair.getSnd())).getCtrlInPorts();
-				ControlInputPort port = null;
-				for (ControlInputPort ctr : ctrlInPorts) {
-					if (ctr.getIri().equals(pair.getFst())) {
-						port = ctr;
+	private List<Node> findEndActs(List<Event> events) {
+		List<Node> result = new ArrayList<Node>();
+		for (Event event : events) {
+			String name = event.getIri().split("#")[1];
+			if (name.startsWith("start_activity")) {
+				String index = name.split("start_activity")[1];
+				boolean found = false;
+				for (Event event2 : events) {
+					String end = event2.getIri().split("#")[1];
+					if (end.equals("end_activity" + index)) {
+						found = true;
 						break;
 					}
 				}
-				tr.setPort(port);
-
-			} else {
-				tr.setNode((FinalNode)pm.getNode(pair.getFst()));
+				if (!found) {
+					result.add(((StartActivityEvent)event).getRelatesTo().getActivity());
+				}
 			}
-			acts.add(tr);
 		}
-		return acts;
+		return result;
 	}
 
-    @PostMapping("/startAct")
-    public String startActivity(Model model, @RequestParam String activity, HttpServletRequest request) throws Exception {
+	@PostMapping("/startAct")
+    public String startActivity(Model model, @RequestParam String iri, HttpServletRequest request) throws Exception {
     	PM pm = (PM)request.getSession().getAttribute("pm");
     	PT pt = (PT)request.getSession().getAttribute("trace");
     	List<PMTrigger> acts = (List<PMTrigger>) request.getSession().getAttribute("acts");
     	List<Node> endacts = (List<Node>) request.getSession().getAttribute("endacts");
-    	Node node = pm.getNode(activity);
+    	PMTrigger element = findPMTrigger(acts,iri);
     	Object arts = request.getSession().getAttribute("arts");
-    	if (node instanceof Activity) {
-
-        	controller.addStartEvent(pt,(Activity)node,((List<TraceArtifact>)arts));
-        	removeElement(acts,node);
-        	endacts.add(node);
+    	if (element.getPort() != null) {
+    		ControlInputPort port = (ControlInputPort)element.getPort();
+        	controller.addStartEvent(pt,port, port.getActivity(),((List<TraceArtifact>)arts));
+        	removeElement(acts,iri);
+        	endacts.add(port.getActivity());
         	request.getSession().removeAttribute("arts");
         	return "enact";
-		} else if (node instanceof FinalNode) {
-			String previous = (String)request.getSession().getAttribute("previous");
-			Event endTraceEvent = controller.addEndTraceEvent(pt.getIri(), previous, pm.getIri());
+		} else if (element.getNode() != null) {
+			Event endTraceEvent = controller.addEndTraceEvent(pt.getIri(), pt.getLastEvent().getIri(), pm.getIri());
 			pt.addEvent(endTraceEvent);
 			controller.updatePT(pt);
 			return "endEnactment";
@@ -156,15 +220,7 @@ public class EnactmentControllerMVC {
     	
     }
     
-    private void removeElement(List<PMTrigger> acts, Node node) {
-		for (PMTrigger pmTrigger : acts) {
-			if (pmTrigger.getIri().equals(node.getIri())) {
-				acts.remove(pmTrigger);
-				break;
-			}
-		}
-
-	}
+    
 
     @PostMapping("/endAct")
     public String endActivityWithArtifacts(Model model, @RequestParam String port, @RequestParam String activity, HttpServletRequest request) throws Exception {
@@ -190,8 +246,6 @@ public class EnactmentControllerMVC {
 				if (part.getName().equals(artifact.getName())) {
 					TraceArtifact tArt = new TraceArtifact();
 					tArt.setLocation(part.getSubmittedFileName());
-					//tArt.setTag("v1"); //TODO fix the tag generation
-					tArt.setGUID(part.getSubmittedFileName()+"-" +tArt.getTag());
 					tArt.setRelatesTo(artifact);
 					traceArts.add(tArt);
 					storageService.save(part);
@@ -200,7 +254,12 @@ public class EnactmentControllerMVC {
 		}
     	
     	controller.addEndEvent(pt,traceArts,p);
-    	endacts.remove(act);
+    	for (Node activ : endacts) {
+			if (activ.getIri().equals(act.getIri())) {
+				endacts.remove(activ);
+				break;
+			}
+		}	
 
     	List<Pair<String,String>> iris = controller.findNextNodes(p.getIri());
         acts.addAll(findElements(pm, iris));
@@ -235,9 +294,11 @@ public class EnactmentControllerMVC {
     public String selectActivity(Model model, @RequestParam String iri, HttpServletRequest request) throws Exception {
     	PM pm = (PM)request.getSession().getAttribute("pm");
     	PT pt = (PT)request.getSession().getAttribute("trace");
+    	List<PMTrigger> acts = (List<PMTrigger>) request.getSession().getAttribute("acts");
     	if (!iri.equals("1")) {
-        	if (pm.getNode(iri) instanceof Activity) {
-        		Activity act = (Activity)pm.getNode(iri);
+    		PMTrigger element = findPMTrigger(acts, iri);
+        	if (element.getPort() != null) {
+        		Activity act = (Activity)element.getPort().getActivity();
         		List<Artifact> inputs = act.getInputs();
         		List<TraceArtifact> arts = new ArrayList<TraceArtifact>();
         		for (Artifact artifact : inputs) {
@@ -270,6 +331,52 @@ public class EnactmentControllerMVC {
     	model.addAttribute("current", iri);
     	return "enact";
     }
+    
+
+    // Helper methods
+    
+    
+    private List<PMTrigger> findElements(PM pm, List<Pair<String, String>> iris) {
+		List<PMTrigger> acts = new ArrayList<PMTrigger>();
+		for (Pair<String,String> pair : iris) {
+			PMTrigger tr = new PMTrigger();
+			if (pair.getSnd() != null) {
+				List<ControlInputPort> ctrlInPorts = ((Activity)pm.getNode(pair.getSnd())).getCtrlInPorts();
+				ControlInputPort port = null;
+				for (ControlInputPort ctr : ctrlInPorts) {
+					if (ctr.getIri().equals(pair.getFst())) {
+						port = ctr;
+						break;
+					}
+				}
+				tr.setPort(port);
+
+			} else {
+				tr.setNode((FinalNode)pm.getNode(pair.getFst()));
+			}
+			acts.add(tr);
+		}
+		return acts;
+	}
+    
+    private PMTrigger findPMTrigger(List<PMTrigger> acts, String iri) {
+		for (PMTrigger pmTrigger : acts) {
+			if (pmTrigger.getIri().equals(iri)) {
+				return pmTrigger;
+			}
+		}
+		return null;
+	}
+
+	private void removeElement(List<PMTrigger> acts, String iri) {
+		for (PMTrigger pmTrigger : acts) {
+			if (pmTrigger.getIri().equals(iri)) {
+				acts.remove(pmTrigger);
+				break;
+			}
+		}
+
+	}
 
 	
 }

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

@@ -35,7 +35,7 @@ public class PMTrigger {
 	
 	public String getIri() {
 		if (port != null) {
-			return port.getActivity().getIri();
+			return port.getIri();
 		} else {
 			return node.getIri();
 		}

+ 47 - 0
src/main/java/ua/be/wee/controller/rest/NodeController.java

@@ -0,0 +1,47 @@
+package ua.be.wee.controller.rest;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.CrossOrigin;
+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.nodes.Node;
+import ua.be.wee.model.repository.FusekiWrapper;
+import ua.be.wee.model.repository.NodeRespository;
+
+@RestController
+public class NodeController {
+
+	@Autowired
+	private NodeRespository nodesRepo;
+	
+	@Autowired
+	public NodeController(@Value("${endpoint}")final String endpoint) throws Exception {
+		if (FusekiWrapper.getInstance().getServiceURI() == null) {
+			FusekiWrapper.getInstance().setServiceURI(endpoint);
+		}
+	} 
+	
+	@CrossOrigin
+	@GetMapping("/nodes/{pmIRI}")
+	public List<Node> all(@PathVariable String pmIRI) throws Exception {
+		return nodesRepo.getNodes(pmIRI);
+	}
+
+	@CrossOrigin
+	@GetMapping("/nodes/{pmIRI}/{nodeIRI}")
+	public Node getNode(@PathVariable String pmIRI, @PathVariable String nodeIRI) throws Exception {
+		List<Node> nodes = nodesRepo.getNodes(pmIRI);
+		for (Node node : nodes) {
+			if (node.getIri().equals(nodeIRI)) {
+				return node;
+			}
+		}
+		return null;
+	}
+	
+}

+ 61 - 0
src/main/java/ua/be/wee/controller/rest/PMController.java

@@ -0,0 +1,61 @@
+package ua.be.wee.controller.rest;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import ua.be.wee.model.pm.PM;
+import ua.be.wee.model.repository.FusekiWrapper;
+import ua.be.wee.model.repository.NodeRespository;
+import ua.be.wee.model.repository.PMRepository;
+
+@RestController
+public class PMController {
+
+	@Autowired
+	private PMRepository pmRepo;
+	
+	@Autowired
+	private NodeRespository nodesRepo;
+	
+	@Autowired
+	public PMController(@Value("${endpoint}")final String endpoint) throws Exception {
+		if (FusekiWrapper.getInstance().getServiceURI() == null) {
+			FusekiWrapper.getInstance().setServiceURI(endpoint);
+		}
+	} 
+
+	@CrossOrigin
+	@GetMapping("/pms")
+	public List<PM> all() throws Exception {
+		List<PM> allPMs = pmRepo.getAllPMs();
+		for (PM pm : allPMs) {
+			pm.setNodes(nodesRepo.getNodes(pm.getIri()));
+		}
+		return allPMs;
+	}
+	
+	@CrossOrigin
+	@GetMapping("/pmss/{id}")
+	public PM getPM(@PathVariable String id) throws Exception {
+		PM pm = pmRepo.getPM(id);
+		pm.setNodes(nodesRepo.getNodes(pm.getIri()));
+		return pm;
+	}
+	
+	@CrossOrigin
+	@PutMapping("/endpoint")
+	public boolean setEndpoint(@RequestBody String url) throws Exception {
+		FusekiWrapper.getInstance().setServiceURI(url);
+		return FusekiWrapper.getInstance().testEndpoint();
+	}
+		
+
+}

+ 58 - 0
src/main/java/ua/be/wee/controller/rest/PTController.java

@@ -0,0 +1,58 @@
+package ua.be.wee.controller.rest;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.CrossOrigin;
+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.Event;
+import ua.be.wee.model.pt.StartTraceEvent;
+import ua.be.wee.model.repository.FusekiWrapper;
+import ua.be.wee.model.repository.PTRepository;
+
+@RestController
+public class PTController {
+
+	@Autowired
+	private PTRepository ptRepository;
+	
+	
+	@Autowired
+	public PTController(@Value("${endpoint}")final String endpoint) throws Exception {
+		if (FusekiWrapper.getInstance().getServiceURI() == null) {
+			FusekiWrapper.getInstance().setServiceURI(endpoint);
+		}
+	} 
+			
+	@CrossOrigin
+	@GetMapping("/traces")
+	public List<StartTraceEvent> allPTs() throws Exception {
+		return ptRepository.getStartTraceEvents();
+	}
+	
+	@CrossOrigin
+	@GetMapping("/traces/events/{traceiri}")
+	public List<Event> getEvents(@PathVariable String traceiri) throws Exception {
+		return ptRepository.getEvents(traceiri);
+	}
+	
+	@CrossOrigin
+	@GetMapping("/traces/active/{pmiri}")
+	public List<StartTraceEvent> getActiveTraces(@PathVariable String pmiri) throws Exception {
+		return ptRepository.getActiveTraces(pmiri);
+	}
+	
+	@CrossOrigin
+	@GetMapping("/traces/finished/{pmiri}")
+	public List<StartTraceEvent> getConcludedTraces(@PathVariable String pmiri) throws Exception {
+		return ptRepository.getConcludedTraces(pmiri);
+	}
+	
+
+
+	
+}

+ 9 - 9
src/main/java/ua/be/wee/model/EnactmentController.java

@@ -7,14 +7,15 @@ import org.springframework.stereotype.Component;
 
 import ua.be.wee.model.nodes.Activity;
 import ua.be.wee.model.nodes.Artifact;
-import ua.be.wee.model.nodes.NodeRespository;
+import ua.be.wee.model.nodes.ports.ControlInputPort;
 import ua.be.wee.model.nodes.ports.ControlOutputPort;
 import ua.be.wee.model.pm.PM;
-import ua.be.wee.model.pm.PMRepository;
 import ua.be.wee.model.pt.Event;
 import ua.be.wee.model.pt.PT;
-import ua.be.wee.model.pt.PTRepository;
 import ua.be.wee.model.pt.TraceArtifact;
+import ua.be.wee.model.repository.NodeRespository;
+import ua.be.wee.model.repository.PMRepository;
+import ua.be.wee.model.repository.PTRepository;
 import ua.be.wee.model.util.Pair;
 
 @Component
@@ -33,9 +34,9 @@ public class EnactmentController {
 		return pmRepo.getAllPMs();
 	}
 
-	public PM getPM(String pmid) {
+	public PM getPM(String pmid) throws Exception {
 		PM pm = pmRepo.getPM(pmid);
-		pm.setNodes(nodeRepo.getNodes(pm));
+		pm.setNodes(nodeRepo.getNodes(pm.getIri()));
 		return pm;
 	}
 
@@ -47,13 +48,12 @@ public class EnactmentController {
 		return traceRepo.createTrace(pm);
 	}
 
-	public void addStartEvent(PT pt, Activity act, List<TraceArtifact> arts) throws Exception {
-		traceRepo.createStartEvent(pt,act,arts);
+	public void addStartEvent(PT pt, ControlInputPort port, Activity act, List<TraceArtifact> arts) throws Exception {
+		traceRepo.createStartEvent(pt,port,act,arts);
 	}
 
 	public void addEndEvent(PT pt, List<TraceArtifact> arts, ControlOutputPort p) throws Exception {
-		traceRepo.createEndEvent(pt,arts,p);
-		
+		traceRepo.createEndEvent(pt,arts,p);	
 	}
 
 	public Event addEndTraceEvent(String iri, String previous, String pmIRI) throws Exception {

+ 17 - 0
src/main/java/ua/be/wee/model/nodes/Activity.java

@@ -3,23 +3,40 @@ package ua.be.wee.model.nodes;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.persistence.Entity;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToMany;
+
+import com.fasterxml.jackson.annotation.JsonBackReference;
+
 import ua.be.wee.model.nodes.ports.ControlInputPort;
 import ua.be.wee.model.nodes.ports.ControlOutputPort;
 import ua.be.wee.model.nodes.ports.DataInputPort;
 import ua.be.wee.model.nodes.ports.DataOutputPort;
 
+@Entity
 public class Activity extends Node {
 	
+	@ManyToMany
 	private List<Artifact> inputs;
 	
+	@ManyToMany
 	private List<Artifact> outputs;
 	
+	@OneToMany
+	@JsonBackReference
 	private List<ControlOutputPort> ctrlOutPorts;
 	
+	@OneToMany
+	@JsonBackReference
 	private List<ControlInputPort> ctrlInPorts;
 	
+	@OneToMany
+	@JsonBackReference
 	private List<DataOutputPort> dataOutPorts;
 	
+	@OneToMany
+	@JsonBackReference
 	private List<DataInputPort> datalInPorts;
 	
 	private String transformationName;

+ 3 - 0
src/main/java/ua/be/wee/model/nodes/Artifact.java

@@ -1,5 +1,8 @@
 package ua.be.wee.model.nodes;
 
+import javax.persistence.Entity;
+
+@Entity
 public class Artifact extends Node {
 	
 	private String type;

+ 11 - 3
src/main/java/ua/be/wee/model/nodes/FinalNode.java

@@ -1,14 +1,22 @@
 package ua.be.wee.model.nodes;
 
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.ManyToMany;
+
+@Entity
 public class FinalNode extends Node {
 	
-	private Node previous;
+	@ManyToMany(cascade = CascadeType.ALL)
+	private List<Node> previous;
 
-	public Node getPrevious() {
+	public List<Node> getPrevious() {
 		return previous;
 	}
 
-	public void setPrevious(Node previous) {
+	public void setPrevious(List<Node> previous) {
 		this.previous = previous;
 	}
 	

+ 8 - 0
src/main/java/ua/be/wee/model/nodes/ForkNode.java

@@ -2,10 +2,18 @@ package ua.be.wee.model.nodes;
 
 import java.util.List;
 
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+
+@Entity
 public class ForkNode extends Node {
 
+	@OneToOne(cascade = CascadeType.ALL)
 	private Node previous;
 	
+	@OneToMany
 	private List<Node> nextNodes;
 
 	public Node getPrevious() {

+ 6 - 0
src/main/java/ua/be/wee/model/nodes/InitialNode.java

@@ -1,7 +1,13 @@
 package ua.be.wee.model.nodes;
 
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.OneToOne;
+
+@Entity
 public class InitialNode extends Node {
 	
+	@OneToOne(cascade = CascadeType.ALL)
 	private Node next;
 
 	public Node getNext() {

+ 8 - 0
src/main/java/ua/be/wee/model/nodes/JoinNode.java

@@ -2,10 +2,18 @@ package ua.be.wee.model.nodes;
 
 import java.util.List;
 
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+
+@Entity
 public class JoinNode extends Node {
 	
+	@OneToMany
 	private List<Node> previousNodes;
 	
+	@OneToOne(cascade = CascadeType.ALL)
 	private Node next;
 
 	public List<Node> getPreviousNodes() {

+ 16 - 0
src/main/java/ua/be/wee/model/nodes/Node.java

@@ -3,8 +3,24 @@ package ua.be.wee.model.nodes;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
 import ua.be.wee.model.NamedElement;
 
+@JsonTypeInfo(
+		  use = JsonTypeInfo.Id.NAME, 
+		  include = JsonTypeInfo.As.PROPERTY, 
+		  property = "type")
+@JsonSubTypes({ 
+		  @Type(value = Activity.class), 
+		  @Type(value = Artifact.class),
+		  @Type(value = FinalNode.class),
+		  @Type(value = ForkNode.class),
+		  @Type(value = InitialNode.class),
+		  @Type(value = JoinNode.class)
+		})
 @Entity
 public abstract class Node implements NamedElement {
 

+ 0 - 260
src/main/java/ua/be/wee/model/nodes/NodeRespository.java

@@ -1,260 +0,0 @@
-package ua.be.wee.model.nodes;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.jena.query.QuerySolution;
-import org.apache.jena.query.ResultSet;
-import org.apache.jena.rdf.model.RDFNode;
-import org.springframework.stereotype.Component;
-
-import ua.be.wee.model.nodes.ports.ControlInputPort;
-import ua.be.wee.model.nodes.ports.ControlOutputPort;
-import ua.be.wee.model.nodes.ports.DataInputPort;
-import ua.be.wee.model.nodes.ports.DataOutputPort;
-import ua.be.wee.model.pm.PM;
-import ua.be.wee.model.repository.FusekiWrapper;
-
-@Component
-public class NodeRespository {
-	
-	
-	public List<Node> getNodes(PM pm) {
-		List<Node> nodes = new ArrayList<Node>();
-		
-		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
-				+ "PREFIX ob: <http://ua.be/sdo2l/vocabulary/formalisms/object_diagram#>\n"
-				+ "SELECT ?node ?nodetype WHERE {\n"
-				+ "  ?pm a pm:Model ;\n"
-				+ "  	ob:hasName ?pmName ;\n"
-				+ "  	owl:sameAs <" + pm.getIri() + "> ;\n"
-				+ "  	ob:hasObject ?node .\n"
-				+ "  ?node a ?nodetype .\n"
-				+ "  FILTER (?nodetype in (pm:Initial, pm:Activity, pm:Final, pm:Join, pm:Fork, pm:Artifact)) .      \n"
-				+ "}";
-		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-		while (results.hasNext()) {
-			QuerySolution soln = results.nextSolution();
-			
-			RDFNode iri = soln.get("?node");
-			RDFNode type = soln.get("?nodetype");
-			Node node = createNode(iri, type);
-			nodes.add(node);
-		}
-		pm.setNodes(nodes);
-		updateArtifactOfActivities(pm);
-		
-		return nodes;
-		
-	}
-
-	private void updateArtifactOfActivities(PM pm) {
-		for (Node node : pm.getNodes()) {
-			if (node instanceof Activity) {
-				Activity act = (Activity)node;
-				for (DataInputPort inport : act.getDatalInPorts()) {
-					String query = "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
-							+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-							+ "SELECT  ?inport ?art\n"
-							+ "WHERE { \n"
-							+ "  ?inport owl:sameAs <" +inport.getIri() + "> .\n"
-							+ "  ?inport pm:dataFrom ?art .\n"
-							+ "}";
-					ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-					QuerySolution soln = results.nextSolution();
-						
-					RDFNode art = soln.get("?art");
-					if (art != null && !art.toString().isEmpty()) {
-						Artifact artifact = (Artifact)pm.getNode(art.toString());
-						act.addInputArtifact(artifact);
-					}					
-				}
-				
-				for (DataOutputPort outport : act.getDataOutPorts()) {
-					String query = "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
-							+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-							+ "SELECT  ?outport ?art\n"
-							+ "WHERE { \n"
-							+ "  ?outport owl:sameAs <"+ outport.getIri() + "> .\n"
-							+ "  ?outport pm:dataTo ?art .\n"
-							+ "}";
-					ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-					QuerySolution soln = results.nextSolution();
-						
-					RDFNode art = soln.get("?art");
-					if (art != null && !art.toString().isEmpty()) {
-						Artifact artifact = (Artifact)pm.getNode(art.toString());
-						act.addOutputArtifact(artifact);
-					}					
-				}
-			}
-		}
-	}
-
-	private Node createNode(RDFNode iri, RDFNode type) {
-		Node node = null;
-		switch (type.toString()) {
-		case Node.ACTIVITY_IRI:
-			node = createActivity(iri.toString());
-			break;
-		case Node.INITIAL_IRI:
-			node = new InitialNode();
-			break;
-		case Node.FINAL_IRI:
-			node = new FinalNode();
-			break;
-		case Node.FORKJOIN_IRI:
-			//addlogic for fork join
-			node = new JoinNode();
-			break;
-		case Node.ARTIFACT_IRI:
-			//addlogic for fork join
-			node = createArtifact(iri.toString());
-			break;
-		}		
-		node.setIri(iri.toString());
-		return node;
-	}
-	
-	private Node createArtifact(String iri) {
-		Artifact art = new Artifact();
-		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
-				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/base#>\n"
-				+ "SELECT ?art ?name ?typename WHERE {\n"
-				+ "	?art owl:sameAs <" + iri + "> .\n"
-				+ " ?art	pm:hasName ?name .\n"
-				+ " ?art  	pm:hasType ?type .\n"
-				+ " ?type base:hasGUID ?typename .\n"
-				+ "}";
-		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-		QuerySolution soln = results.nextSolution();
-		RDFNode name = soln.get("?name");
-		RDFNode type = soln.get("?typename");
-		art.setIri(iri);
-		art.setName(name.toString());
-		art.setType(type.toString());
-		
-		return art;
-	}
-
-	private Node createActivity(String iri) {
-		Activity act = new Activity();
-		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
-				+ "SELECT ?act ?name WHERE {\n"
-				+ "	?act owl:sameAs <" + iri + ">;\n"
-				+ "   		pm:hasName ?name .  \n"
-				+ "}";
-		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-		QuerySolution soln = results.nextSolution();
-		RDFNode name = soln.get("?name");
-		act.setIri(iri);
-		act.setName(name.toString());
-		
-		act.setCtrlInPorts(getCtrlInPorts(act));
-		act.setCtrlOutPorts(getCtrlOutPorts(act));
-		act.setDatalInPorts(getDataInPorts(act));
-		act.setDataOutPorts(getDataOutPorts(act));
-		
-		return act;
-	}
-
-	private List<DataOutputPort> getDataOutPorts(Activity act) {
-		List<DataOutputPort> list = new ArrayList<DataOutputPort>();
-		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-			+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
-			+ "SELECT ?port ?pname WHERE {\n"
-			+ "	?act owl:sameAs <" + act.getIri() + ">;\n"
-			+ "   		pm:hasPort ?port .\n"
-			+ "  	?port a pm:DataOutputPort .\n"
-			+ "  	?port pm:hasName ?pname .\n"
-			+ "}";
-		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-		while (results.hasNext()) {
-			QuerySolution soln = results.nextSolution();
-			RDFNode iri = soln.get("?port");
-			RDFNode name = soln.get("?pname");
-			DataOutputPort cout = new DataOutputPort();
-			cout.setIri(iri.toString());
-			cout.setName(name.toString());
-			cout.setActivity(act);
-			list.add(cout);
-		}
-		return list;
-	}
-
-	private List<DataInputPort> getDataInPorts(Activity act) {
-		List<DataInputPort> list = new ArrayList<DataInputPort>();
-		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-			+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
-			+ "SELECT ?port ?pname WHERE {\n"
-			+ "	?act owl:sameAs <" + act.getIri() + ">;\n"
-			+ "   		pm:hasPort ?port .\n"
-			+ "  	?port a pm:DataInputPort .\n"
-			+ "  	?port pm:hasName ?pname .\n"
-			+ "}";
-		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-		while (results.hasNext()) {
-			QuerySolution soln = results.nextSolution();
-			RDFNode iri = soln.get("?port");
-			RDFNode name = soln.get("?pname");
-			DataInputPort cout = new DataInputPort();
-			cout.setIri(iri.toString());
-			cout.setName(name.toString());
-			cout.setActivity(act);
-			list.add(cout);
-		}
-		return list;
-	}
-
-	private List<ControlOutputPort> getCtrlOutPorts(Activity act) {
-		List<ControlOutputPort> list = new ArrayList<ControlOutputPort>();
-		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-			+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
-			+ "SELECT ?port ?pname WHERE {\n"
-			+ "	?act owl:sameAs <" + act.getIri() + ">;\n"
-			+ "   		pm:hasPort ?port .\n"
-			+ "  	?port a pm:CtrlOutputPort .\n"
-			+ "  	?port pm:hasName ?pname .\n"
-			+ "}";
-		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-		while (results.hasNext()) {
-			QuerySolution soln = results.nextSolution();
-			RDFNode iri = soln.get("?port");
-			RDFNode name = soln.get("?pname");
-			ControlOutputPort cout = new ControlOutputPort();
-			cout.setIri(iri.toString());
-			cout.setName(name.toString());
-			cout.setActivity(act);
-			list.add(cout);
-		}
-		return list;
-	}
-
-	private List<ControlInputPort> getCtrlInPorts(Activity act) {
-		List<ControlInputPort> list = new ArrayList<ControlInputPort>();
-		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-			+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
-			+ "SELECT ?port ?pname WHERE {\n"
-			+ "	?act owl:sameAs <" + act.getIri() + ">;\n"
-			+ "   		pm:hasPort ?port .\n"
-			+ "  	?port a pm:CtrlInputPort .\n"
-			+ "  	?port pm:hasName ?pname .\n"
-			+ "}";
-		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-		while (results.hasNext()) {
-			QuerySolution soln = results.nextSolution();
-			RDFNode iri = soln.get("?port");
-			RDFNode name = soln.get("?pname");
-			ControlInputPort cout = new ControlInputPort();
-			cout.setIri(iri.toString());
-			cout.setName(name.toString());
-			cout.setAct(act);
-			list.add(cout);
-		}
-		return list;
-	}
-
-}

+ 9 - 0
src/main/java/ua/be/wee/model/nodes/ports/ControlInputPort.java

@@ -1,9 +1,18 @@
 package ua.be.wee.model.nodes.ports;
 
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+
+import com.fasterxml.jackson.annotation.JsonManagedReference;
+
 import ua.be.wee.model.nodes.Activity;
 
+@Entity
 public class ControlInputPort extends Port {
 
+	@ManyToOne(cascade = CascadeType.ALL)
+	@JsonManagedReference
 	private Activity activity;
 
 	public Activity getActivity() {

+ 9 - 0
src/main/java/ua/be/wee/model/nodes/ports/ControlOutputPort.java

@@ -1,9 +1,18 @@
 package ua.be.wee.model.nodes.ports;
 
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+
+import com.fasterxml.jackson.annotation.JsonManagedReference;
+
 import ua.be.wee.model.nodes.Activity;
 
+@Entity
 public class ControlOutputPort extends Port {
 	
+	@ManyToOne(cascade = CascadeType.ALL)
+	@JsonManagedReference
 	private Activity activity;
 
 	public Activity getActivity() {

+ 9 - 0
src/main/java/ua/be/wee/model/nodes/ports/DataInputPort.java

@@ -1,9 +1,18 @@
 package ua.be.wee.model.nodes.ports;
 
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+
+import com.fasterxml.jackson.annotation.JsonManagedReference;
+
 import ua.be.wee.model.nodes.Activity;
 
+@Entity
 public class DataInputPort extends Port {
 	
+	@ManyToOne(cascade = CascadeType.ALL)
+	@JsonManagedReference
 	private Activity act;
 
 	public Activity getActivity() {

+ 10 - 0
src/main/java/ua/be/wee/model/nodes/ports/DataOutputPort.java

@@ -1,8 +1,18 @@
 package ua.be.wee.model.nodes.ports;
 
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+
+import com.fasterxml.jackson.annotation.JsonManagedReference;
+
 import ua.be.wee.model.nodes.Activity;
 
+@Entity
 public class DataOutputPort extends Port {
+	
+	@ManyToOne(cascade = CascadeType.ALL)
+	@JsonManagedReference
 	private Activity act;
 
 	public Activity getActivity() {

+ 16 - 0
src/main/java/ua/be/wee/model/nodes/ports/Port.java

@@ -1,9 +1,25 @@
 package ua.be.wee.model.nodes.ports;
 
+import javax.persistence.Entity;
 import javax.persistence.Id;
 
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
 import ua.be.wee.model.NamedElement;
 
+@JsonTypeInfo(
+		  use = JsonTypeInfo.Id.NAME, 
+		  include = JsonTypeInfo.As.PROPERTY, 
+		  property = "type")
+@JsonSubTypes({ 
+		  @Type(value = ControlInputPort.class), 
+		  @Type(value = ControlOutputPort.class),
+		  @Type(value = DataInputPort.class),
+		  @Type(value = DataOutputPort.class)
+		})
+@Entity
 public abstract class Port implements NamedElement {
 	
 	private String name;

+ 15 - 10
src/main/java/ua/be/wee/model/pm/PM.java

@@ -2,9 +2,9 @@ package ua.be.wee.model.pm;
 
 import java.util.List;
 
-import javax.persistence.ElementCollection;
 import javax.persistence.Entity;
 import javax.persistence.Id;
+import javax.persistence.OneToMany;
 
 import ua.be.wee.model.nodes.InitialNode;
 import ua.be.wee.model.nodes.Node;
@@ -17,7 +17,7 @@ public class PM {
 	
 	private String name;
 	
-	@ElementCollection
+	@OneToMany
 	private List<Node> nodes;
 
 	public String getName() {
@@ -49,19 +49,24 @@ public class PM {
 	}
 	
 	public InitialNode getInitial() {
-		for (Node node : nodes) {
-			if (node instanceof InitialNode) {
-				return (InitialNode) node;
+		if (nodes != null) {
+			for (Node node : nodes) {
+				if (node instanceof InitialNode) {
+					return (InitialNode) node;
+				}
 			}
-		}
+		} 
 		return null;
+		
 	}
 	
 	public Node getNode(String iri) {
-		for (Node node : nodes) {
-			if (node.getIri().equals(iri)) {
-				return node;
-			}
+		if (nodes != null) {
+			for (Node node : nodes) {
+				if (node.getIri().equals(iri)) {
+					return node;
+				}
+			}			
 		}
 		return null;
 	}

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

@@ -3,12 +3,19 @@ package ua.be.wee.model.pt;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+
 import ua.be.wee.model.nodes.ports.ControlOutputPort;
 
+@Entity
 public class EndActivityEvent extends Event {
 
+	@OneToOne
 	private ControlOutputPort relatesTo;
 	
+	@OneToMany
 	private List<TraceArtifact> producedArtifacts;
 	
 	public EndActivityEvent() {
@@ -31,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())) {

+ 12 - 12
src/main/java/ua/be/wee/model/pt/EndTraceEvent.java

@@ -1,22 +1,22 @@
 package ua.be.wee.model.pt;
 
-import java.sql.Timestamp;
-import java.text.SimpleDateFormat;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
 
+import ua.be.wee.model.pm.PM;
+
+@Entity
 public class EndTraceEvent extends Event {
 	
-	private Timestamp timestamp;
-	
-	public Timestamp getTimestamp() {
-		return timestamp;
+	@ManyToOne
+	private PM pmEnacted;
+
+	public PM getPmEnacted() {
+		return pmEnacted;
 	}
 
-	public void setTimestamp(Timestamp timestamp) {
-		this.timestamp = timestamp;
+	public void setPmEnacted(PM pmEnacted) {
+		this.pmEnacted = pmEnacted;
 	}
 	
-	public String getTimestampF() {
-		return new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(timestamp);
-	}
-
 }

+ 41 - 1
src/main/java/ua/be/wee/model/pt/Event.java

@@ -1,11 +1,36 @@
 package ua.be.wee.model.pt;
 
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+
+import javax.persistence.Entity;
 import javax.persistence.Id;
 
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+@JsonTypeInfo(
+		  use = JsonTypeInfo.Id.NAME, 
+		  include = JsonTypeInfo.As.PROPERTY, 
+		  property = "type")
+@JsonSubTypes({ 
+		  @Type(value = EndActivityEvent.class), 
+		  @Type(value = StartActivityEvent.class),
+		  @Type(value = EndTraceEvent.class)
+		})
+@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; 
+	private String iri;
+	
+	private Timestamp timestamp;
 	
 	public String getIri() {
 		return iri;
@@ -14,6 +39,21 @@ public abstract class Event {
 	public void setIri(String iri) {
 		this.iri = iri;
 	}
+
+	public Timestamp getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(Timestamp timestamp) {
+		this.timestamp = timestamp;
+	}
+	
+	public String getTimestampF() {
+		return new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(timestamp);
+	}
+
+	
+	
 	
 	
 

+ 13 - 17
src/main/java/ua/be/wee/model/pt/PT.java

@@ -1,25 +1,33 @@
 package ua.be.wee.model.pt;
 
 
-import java.sql.Timestamp;
-import java.text.SimpleDateFormat;
 import java.util.List;
 
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+
 import ua.be.wee.model.pm.PM;
 
+@Entity
 public class PT {
 	
-	private PM pmEnacted;
-	
-	private Timestamp timestamp;
+	public static String TRACE_GRAPH_IRI = "http://ua.be/sdo2l/description/traces";
 	
+	@Id
 	private String iri;
 	
 	private String name;
 	
+	@OneToMany
 	private List<Event> events;
 	
+	@OneToMany
 	private List<TraceArtifact> inputs;
+	
+	@OneToOne
+	private PM pmEnacted;
 
 	public PM getPmEnacted() {
 		return pmEnacted;
@@ -29,14 +37,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;
 	}
@@ -49,10 +49,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;

+ 0 - 325
src/main/java/ua/be/wee/model/pt/PTRepository.java

@@ -1,325 +0,0 @@
-package ua.be.wee.model.pt;
-
-import java.sql.Timestamp;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.jena.query.QuerySolution;
-import org.apache.jena.query.ResultSet;
-import org.apache.jena.rdf.model.RDFNode;
-import org.springframework.stereotype.Component;
-
-import ua.be.wee.model.nodes.Activity;
-import ua.be.wee.model.nodes.ports.ControlOutputPort;
-import ua.be.wee.model.pm.PM;
-import ua.be.wee.model.repository.FusekiWrapper;
-
-@Component
-public class PTRepository {
-
-	public PT createTrace(PM pm) throws Exception {
-		int index = getNextIndex(pm);
-		String traceiri = pm.getIri().split("#")[0] + "/traces#pt_" + index;
-		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"
-				+ "INSERT DATA {\n"
-				+ "	<"+ traceiri + "> 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"
-				+ "    	tr:relatesTo <" + pm.getIri() + "> ;\n"
-				+ "     owl:sameAs  <" + traceiri + "> .\n"
-				+ "}";
-		if (FusekiWrapper.getInstance().updateQuery(query) ) {
-			PT pt = new PT();
-			pt.setPmEnacted(pm);
-			pt.setTimestamp(Timestamp.from(Instant.now()));
-			pt.setIri(traceiri);
-			pt.setEvents(new ArrayList<Event>());
-			return pt;
-		} else {
-			throw new Exception("Error inserting data.");
-		}
-		
-	}
-	
-	private int getNextIndex(PM pm) {
-		int index = 0;
-		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
-				+ "SELECT ?pt  WHERE {\n"
-				+ "	?pt a tr:StartTraceEvent ;\n"
-				+ "  		tr:relatesTo <" + pm.getIri() + "> .\n"
-				+ "}";
-		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
-		while (results.hasNext()) {
-			results.next();
-			index++;
-		}
-		return index;
-	}
-
-	public void createStartEvent(PT pt, 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); 
-
-		String iri = pt.getIri().replace('#', '/') + "#" + "start_activity" + index;
-		String endiri = pt.getIri().replace('#', '/') + "#" + "end_activity" + index;
-		
-		String preiri = pt.getLastEvent() != null ? pt.getLastEvent().getIri() : pt.getIri();
-		String portiri = act.getCtrlInPorts().get(0).getIri(); //TODO:  change it later to consider multiple input ports
-		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"
-				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/acyclic#>\n"
-				+ "INSERT DATA {\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:isPrecededBy <" + preiri + "> ;\n"
-				+ "    tr:relatesTo <" + portiri + "> ;\n";
-		if (arts != null) {
-			for (TraceArtifact artifact : arts) {
-				query += "    tr:consumes <" + artifact.getIri() + "> ;\n";
-			}
-		}
-		query +=  "    owl:sameAs <" + iri + "> .\n"
-				+ "}";
-		StartActivityEvent ev = new StartActivityEvent();
-		if (FusekiWrapper.getInstance().updateQuery(query) ) {
-			ev.setIri(iri);
-			ev.setRelatesTo(act.getCtrlInPorts().get(0));
-			pt.addEvent(ev);
-		} else {
-			throw new Exception("Error inserting data.");
-		}
-		
-		if (arts != null) {
-			for (TraceArtifact traceArtifact : arts) {
-				query = "PREFIX pt: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
-						+ "INSERT DATA { \n"
-						+ " <" + traceArtifact.getIri() + "> " 
-						+ "        pt:isConsumedBy <" + iri + "> ;\n"
-						+ "}";
-				if (FusekiWrapper.getInstance().updateQuery(query) ) {
-					traceArtifact.setConsumedBy(ev);
-					ev.addTraceArtifact(traceArtifact);
-				} else {
-					throw new Exception("Error inserting data.");
-				}
-			}
-		}
-		updatePT(pt);
-		
-	}
-	
-	public void updatePT(PT pt) throws Exception {
-		String transitive = "";
-		for (Event ev : pt.getEvents()) {
-			transitive += "<" + ev.getIri()+">,";
-		}
-		transitive = transitive.substring(0, transitive.length()-1);
-		
-		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"
-				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/acyclic#>\n"
-				+ "DELETE { ?pt ?p ?v . }\n"
-				+ "WHERE { \n"
-				+ "  ?pt a tr:StartTraceEvent .\n"
-				+ "  ?pt owl:sameAs <" + pt.getIri() + "> .\n"
-				+ "  ?pt ?p ?v .\n"
-				+ "};\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:transitiveForward "+ transitive + " ;\n"
-				+ "    tr:isFollowedBy <" + pt.getEvents().get(0).getIri() + "> ;\n"
-				+ "    tr:relatesTo <" + pt.getPmEnacted().getIri() + "> ;\n"
-				+ "    owl:sameAs <"+ pt.getIri() + "> .\n"
-				+ "};";
-		if (!FusekiWrapper.getInstance().updateQuery(query) ) {
-			throw new Exception("Error inserting data.");
-		}
-		
-	}
-
-	public void createEndEvent(PT pt, List<TraceArtifact> arts, ControlOutputPort p) throws Exception {
-		//TODO: this won't work with concurrent flows (solution: send the start activity event in the request)
-		List<Event> events = pt.getEvents();
-		Event aux = null;
-		Event source = null;
-		for (int i = (events.size()-1); i >= 0; i--) {
-			aux = events.get(i); 
-			if (aux instanceof StartActivityEvent && 
-					(((StartActivityEvent) aux).getRelatesTo().getActivity().getIri().equals(p.getActivity().getIri()))) {
-				source = aux;
-				break;
-			}
-		}
-		int index = (Integer.parseInt(""+source.getIri().charAt(source.getIri().length()-1)));
-		
-		String startiri = pt.getIri().replace('#', '/') + "#" + "start_activity" + index;
-		String endiri = pt.getIri().replace('#', '/') + "#" + "end_activity" + index;
-		
-		List<String> artifactsIRI = new ArrayList<String>();
-		for (TraceArtifact art : arts) {
-			String artifactIRI = pt.getIri().replace('#', '/') + "#" + art.getGUID();
-			art.setIri(artifactIRI);
-			artifactsIRI.add(artifactIRI);
-			createTraceArtifact(endiri,startiri, art, pt);
-		}
-		
-	
-		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"
-				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/acyclic#>\n"
-				+ "INSERT DATA {\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"
-				+ "    tr:relatesTo <" + p.getIri() + "> ;\n";
-				
-		for (String iri : artifactsIRI) {
-			query += "    tr:produces <" + iri + "> ;\n" ;
-		}
-		query += "    owl:sameAs <" + endiri + "> .\n"
-			  + " <"+ startiri + "> tr:isFollowedBy <" + endiri + "> .\n"
-			  + "}";
-		
-		if (FusekiWrapper.getInstance().updateQuery(query) ) {
-			EndActivityEvent ev = new EndActivityEvent();
-			ev.setIri(endiri);
-			ev.setRelatesTo(p);
-			pt.addEvent(ev);
-			for (TraceArtifact art : arts) {
-				art.setProducedBy(ev);
-				ev.addTraceArtifact(art);
-			}
-			updatePT(pt);
-		} else {
-			throw new Exception("Error inserting data.");
-		}		
-	}
-
-	private void createTraceArtifact(String endEvIRI, String startEvIRI, TraceArtifact art, PT pt)
-			throws Exception {
-		
-		TraceArtifact latest = getLastestVersion(startEvIRI,art);
-		
-		String query = "PREFIX pt: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
-				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
-				+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
-				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/base#>\n"
-				+ "INSERT DATA { \n"
-				+ " <" + art.getIri() + "> rdf:type base:Versionable , pt:Artifact , owl:Thing , pt:element , base:ImmutableThing ;\n"
-				+ "        pt:hasLocation \"" + art.getLocation() + "\" ;\n"
-				+ "        pt:isProducedBy <" + endEvIRI + "> ;\n"
-				+ "        pt:relatesTo <" + art.getRelatesTo().getIri() + "> ;\n"
-				+ "        owl:sameAs  <" + art.getIri() + "> ;\n";
-				if (latest != null) {
-					String newTag = (Integer.parseInt(latest.getTag().substring(1))+1)+"";
-					art.setTag(newTag);
-					art.setGUID(art.getRelatesTo().getName()+"-"+art.getTag());
-					query += "        base:nextVersionOf \"" + latest.getIri() + "\" ;\n"
-					+ "        base:hasGUID \"" + art.getGUID() + "\" ;\n"
-					+ "        base:hasTag \"" + art.getTag() + "\" ;\n"
-					+ "  <" +latest.getIri() + "> base:previousVersionOf <" + art.getIri() +  "> .\n" 
-					+ "}";
-				} else {
-					art.setTag("v1");
-					art.setGUID(art.getRelatesTo().getName()+"-"+art.getTag());
-					query += "        base:hasGUID \"" + art.getGUID() + "\" ;\n"
-					+ "        base:hasTag \"" + art.getTag() + "\" .\n"
-					+ "}";
-				} 
-				
-		if (FusekiWrapper.getInstance().updateQuery(query) ) {
-			art.setTimestamp(Timestamp.from(Instant.now()));
-			if (latest != null) {
-				List<TraceArtifact> inputs = pt.getInputs();
-				boolean found = false;
-				if (inputs != null) {
-					for (TraceArtifact traceArtifact : inputs) {
-						if (traceArtifact.getIri().equals(latest.getIri())) {
-							traceArtifact.setNextVersion(art);
-							found = true;
-							break;
-						}
-					}
-				}
-				
-				if (!found) {
-					List<Event> events = pt.getEvents();
-					for (Event event : events) {
-						if (event instanceof StartActivityEvent && ((StartActivityEvent)event).getArtifact(latest.getIri()) != null) {
-							((StartActivityEvent)event).getArtifact(latest.getIri()).setNextVersion(art);
-							break;
-						} else if (event instanceof EndActivityEvent && ((EndActivityEvent)event).getArtifact(latest.getIri()) != null) {
-							((EndActivityEvent)event).getArtifact(latest.getIri()).setNextVersion(art);
-							break;
-						}  
-					}
-				}
-			}
-		} else {
-			throw new Exception("Error inserting data.");
-		}
-	}
-	
-	private TraceArtifact getLastestVersion(String startEvIRI, TraceArtifact art) {
-		String query = "PREFIX pt: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
-				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/base#>\n"
-				+ "SELECT DISTINCT ?art ?version\n"
-				+ "WHERE { \n"
-				+ "  ?art a pt:Artifact .\n"
-				+ "  ?art pt:relatesTo <" + art.getRelatesTo().getIri() + "> .\n"
-				+ "  ?art base:hasTag ?version .\n"
-				+ "  {\n"
-				+ "    {?art pt:isProducedBy ?endEv .\n"
-				+ "    <"+ startEvIRI+ "> pt:isPrecededBy+ ?endEv .} \n"
-				+ "    UNION \n"
-				+ "    {?art pt:isConsumedBy ?startEv .\n"
-				+ "     <"+ startEvIRI+ "> pt:isPrecededBy+ ?startEv .}\n"
-				+ "  }  \n"
-				+ "  FILTER NOT EXISTS {\n"
-				+ "  	?art base:previousVersionOf ?newArt .\n"
-				+ "    FILTER (?art != ?newArt) \n"
-				+ "  }\n"
-				+ "}";
-		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
-		if (rs.hasNext()) {
-			QuerySolution next = rs.next();
-			RDFNode lastestIRI = next.get("?art");
-			RDFNode latestVersion = next.get("?version");
-			if (lastestIRI != null) {
-				TraceArtifact result = new TraceArtifact();
-				result.setIri(latestVersion.toString());
-				result.setGUID(latestVersion.toString());
-				return result;
-			}
-		}
-		return null;
-	}
-
-	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"
-				+ "INSERT DATA {\n"
-				+ "	<"+ traceiri + "> rdf:type <http://ua.be/sdo2l/vocabulary/base/acyclic#element> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#EndTraceEvent> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#Event> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#element> , owl:Thing ;\n"
-				+ " 	tr:isPrecededBy <" + previous + "> ;\n"
-				+ "    	tr:relatesTo <" + pmIRI + "> ;\n"
-				+ "     owl:sameAs  <" + traceiri + "> .\n"
-				+ " <" + previous + "> tr:isFollowedBy <" + traceiri + "> .\n"				
-				+ "}";
-		if (FusekiWrapper.getInstance().updateQuery(query) ) {
-			EndTraceEvent ev = new EndTraceEvent();
-			ev.setIri(traceiri);
-			ev.setTimestamp(Timestamp.from(Instant.now()));
-			return ev;
-		} else {
-			throw new Exception("Error inserting data.");
-		}
-		
-	}
-
-}

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

@@ -3,12 +3,19 @@ package ua.be.wee.model.pt;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+
 import ua.be.wee.model.nodes.ports.ControlInputPort;
 
+@Entity
 public class StartActivityEvent extends Event {
 	
+	@OneToOne
 	private ControlInputPort relatesTo;
 	
+	@OneToMany
 	private List<TraceArtifact> consumedArtifacts;
 	
 	public StartActivityEvent() {
@@ -27,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())) {

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

@@ -0,0 +1,25 @@
+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;
+	}
+	
+	public String getName() {
+		return super.getIri().split("#")[1];
+	}
+}

+ 23 - 0
src/main/java/ua/be/wee/model/pt/TraceArtifact.java

@@ -2,8 +2,13 @@ package ua.be.wee.model.pt;
 
 import java.sql.Timestamp;
 
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+
 import ua.be.wee.model.nodes.Artifact;
 
+@Entity
 public class TraceArtifact {
 	
 	private String location;
@@ -12,16 +17,21 @@ public class TraceArtifact {
 	
 	private String GUID;
 	
+	@Id
 	private String iri;
 	
+	@OneToOne
 	private StartActivityEvent consumedBy;
 	
+	@OneToOne
 	private EndActivityEvent producedBy;
 	
+	@OneToOne
 	private Artifact relatesTo;
 	
 	private Timestamp timestamp;
 	
+	@OneToOne
 	private TraceArtifact nextVersion;
 	
 	
@@ -96,4 +106,17 @@ public class TraceArtifact {
 	public void setNextVersion(TraceArtifact nextVersion) {
 		this.nextVersion = nextVersion;
 	}
+	
+	public String getFileExtension() {
+		if (location != null && !location.equals("")) {
+			String ext = location.substring(location.lastIndexOf(".")+1);
+			return ext;
+		}
+		return null;
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		return iri.equals(((TraceArtifact)obj).getIri());
+	}
 }

+ 6 - 72
src/main/java/ua/be/wee/model/repository/FusekiWrapper.java

@@ -1,7 +1,5 @@
 package ua.be.wee.model.repository;
 
-import java.io.IOException;
-
 import org.apache.jena.query.QueryExecution;
 import org.apache.jena.query.ResultSet;
 import org.apache.jena.rdfconnection.RDFConnectionFuseki;
@@ -18,7 +16,13 @@ public class FusekiWrapper {
 	
 	private String serviceURI;
 	
+
+	public String getServiceURI() {
+		return serviceURI;
+	}
+
 	private FusekiWrapper() {
+		
 	}
 	
 	public static FusekiWrapper getInstance() {
@@ -62,53 +66,6 @@ public class FusekiWrapper {
 
 	}
 	
-
-//
-//	private static void uploadRDF(File rdf, String serviceURI)
-//			throws IOException {
-//
-//		// parse the file
-//		Model m = ModelFactory.createDefaultModel();
-//		try (FileInputStream in = new FileInputStream(rdf)) {
-//			m.read(in, null, "RDF/XML");
-//		}
-//
-//		// upload the resulting model
-////		DatasetAccessor accessor = DatasetAccessorFactory
-////				.createHTTP(serviceURI);
-////		accessor.putModel(m);
-//	}
-	
-	
-
-//	private static void execSelectAndPrint(String serviceURI, String queryStr) {
-//		
-//		QueryExecution q = QueryExecutionFactory.sparqlService(serviceURI,
-//				queryStr);
-//		ResultSet results = q.execSelect();
-//
-//		ResultSetFormatter.out(System.out, results);
-//
-//		while (results.hasNext()) {
-//			QuerySolution soln = results.nextSolution();
-//			RDFNode x = soln.get("?pm");
-//			System.out.println(x);
-//		}
-//	}
-//
-//	private static void execSelectAndProcess(String serviceURI, String query) {
-//		QueryExecution q = QueryExecutionFactory.sparqlService(serviceURI,
-//				query);
-//		ResultSet results = q.execSelect();
-//
-//		while (results.hasNext()) {
-//			QuerySolution soln = results.nextSolution();
-//			// assumes that you have an "?x" in your query
-//			RDFNode x = soln.get("x");
-//			System.out.println(x);
-//		}
-//	}
-	
 	public boolean testEndpoint() {
 		String query = "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" 
 				+ "SELECT ?pm WHERE {\n"
@@ -123,27 +80,4 @@ public class FusekiWrapper {
 		}
 		return execSelect.hasNext();
 	}
-
-	public static void main(String[] argv) throws IOException {
-		// uploadRDF(new File("test.rdf"), );
-//		execSelectAndPrint(
-//				"http://localhost:3030/Drivetrain",
-//				"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
-//				+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"
-//				+ "PREFIX wf: <http://ua.be/sdo2l/vocabulary/workflow#>\n"
-//				+ "SELECT ?pm ?nodes WHERE {\n"
-//				+ "  ?pm a wf:Workflow .\n"
-//				+ "  ?pm wf:coordinates ?nodes .\n"
-//				+ "}");
-
-//		execSelectAndProcess(
-//				"http://localhost:3030/Drivetrain",
-//				"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
-//				+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"
-//				+ "PREFIX wf: <http://ua.be/sdo2l/vocabulary/workflow#>\n"
-//				+ "SELECT ?pm ?nodes WHERE {\n"
-//				+ "  ?pm a wf:Workflow .\n"
-//				+ "  ?pm wf:coordinates ?nodes .\n"
-//				+ "}");
-	}
 }

+ 442 - 0
src/main/java/ua/be/wee/model/repository/NodeRespository.java

@@ -0,0 +1,442 @@
+package ua.be.wee.model.repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jena.query.QuerySolution;
+import org.apache.jena.query.ResultSet;
+import org.apache.jena.rdf.model.RDFNode;
+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.FinalNode;
+import ua.be.wee.model.nodes.ForkNode;
+import ua.be.wee.model.nodes.InitialNode;
+import ua.be.wee.model.nodes.JoinNode;
+import ua.be.wee.model.nodes.Node;
+import ua.be.wee.model.nodes.ports.ControlInputPort;
+import ua.be.wee.model.nodes.ports.ControlOutputPort;
+import ua.be.wee.model.nodes.ports.DataInputPort;
+import ua.be.wee.model.nodes.ports.DataOutputPort;
+import ua.be.wee.model.pm.PM;
+
+@Repository
+public class NodeRespository {
+
+	@Autowired
+	private PMRepository pmRepo;
+
+	public List<Node> getNodes(String pmIri) throws Exception {
+		List<Node> nodes = new ArrayList<Node>();
+
+		PM pm = pmRepo.getPM(pmIri);
+
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
+				+ "PREFIX ob: <http://ua.be/sdo2l/vocabulary/formalisms/object_diagram#>\n"
+				+ "SELECT ?node ?nodetype WHERE {\n" + "  ?pm a pm:Model ;\n" + "  	ob:hasName ?pmName ;\n"
+				+ "  	owl:sameAs <" + pm.getIri() + "> ;\n" + "  	ob:hasObject ?node .\n" + "  ?node a ?nodetype .\n"
+				+ "  FILTER (?nodetype in (pm:Initial, pm:Activity, pm:Final, pm:Join, pm:Fork, pm:Artifact)) .      \n"
+				+ "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+
+			RDFNode iri = soln.get("?node");
+			RDFNode type = soln.get("?nodetype");
+			Node node = createNode(iri, type);
+			nodes.add(node);
+		}
+		pm.setNodes(nodes);
+		updateArtifactOfActivities(pm);
+		updateControlNodesReferences(nodes);
+
+		return nodes;
+
+	}
+
+	private void updateControlNodesReferences(List<Node> nodes) {
+
+		for (Node node : nodes) {
+			if (node instanceof InitialNode) {
+				updateInitialNode(nodes, (InitialNode) node);
+			} else if (node instanceof FinalNode) {
+				updateFinalNode(nodes, (FinalNode) node);
+			} else if (node instanceof ForkNode) {
+				updateForkNode(nodes, (ForkNode) node);
+			} else if (node instanceof JoinNode) {
+				updateJoinNode(nodes, (JoinNode) node);
+			}
+		}
+
+	}
+
+	private void updateJoinNode(List<Node> nodes, JoinNode node) {
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" + "SELECT ?next ?nodetype ?act\n"
+				+ "WHERE { \n" + "  ?node owl:sameAs<" + node.getIri() + ">.\n" + "  ?node pm:ctrlTo ?next.\n"
+				+ "  ?next a ?nodetype ;\n"
+				+ "	FILTER (?nodetype in (pm:CtrlOutputPort, pm:Initial, pm:Final,pm:Fork, pm:Join)) \n"
+				+ "	OPTIONAL {\n" + "		?next pm:ofActivity ?act .\n" + "	}\n" + "}";
+		List<Node> list = new ArrayList<Node>();
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode type = soln.get("?nodetype");
+			String nextIri;
+			if (type.toString().equals(Node.CTRL_OUTPUT_PORT_IRI)) {
+				nextIri = soln.get("?act").toString();
+			} else {
+				nextIri = soln.get("?next").toString();
+			}
+			for (Node node2 : nodes) {
+				if (node2.getIri().equals(nextIri)) {
+					list.add(node2);
+				}
+			}
+		}
+		node.setPreviousNodes(list);
+		
+		
+		query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" 
+				+ "SELECT ?next ?nodetype ?act\n"
+				+ "WHERE { \n" + "  ?node owl:sameAs<" + node.getIri() + ">.\n" 
+				+ "  ?node pm:ctrlFrom ?next.\n"
+				+ "  ?next a ?nodetype ;\n"
+				+ "	FILTER (?nodetype in (pm:CtrlOutputPort,pm:Fork, pm:Join, pm:Initial)) \n" 
+				+ "	OPTIONAL {\n"
+				+ "		?next pm:ofActivity ?act .\n" + "	}\n" + "}";
+		results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode type = soln.get("?nodetype");
+			String nextIri;
+			if (type.toString().equals(Node.CTRL_OUTPUT_PORT_IRI)) {
+				nextIri = soln.get("?act").toString();
+			} else {
+				nextIri = soln.get("?next").toString();
+			}
+			for (Node node2 : nodes) {
+				if (node2.getIri().equals(nextIri)) {
+					node.setNext(node2);
+					break;
+				}
+			}
+		}
+
+		
+	}
+
+	private void updateForkNode(List<Node> nodes, ForkNode node) {
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" 
+				+ "SELECT ?next ?nodetype ?act\n"
+				+ "WHERE { \n" + "  ?node owl:sameAs<" + node.getIri() + ">.\n" 
+				+ "  ?node pm:ctrlFrom ?next.\n"
+				+ "  ?next a ?nodetype ;\n"
+				+ "	FILTER (?nodetype in (pm:CtrlOutputPort,pm:Fork, pm:Join, pm:Initial)) \n" 
+				+ "	OPTIONAL {\n"
+				+ "		?next pm:ofActivity ?act .\n" + "	}\n" + "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode type = soln.get("?nodetype");
+			String nextIri;
+			if (type.toString().equals(Node.CTRL_OUTPUT_PORT_IRI)) {
+				nextIri = soln.get("?act").toString();
+			} else {
+				nextIri = soln.get("?next").toString();
+			}
+			for (Node node2 : nodes) {
+				if (node2.getIri().equals(nextIri)) {
+					node.setPrevious(node2);
+					break;
+				}
+			}
+		}
+
+		query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" + "SELECT ?next ?nodetype ?act\n"
+				+ "WHERE { \n" + "  ?node owl:sameAs<" + node.getIri() + ">.\n" + "  ?node pm:ctrlTo ?next.\n"
+				+ "  ?next a ?nodetype ;\n"
+				+ "	FILTER (?nodetype in (pm:CtrlInputPort, pm:Initial, pm:Final,pm:Fork, pm:Join)) \n"
+				+ "	OPTIONAL {\n" + "		?next pm:ofActivity ?act .\n" + "	}\n" + "}";
+		List<Node> list = new ArrayList<Node>();
+		results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode type = soln.get("?nodetype");
+			String nextIri;
+			if (type.toString().equals(Node.CTRL_INPUT_PORT_IRI)) {
+				nextIri = soln.get("?act").toString();
+			} else {
+				nextIri = soln.get("?next").toString();
+			}
+			for (Node node2 : nodes) {
+				if (node2.getIri().equals(nextIri)) {
+					list.add(node2);
+				}
+			}
+		}
+		node.setNextNodes(list);
+
+	}
+
+	private void updateFinalNode(List<Node> nodes, FinalNode node) {
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" + "SELECT ?next ?nodetype ?act\n"
+				+ "WHERE { \n" + "  ?node owl:sameAs<" + node.getIri() + ">.\n" + "  ?node pm:ctrlFrom ?next.\n"
+				+ "  ?next a ?nodetype ;\n"
+				+ "	FILTER (?nodetype in (pm:CtrlOutputPort, pm:Initial, pm:Final,pm:Fork, pm:Join)) \n"
+				+ "	OPTIONAL {\n" + "		?next pm:ofActivity ?act .\n" + "	}\n" + "}";
+		List<Node> list = new ArrayList<Node>();
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode type = soln.get("?nodetype");
+			String nextIri;
+			if (type.toString().equals(Node.CTRL_OUTPUT_PORT_IRI)) {
+				nextIri = soln.get("?act").toString();
+			} else {
+				nextIri = soln.get("?next").toString();
+			}
+			for (Node node2 : nodes) {
+				if (node2.getIri().equals(nextIri)) {
+					list.add(node2);
+				}
+			}
+		}
+		node.setPrevious(list);
+	}
+
+	private void updateInitialNode(List<Node> nodes, InitialNode node) {
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" + "SELECT ?next ?nodetype ?act\n"
+				+ "WHERE { \n" + "  ?node owl:sameAs<" + node.getIri() + ">.\n" + "  ?node pm:ctrlTo ?next.\n"
+				+ "  ?next a ?nodetype ;\n" + "	FILTER (?nodetype in (pm:CtrlInputPort, pm:Final,pm:Fork, pm:Join)) \n"
+				+ "	OPTIONAL {\n" + "		?next pm:ofActivity ?act .\n" + "	}\n" + "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode type = soln.get("?nodetype");
+			String nextIri;
+			if (type.toString().equals(Node.CTRL_INPUT_PORT_IRI)) {
+				nextIri = soln.get("?act").toString();
+			} else {
+				nextIri = soln.get("?next").toString();
+			}
+			for (Node node2 : nodes) {
+				if (node2.getIri().equals(nextIri)) {
+					node.setNext(node2);
+					break;
+				}
+			}
+		}
+	}
+
+	private void updateArtifactOfActivities(PM pm) throws Exception {
+		for (Node node : pm.getNodes()) {
+			if (node instanceof Activity) {
+				Activity act = (Activity) node;
+				for (DataInputPort inport : act.getDatalInPorts()) {
+					String query = "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
+							+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n" + "SELECT  ?inport ?art\n" + "WHERE { \n"
+							+ "  ?inport owl:sameAs <" + inport.getIri() + "> .\n" + "  ?inport pm:dataFrom ?art .\n"
+							+ "}";
+					ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+					if (results.hasNext()) {
+						QuerySolution soln = results.nextSolution();
+
+						RDFNode art = soln.get("?art");
+						if (art != null && !art.toString().isEmpty()) {
+							Artifact artifact = (Artifact) pm.getNode(art.toString());
+							act.addInputArtifact(artifact);
+						}
+					} else {
+						throw new Exception("Query did not return any data: \n" + query );
+					}
+					
+				}
+
+				for (DataOutputPort outport : act.getDataOutPorts()) {
+					String query = "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
+							+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n" + "SELECT  ?outport ?art\n"
+							+ "WHERE { \n" + "  ?outport owl:sameAs <" + outport.getIri() + "> .\n"
+							+ "  ?outport pm:dataTo ?art .\n" + "}";
+					ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+					if (results.hasNext()) {
+						QuerySolution soln = results.nextSolution();
+	
+						RDFNode art = soln.get("?art");
+						if (art != null && !art.toString().isEmpty()) {
+							Artifact artifact = (Artifact) pm.getNode(art.toString());
+							act.addOutputArtifact(artifact);
+						}
+					} else {
+						throw new Exception("Query did not return any data: \n" + query );
+					}
+				}
+			}
+		}
+	}
+
+	private Node createNode(RDFNode iri, RDFNode type) throws Exception {
+		Node node = null;
+		switch (type.toString()) {
+		case Node.ACTIVITY_IRI:
+			node = createActivity(iri.toString());
+			break;
+		case Node.INITIAL_IRI:
+			node = new InitialNode();
+			break;
+		case Node.FINAL_IRI:
+			node = new FinalNode();
+			break;
+		case Node.FORKJOIN_IRI:
+			// addlogic for fork join
+			node = new JoinNode();
+			break;
+		case Node.ARTIFACT_IRI:
+			// addlogic for fork join
+			node = createArtifact(iri.toString());
+			break;
+		}
+		node.setIri(iri.toString());
+		return node;
+	}
+
+	private Node createArtifact(String iri) throws Exception {
+		Artifact art = new Artifact();
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n"
+				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/base#>\n" + "SELECT ?art ?name ?typename WHERE {\n"
+				+ "	?art owl:sameAs <" + iri + "> .\n" + " ?art	pm:hasName ?name .\n"
+				+ " ?art  	pm:hasType ?type .\n" + " ?type base:hasGUID ?typename .\n" + "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		if (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode name = soln.get("?name");
+			RDFNode type = soln.get("?typename");
+			art.setIri(iri);
+			art.setName(name.toString());
+			art.setType(type.toString());
+			return art;
+		} else {
+			throw new Exception("Query did not return any data: \n" + query );
+		}
+		
+	}
+
+	private Node createActivity(String iri) throws Exception {
+		Activity act = new Activity();
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX ftg: <http://ua.be/sdo2l/vocabulary/formalisms/ftg#>\n"
+				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/base#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" + "SELECT ?act ?name ?type WHERE {\n"
+				+ "	?act owl:sameAs <" + iri + ">;\n" + "   		pm:isTransformation ?t ;  \n"
+				+ "   		pm:hasName ?name .  \n" + " ?t base:hasGUID ?type .  \n" + "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		if (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode name = soln.get("?name");
+			RDFNode type = soln.get("?type");
+			act.setIri(iri);
+			act.setName(name.toString());
+			act.setTransformationName(type.toString());
+
+			act.setCtrlInPorts(getCtrlInPorts(act));
+			act.setCtrlOutPorts(getCtrlOutPorts(act));
+			act.setDatalInPorts(getDataInPorts(act));
+			act.setDataOutPorts(getDataOutPorts(act));
+
+			return act;
+
+		} else {
+			throw new Exception("Query did not return any data: \n" + query );
+		}
+	}
+
+	private List<DataOutputPort> getDataOutPorts(Activity act) {
+		List<DataOutputPort> list = new ArrayList<DataOutputPort>();
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" + "SELECT ?port ?pname WHERE {\n"
+				+ "	?act owl:sameAs <" + act.getIri() + ">;\n" + "   		pm:hasPort ?port .\n"
+				+ "  	?port a pm:DataOutputPort .\n" + "  	?port pm:hasName ?pname .\n" + "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode iri = soln.get("?port");
+			RDFNode name = soln.get("?pname");
+			DataOutputPort cout = new DataOutputPort();
+			cout.setIri(iri.toString());
+			cout.setName(name.toString());
+			cout.setActivity(act);
+			list.add(cout);
+		}
+		return list;
+	}
+
+	private List<DataInputPort> getDataInPorts(Activity act) {
+		List<DataInputPort> list = new ArrayList<DataInputPort>();
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" + "SELECT ?port ?pname WHERE {\n"
+				+ "	?act owl:sameAs <" + act.getIri() + ">;\n" + "   		pm:hasPort ?port .\n"
+				+ "  	?port a pm:DataInputPort .\n" + "  	?port pm:hasName ?pname .\n" + "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode iri = soln.get("?port");
+			RDFNode name = soln.get("?pname");
+			DataInputPort cout = new DataInputPort();
+			cout.setIri(iri.toString());
+			cout.setName(name.toString());
+			cout.setActivity(act);
+			list.add(cout);
+		}
+		return list;
+	}
+
+	private List<ControlOutputPort> getCtrlOutPorts(Activity act) {
+		List<ControlOutputPort> list = new ArrayList<ControlOutputPort>();
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" + "SELECT ?port ?pname WHERE {\n"
+				+ "	?act owl:sameAs <" + act.getIri() + ">;\n" + "   		pm:hasPort ?port .\n"
+				+ "  	?port a pm:CtrlOutputPort .\n" + "  	?port pm:hasName ?pname .\n" + "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode iri = soln.get("?port");
+			RDFNode name = soln.get("?pname");
+			ControlOutputPort cout = new ControlOutputPort();
+			cout.setIri(iri.toString());
+			cout.setName(name.toString());
+			cout.setActivity(act);
+			list.add(cout);
+		}
+		return list;
+	}
+
+	private List<ControlInputPort> getCtrlInPorts(Activity act) {
+		List<ControlInputPort> list = new ArrayList<ControlInputPort>();
+		String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX pm: <http://ua.be/sdo2l/vocabulary/formalisms/pm#>\n" + "SELECT ?port ?pname WHERE {\n"
+				+ "	?act owl:sameAs <" + act.getIri() + ">;\n" + "   		pm:hasPort ?port .\n"
+				+ "  	?port a pm:CtrlInputPort .\n" + "  	?port pm:hasName ?pname .\n" + "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			QuerySolution soln = results.nextSolution();
+			RDFNode iri = soln.get("?port");
+			RDFNode name = soln.get("?pname");
+			ControlInputPort cout = new ControlInputPort();
+			cout.setIri(iri.toString());
+			cout.setName(name.toString());
+			cout.setAct(act);
+			list.add(cout);
+		}
+		return list;
+	}
+
+}

+ 4 - 4
src/main/java/ua/be/wee/model/pm/PMRepository.java

@@ -1,4 +1,4 @@
-package ua.be.wee.model.pm;
+package ua.be.wee.model.repository;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -6,13 +6,13 @@ import java.util.List;
 import org.apache.jena.query.QuerySolution;
 import org.apache.jena.query.ResultSet;
 import org.apache.jena.rdf.model.RDFNode;
-import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Repository;
 
 import ua.be.wee.model.nodes.Node;
-import ua.be.wee.model.repository.FusekiWrapper;
+import ua.be.wee.model.pm.PM;
 import ua.be.wee.model.util.Pair;
 
-@Component
+@Repository
 public class PMRepository {
 
 	public List<PM> getAllPMs() {

+ 819 - 0
src/main/java/ua/be/wee/model/repository/PTRepository.java

@@ -0,0 +1,819 @@
+package ua.be.wee.model.repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jena.query.QuerySolution;
+import org.apache.jena.query.ResultSet;
+import org.apache.jena.rdf.model.RDFNode;
+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;
+import ua.be.wee.model.pt.EndActivityEvent;
+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);
+		String traceiri = pm.getIri().split("#")[0] + "/traces#pt_" + index;
+		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"
+				+ "INSERT {\n"
+				+ "GRAPH <"+ PT.TRACE_GRAPH_IRI + "> {"
+				+ "	<"+ traceiri + "> 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"
+				+ "    	tr:relatesTo <" + pm.getIri() + "> ;\n"
+				+ " 	tr:hasTimestamp ?now ; \n"
+				+ "     owl:sameAs  <" + traceiri + "> .\n"
+				+ "}"
+				+ "} WHERE {"
+				+ "	SELECT ?now\n"
+				+ "    WHERE\n"
+				+ "      {\n"
+				+ "      BIND(now() AS ?now) .\n"
+				+ "      }"
+				+ "}";
+		if (FusekiWrapper.getInstance().updateQuery(query) ) {
+			PT pt = new PT();
+			pt.setPmEnacted(pm);
+			pt.setIri(traceiri);
+			
+			
+			
+			query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+					+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+					+ "SELECT ?ts  WHERE {\n"
+					+ "	?pt a tr:StartTraceEvent ;\n"
+					+ "  		tr:hasTimestamp ?ts ;\n"
+					+ "  		owl:sameAs <" + traceiri + "> .\n"
+					+ "}";
+			ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+			if (results.hasNext()) {
+				QuerySolution next = results.next();
+				RDFNode rdfNode = next.get("?ts");
+				
+				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 {
+			throw new Exception("Error inserting data.");
+		}
+		
+	}
+	
+	private int getNextIndex(PM pm) {
+		int index = 0;
+		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "SELECT ?pt  WHERE {\n"
+				+ "	?pt a tr:StartTraceEvent ;\n"
+				+ "  		tr:relatesTo <" + pm.getIri() + "> .\n"
+				+ "}";
+		ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+		while (results.hasNext()) {
+			results.next();
+			index++;
+		}
+		return index;
+	}
+
+	public void createStartEvent(PT pt, ControlInputPort port, Activity act, List<TraceArtifact> arts) throws Exception {
+		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;
+		
+		String preiri = pt.getLastEvent() != null ? pt.getLastEvent().getIri() : pt.getIri();
+		String portiri = port.getIri();
+		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"
+				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/acyclic#>\n"
+				+ "INSERT {\n"
+				+ "GRAPH <"+ PT.TRACE_GRAPH_IRI + "> {"
+				+ "	<" + 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:hasTimestamp ?now ; \n"
+				+ "    tr:isPrecededBy <" + preiri + "> ;\n"
+				+ "    tr:relatesTo <" + portiri + "> ;\n";
+		if (arts != null) {
+			for (TraceArtifact artifact : arts) {
+				query += "    tr:consumes <" + artifact.getIri() + "> ;\n";
+			}
+		}
+		query +=  "    owl:sameAs <" + iri + "> .\n"
+				+ " <"+ preiri + "> tr:isFollowedBy <" + iri + "> .\n"
+				+ "}"
+				+ "} WHERE {"
+				+ "	SELECT ?now\n"
+				+ "    WHERE\n"
+				+ "      {\n"
+				+ "      BIND(now() AS ?now) .\n"
+				+ "      }"
+				+ "}";
+		StartActivityEvent ev = new StartActivityEvent();
+		if (FusekiWrapper.getInstance().updateQuery(query) ) {
+			ev.setIri(iri);
+			ev.setRelatesTo(act.getCtrlInPorts().get(0));
+			pt.addEvent(ev);
+			
+			query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+					+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+					+ "SELECT ?ts  WHERE {\n"
+					+ "	?pt		tr:hasTimestamp ?ts ;\n"
+					+ "  		owl:sameAs <" + iri + "> .\n"
+					+ "}";
+			ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+			if (results.hasNext()) {
+				QuerySolution next = results.next();
+				RDFNode rdfNode = next.get("?ts");
+				ev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(rdfNode.toString()));
+			}
+			
+		} else {
+			throw new Exception("Error inserting data.");
+		}
+		
+		if (arts != null) {
+			for (TraceArtifact traceArtifact : arts) {
+				query = "PREFIX pt: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+						+ "INSERT DATA { \n"
+						+ "GRAPH <"+ PT.TRACE_GRAPH_IRI + "> {"
+						+ " <" + traceArtifact.getIri() + "> " 
+						+ "        pt:isConsumedBy <" + iri + "> ;\n"
+						+ "}"
+						+ "}";
+				if (FusekiWrapper.getInstance().updateQuery(query) ) {
+					traceArtifact.setConsumedBy(ev);
+					ev.addTraceArtifact(traceArtifact);
+				} else {
+					throw new Exception("Error inserting data.");
+				}
+			}
+		}
+		updatePT(pt);
+		
+	}
+	
+	public void updatePT(PT pt) throws Exception {
+		String transitive = "";
+		for (Event ev : pt.getEvents()) {
+			if (ev instanceof StartTraceEvent) {
+				continue;
+			} else {
+				transitive += "<" + ev.getIri()+">,";
+			}
+		}
+		transitive = transitive.substring(0, transitive.length()-1);
+		
+		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"
+				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/acyclic#>\n"
+				+ "DELETE { "
+				+ "GRAPH <"+ PT.TRACE_GRAPH_IRI + "> {"
+				+ "?pt ?p ?v . }\n"
+				+ "}"
+				+ "WHERE { \n"
+				+ "  ?pt a tr:StartTraceEvent .\n"
+				+ "  ?pt owl:sameAs <" + pt.getIri() + "> .\n"
+				+ "  ?pt ?p ?v .\n"
+				+ "};\n"
+				+ "INSERT DATA {\n"
+				+ "GRAPH <"+ PT.TRACE_GRAPH_IRI + "> {"
+				+ "	<" + 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(1).getIri() + "> ;\n"
+				+ "    base:transitiveForward "+ transitive + " ;\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"
+				+ "}"
+				+ "};";
+		if (!FusekiWrapper.getInstance().updateQuery(query) ) {
+			throw new Exception("Error inserting data.");
+		}
+		
+	}
+
+	public void createEndEvent(PT pt, List<TraceArtifact> arts, ControlOutputPort p) throws Exception {
+		//TODO: this won't work with concurrent flows (solution: send the start activity event in the request)
+		List<Event> events = pt.getEvents();
+		Event aux = null;
+		Event source = null;
+		for (int i = (events.size()-1); i >= 0; i--) {
+			aux = events.get(i); 
+			if (aux instanceof StartActivityEvent && 
+					(((StartActivityEvent) aux).getRelatesTo().getActivity().getIri().equals(p.getActivity().getIri()))) {
+				source = aux;
+				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 endiri = pt.getIri().replace('#', '/') + "#" + "end_activity" + index;
+		
+		List<String> artifactsIRI = new ArrayList<String>();
+		for (TraceArtifact art : arts) {
+			artifactsIRI.add(createTraceArtifact(endiri,preiri, art, pt));
+		}
+		
+	
+		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"
+				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/acyclic#>\n"
+				+ "INSERT {\n"
+				+ "GRAPH <"+ PT.TRACE_GRAPH_IRI + "> {"
+				+ "	<" + 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";
+				
+		for (String iri : artifactsIRI) {
+			query += "    tr:produces <" + iri + "> ;\n" ;
+		}
+		query += "    owl:sameAs <" + endiri + "> .\n"
+			  + " <"+ preiri + "> tr:isFollowedBy <" + endiri + "> .\n"
+			  + "}"
+			  + "} WHERE {"
+				+ "	SELECT ?now\n"
+				+ "    WHERE\n"
+				+ "      {\n"
+				+ "      BIND(now() AS ?now) .\n"
+				+ "      }"
+				+ "}";
+		
+		if (FusekiWrapper.getInstance().updateQuery(query) ) {
+			EndActivityEvent ev = new EndActivityEvent();
+			ev.setIri(endiri);
+			ev.setRelatesTo(p);
+			pt.addEvent(ev);
+			
+			query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+					+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+					+ "SELECT ?ts  WHERE {\n"
+					+ "	?pt		tr:hasTimestamp ?ts ;\n"
+					+ "  		owl:sameAs <" + endiri + "> .\n"
+					+ "}";
+			ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+			if (results.hasNext()) {
+				QuerySolution next = results.next();
+				RDFNode rdfNode = next.get("?ts");
+				ev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(rdfNode.toString()));
+			}
+			
+			
+			for (TraceArtifact art : arts) {
+				art.setProducedBy(ev);
+				ev.addTraceArtifact(art);
+			}
+			updatePT(pt);
+		} else {
+			throw new Exception("Error inserting data.");
+		}		
+	}
+
+	private String createTraceArtifact(String endEvIRI, String startEvIRI, TraceArtifact art, PT pt)
+			throws Exception {
+		
+		TraceArtifact latest = getLastestVersion(startEvIRI,art);
+		if (latest != null) {
+			String newTag = (Integer.parseInt(latest.getTag().substring(1))+1)+"";
+			art.setTag("v"+newTag);
+		} else {
+			art.setTag("v1");	
+		}
+		art.setGUID(art.getRelatesTo().getName()+"-"+art.getTag());
+		art.setIri(pt.getIri().replace('#', '/') + "#" + art.getGUID());
+		
+		
+		String query = "PREFIX pt: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+				+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
+				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/base#>\n"
+				+ "INSERT { \n"
+				+ "GRAPH <"+ PT.TRACE_GRAPH_IRI + "> {"
+				+ " <" + art.getIri() + "> rdf:type base:Versionable , pt:Artifact , owl:Thing , pt:element , base:ImmutableThing ;\n"
+				+ "        pt:hasLocation \"" + art.getLocation() + "\" ;\n"
+				+ "        pt:isProducedBy <" + endEvIRI + "> ;\n"
+				+ "        pt:relatesTo <" + art.getRelatesTo().getIri() + "> ;\n"
+				+ "	       pt:addedAt ?now ; \n "
+				+ "        owl:sameAs  <" + art.getIri() + "> ;\n";
+				if (latest != null) {
+					query += "        base:nextVersionOf <" + latest.getIri() + "> ;\n"
+					+ "        base:hasGUID \"" + art.getGUID() + "\" ;\n"
+					+ "        base:hasTag \"" + art.getTag() + "\" .\n"
+					+ "  <" +latest.getIri() + "> base:previousVersionOf <" + art.getIri() +  "> .\n"; 
+				} else {
+					query += "        base:hasGUID \"" + art.getGUID() + "\" ;\n"
+					+ "        base:hasTag \"" + art.getTag() + "\" .\n";
+				} 
+				query += "}"
+					   + "} WHERE {"
+				+ "	SELECT ?now\n"
+				+ "    WHERE\n"
+				+ "      {\n"
+				+ "      BIND(now() AS ?now) .\n"
+				+ "      }"
+				+ "}";
+				
+		if (FusekiWrapper.getInstance().updateQuery(query) ) {
+			
+			
+			query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+					+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+					+ "SELECT ?ts  WHERE {\n"
+					+ "	?pt		tr:addedAt ?ts ;\n"
+					+ "  		owl:sameAs <" + art.getIri() + "> .\n"
+					+ "}";
+			ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+			if (results.hasNext()) {
+				QuerySolution next = results.next();
+				RDFNode rdfNode = next.get("?ts");
+				art.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(rdfNode.toString()));
+			}
+			
+			
+			if (latest != null) {
+				List<TraceArtifact> inputs = pt.getInputs();
+				boolean found = false;
+				if (inputs != null) {
+					for (TraceArtifact traceArtifact : inputs) {
+						if (traceArtifact.getIri().equals(latest.getIri())) {
+							traceArtifact.setNextVersion(art);
+							found = true;
+							break;
+						}
+					}
+				}
+				
+				if (!found) {
+					List<Event> events = pt.getEvents();
+					for (Event event : events) {
+						if (event instanceof StartActivityEvent && ((StartActivityEvent)event).getArtifact(latest.getIri()) != null) {
+							((StartActivityEvent)event).getArtifact(latest.getIri()).setNextVersion(art);
+							break;
+						} else if (event instanceof EndActivityEvent && ((EndActivityEvent)event).getArtifact(latest.getIri()) != null) {
+							((EndActivityEvent)event).getArtifact(latest.getIri()).setNextVersion(art);
+							break;
+						}  
+					}
+				}
+				
+			}
+			return art.getIri();
+		} else {
+			throw new Exception("Error inserting data.");
+		}
+
+	}
+	
+	private TraceArtifact getLastestVersion(String startEvIRI, TraceArtifact art) {
+		String query = "PREFIX pt: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+				+ "PREFIX base: <http://ua.be/sdo2l/vocabulary/base/base#>\n"
+				+ "SELECT DISTINCT ?art ?version\n"
+				+ "WHERE { \n"
+				+ "  ?art a pt:Artifact .\n"
+				+ "  ?art pt:relatesTo <" + art.getRelatesTo().getIri() + "> .\n"
+				+ "  ?art base:hasTag ?version .\n"
+				+ "  {\n"
+				+ "    {?art pt:isProducedBy ?endEv .\n"
+				+ "    <"+ startEvIRI+ "> pt:isPrecededBy+ ?endEv .} \n"
+				+ "    UNION \n"
+				+ "    {?art pt:isConsumedBy ?startEv .\n"
+				+ "     <"+ startEvIRI+ "> pt:isPrecededBy+ ?startEv .}\n"
+				+ "  }  \n"
+				+ "  FILTER NOT EXISTS {\n"
+				+ "  	?art base:previousVersionOf ?newArt .\n"
+				+ "    FILTER (?art != ?newArt) \n"
+				+ "  }\n"
+				+ "}";
+		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
+		if (rs.hasNext()) {
+			QuerySolution next = rs.next();
+			RDFNode lastestIRI = next.get("?art");
+			RDFNode latestVersion = next.get("?version");
+			if (lastestIRI != null) {
+				TraceArtifact result = new TraceArtifact();
+				result.setIri(lastestIRI.toString());
+				result.setTag(latestVersion.toString());
+				return result;
+			}
+		}
+		return null;
+	}
+
+	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"
+				+ "INSERT {\n"
+				+ "GRAPH <"+ PT.TRACE_GRAPH_IRI + "> {"
+				+ "	<"+ traceiri + "> rdf:type <http://ua.be/sdo2l/vocabulary/base/acyclic#element> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#EndTraceEvent> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#Event> , <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#element> , owl:Thing ;\n"
+				+ " 	tr:isPrecededBy <" + previous + "> ;\n"
+				+ "    	tr:relatesTo <" + pmIRI + "> ;\n"
+				+ "     tr:hasTimestamp ?now ; \n"
+				+ "     owl:sameAs  <" + traceiri + "> .\n"
+				+ " <" + previous + "> tr:isFollowedBy <" + traceiri + "> .\n"				
+				+ "}"
+				+ "} WHERE {"
+				+ "	SELECT ?now\n"
+				+ "    WHERE\n"
+				+ "      {\n"
+				+ "      BIND(now() AS ?now) .\n"
+				+ "      }"
+				+ "}";
+				
+		if (FusekiWrapper.getInstance().updateQuery(query) ) {
+			EndTraceEvent ev = new EndTraceEvent();
+			ev.setIri(traceiri);
+
+			query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#>\n"
+					+ "PREFIX owl: <http://www.w3.org/2002/07/owl#>\n"
+					+ "SELECT ?ts  WHERE {\n"
+					+ "	?pt		tr:hasTimestamp ?ts ;\n"
+					+ "  		owl:sameAs <" + traceiri + "> .\n"
+					+ "}";
+			ResultSet results = FusekiWrapper.getInstance().execQuery(query);
+			if (results.hasNext()) {
+				QuerySolution next = results.next();
+				RDFNode rdfNode = next.get("?ts");
+				ev.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(rdfNode.toString()));
+			}
+			
+			ev.setPmEnacted(pmRepo.getPM(pmIRI));
+			
+			return ev;
+		} else {
+			throw new Exception("Error inserting data.");
+		}
+		
+	}
+
+	
+	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"
+				+ "SELECT ?trace ?pm ?ts WHERE {\n"
+				+ "	?trace rdf:type <http://ua.be/sdo2l/vocabulary/formalisms/processtraces#StartTraceEvent> ;\n"
+				+ "    	tr:relatesTo ?pm ;\n"
+				+ " 	tr:hasTimestamp ?ts ; \n"
+				+ "}";
+		ResultSet rs = FusekiWrapper.getInstance().execQuery(query);
+		while (rs.hasNext()) {
+			QuerySolution next = rs.next();
+			RDFNode trace = next.get("?trace");
+			RDFNode pm = next.get("?pm");
+			RDFNode ts = next.get("?ts");
+			StartTraceEvent pt = new StartTraceEvent();
+			pt.setIri(trace.toString());
+			pt.setTimestamp(DateTimeConverter.convertSPARQLDateTimeToTimestamp(ts.toString()));
+			pt.setPmEnacted(pmRepo.getPM(pm.toString()));
+			list.add(pt);
+		}
+		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;
+			
+			List<TraceArtifact> artifacts = new ArrayList<TraceArtifact>();
+			
+			while (next!= null && !next.toString().equals("")) {
+				if (nexttype.toString().equals(Event.START_ACTIVITY_IRI)) {
+					Pair<String,String> p = getStartActivityEvent(next.toString(), pm2, list, artifacts);
+					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, artifacts);
+					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, List<TraceArtifact> artifacts) 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, artifacts));
+
+			
+			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> artifacts) {
+		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 ?next 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"
+				+ "	   OPTIONAL {\n"
+				+ "    	?art base:nextVersionOf ?next \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");
+			RDFNode nextArt = next.get("?next");
+			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);
+			
+			if (nextArt != null && !nextArt.toString().equals("")) {
+				for (TraceArtifact traceArtifact : artifacts) {
+					if (traceArtifact.getIri().equals(nextArt.toString())) {
+						traceArtifact.setNextVersion(tArt);
+					}
+				}
+			}
+
+			artifacts.add(tArt);
+		}
+		return arts;				
+	}
+
+	private Pair<String, String> getEndActivityEvent(String iri, PM pm, List<Event> list, List<TraceArtifact> artifacts) 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,artifacts));
+						
+			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;		
+	}
+
+	
+
+}

+ 22 - 0
src/main/java/ua/be/wee/model/util/DateTimeConverter.java

@@ -0,0 +1,22 @@
+package ua.be.wee.model.util;
+
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+import org.apache.jena.atlas.lib.DateTimeUtils;
+
+public class DateTimeConverter {
+	
+	public static Timestamp convertSPARQLDateTimeToTimestamp(String dateTimeSparql) {
+		String[] split = dateTimeSparql.split("T");
+		return Timestamp.valueOf(split[0].substring(0) + " " + split[1].substring(0,8));
+	}
+
+	public static String convertTimestampToSPARQLdateTime(Timestamp timestamp) {
+		Calendar instance = Calendar.getInstance();
+		instance.setTime(timestamp);
+		String converted = DateTimeUtils.calendarToXSDDateTimeString(instance);
+		converted = "\"" + converted + "\"^^<http://www.w3.org/2001/XMLSchema#dateTime>";
+		return converted;
+	}
+}

+ 1 - 1
src/main/resources/application.properties

@@ -1,5 +1,5 @@
 server.port=8081
 base_url=http://localhost:8081/
 spring.application.name=wee
-endpoint=http://localhost:3030/joeri
+endpoint=http://localhost:3030/SystemDesignOntology2Layers
 storageURL=http://localhost:5000

BIN
src/main/resources/static/audio/Wee.mp3


BIN
src/main/resources/static/img/home-button.png


BIN
src/main/resources/static/img/home.png


BIN
src/main/resources/static/img/slip-and-fall.png


+ 17 - 0
src/main/resources/static/main.js

@@ -7,6 +7,23 @@ function showDiv(select){
     }
 }
 
+function play() {
+           var audio = document.getElementById("audio");
+    		var img = document.getElementById("img");
+    
+    		function play() {
+    			  audio.play();
+    		}
+    
+    		function stop() {
+      			audio.pause();
+    		}
+    
+    		img.addEventListener('click', play);
+    		img.addEventListener('mouseover', play);
+    		img.addEventListener('mouseout', stop);
+}
+
 // document.addEventListener('DOMContentLoaded', () => {
 //     (document.querySelectorAll('.toggle') || []).forEach(($toggle) => {
 //         $toggle.addEventListener('click', () => {

+ 1 - 1
src/main/resources/templates/base.html

@@ -28,7 +28,7 @@
 
     <div id="navigation-menu" class="navbar-menu">
       <div class="navbar-start">
-        <a class="navbar-item">Home</a>
+        <a class="navbar-item" href="/" >Home</a>
         <div class="navbar-item has-dropdown is-hoverable">
           <a class="navbar-link">Enactment</a>
           <div class="navbar-dropdown">

+ 8 - 7
src/main/resources/templates/enact.html

@@ -23,7 +23,7 @@
           <div class="field has-addons">
             <div class="control is-expanded">
               <div class="select is-fullwidth">
-                <select id="activities" name="activity" th:onchange="'window.location.href = \'' + @{/inarts} + '?iri=\' + encodeURIComponent(this.value) ' ">
+                <select id="activities" name="iri" th:onchange="'window.location.href = \'' + @{/inarts} + '?iri=\' + encodeURIComponent(this.value) ' ">
                   <option th:value="1">Select Activity</option>
                   <option th:each="act: ${session.acts}" th:selected="${act.iri == current}" th:value="${act.iri}" th:text="${act.name}"></option>
                 </select>
@@ -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.act.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.act.name}"></span></p>
-          <p><strong>Port: </strong><span class="accent">[[${ev.relatesTo.activity.name}]]</span></p>
+          <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 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>
 
@@ -77,8 +77,9 @@
             <div class="content">
               <p>
                 <strong th:text="${art.relatesTo.name}"></strong> <small th:text="${art.relatesTo.type}"></small>
-                <br>
-                <a th:href="@{|${storageURL}/files/file/${art.location}|}">Download</a>
+                <br>                
+                <a th:if="${art.fileExtension == 'xopp' || art.fileExtension == 'csv' || art.fileExtension == 'drawio'}" th:href="@{|${storageURL}/files/${art.fileExtension}/${art.location}|}">Download</a>
+                <a th:if="${art.fileExtension != null && art.fileExtension != 'xopp' && art.fileExtension != 'csv' && art.fileExtension != 'drawio'}" th:href="@{|${storageURL}/files/file/${art.location}|}">Download</a>                
               </p>
             </div>
           </div>

+ 4 - 4
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.act.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.act.name}"></span></p>
-          <p><strong>Port: </strong><span class="accent">[[${ev.relatesTo.activity.name}]]</span></p>
+          <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 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>

+ 15 - 24
src/main/resources/templates/endEnactment.html

@@ -5,30 +5,21 @@
 </head>
 <body>
 <main>
-  <h1>Wee: Workflow Enactment Engine</h1>
-  <div>
-    <h3 th:inline="text">Enactment of the Process Model: [[${session.pm.name}]] has ended!</h3>
-    <a th:href="@{/}"> HOME </a>
-  </div>
-  <div>
-    <h3 th:inline="text">Trace: [[${session.trace.name}]] </h3>
-    <h4 th:inline="text">Started at: [[${session.trace.timestampF}]] </h4>
-    <table>
-      <th:block th:each="ev : ${session.trace.events}">
-        <tr>
-          <td th:if="${ev.class.name == 'ua.be.wee.model.pt.StartActivityEvent'}">begin:</td>
-          <td th:if="${ev.class.name == 'ua.be.wee.model.pt.EndActivityEvent'}">end:</td>
-          <td colspan="2" th:if="${ev.class.name != 'ua.be.wee.model.pt.EndTraceEvent'}" th:text="${ev.relatesTo.activity.name}">...</td>
-          <td th:if="${ev.class.name == 'ua.be.wee.model.pt.EndTraceEvent'}">End of Trace at:</td>
-          <td colspan="2" th:if="${ev.class.name == 'ua.be.wee.model.pt.EndTraceEvent'}" th:text="${ev.timestampF}">...</td>
-        </tr>
-        <tr th:if="${ev.class.name != 'ua.be.wee.model.pt.EndTraceEvent'}">
-          <td colspan="2">port:</td>
-          <td>[[${ev.relatesTo.name}]]</td>
-        </tr>
-      </th:block>
-    </table>
-  </div>
+  <section class="pt-6 pb-6 pl-5 pr-5">
+    <h2 class="is-size-3 is-capitalized">Workflow Enactment Engine</h2>
+    <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.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.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.EndActivityEvent' || ev.class.name == 'ua.be.wee.model.pt.StartActivityEvent'}">port: [[${ev.relatesTo.name}]]</p>
+    </th:block>
+  </section>
 </main>
 </body>
 </html>

+ 13 - 0
src/main/resources/templates/error.html

@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<body>
+<center>
+<h1>Sorry, WEE have weeed and something went wrong </h1>
+<img id="img" class="wee-meme-image" src="../static/img/slip-and-fall.png" th:src="@{/img/slip-and-fall.png}" alt="Logo of person slipping">
+<h2>Let us know about it and we will try to fix ASAP </h2>
+<a href="/" >
+<img id="home" src="../static/img/home-button.png" th:src="@{/img/home-button.png}" alt="Home icon"> 
+</a>
+</center>
+</body>
+</html>

+ 2 - 1
src/main/resources/templates/index.html

@@ -7,7 +7,8 @@
 <main>
   <section class="pt-6 pb-6 pl-5 pr-5">
     <h2 class="is-size-3 is-capitalized">Welcome to Wee!</h2>
-    <img class="wee-meme-image" src="../static/img/wee.png" th:src="@{/img/wee.png}" alt="Logo of person slipping"><!--  https://thenounproject.com/icon/slipping-11426/  -->
+    <audio id="audio" src="/audio/Wee.mp3"></audio>
+    <img id="img" value="PLAY" onclick="play()" class="wee-meme-image" src="../static/img/wee.png" th:src="@{/img/wee.png}" alt="Logo of person slipping"><!--  https://thenounproject.com/icon/slipping-11426/  -->
     <p>If you want to see wee memes click <a href="https://www.instagram.com/weee.memes/">here!</a></p>
     <p>Otherwise, please, indicate the url of your endpoint and let's start enacting your workflow!</p>
     <form class="pt-3" th:action="@{/pm}" method="post">

+ 19 - 4
src/main/resources/templates/pms.html

@@ -12,16 +12,31 @@
       <div class="field has-addons">
         <div class="control is-expanded">
           <div class="select is-fullwidth">
-            <select id="dropDownList" name="pmiri">
-              <option value="Select PM">select PM</option>
-              <option th:each="pm: ${pms}" th:value="${pm.iri}" th:text="${pm}"></option>
+            <select id="dropDownList" name="pmiri" th:onchange="'window.location.href = \'' + @{/gettraces} + '?iri=\' + encodeURIComponent(this.value) ' ">
+              <option th:value="1">select PM</option>
+              <option th:each="pm: ${pms}" th:value="${pm.iri}" th:text="${pm}" th:selected="${pm.iri == current}"></option>
             </select>
           </div>
         </div>
         <div class="control">
-          <button type="submit" class="button is-primary">Start Enactment</button>
+          <button type="submit" class="button is-primary" name="action" value="new" >New Enactment</button>
         </div>
+        
       </div>
+      
+       <div class="field has-addons" th:if="${traces != null}">
+          <p class="is-size-6">Continue enactment:</p>
+           <div class="select is-fullwidth">
+          <select id="dropDownList" name="contTrace">
+              <option value="Select Trace">select trace</option>
+              <option th:each="trace: ${traces}" th:value="${trace.iri}" th:text="${trace.name} + ' started at ' + ${trace.timestampF}"></option>
+          </select>
+          </div>
+          <div class="control">
+          	<button type="submit" class="button is-primary" name="action" value="continue">Continue Enactment</button>
+      	  </div>    
+       </div>
+      
     </form>
   </section>
 </main>

+ 48 - 0
tasks.py

@@ -0,0 +1,48 @@
+from pathlib import Path
+from invoke import task
+import xml.etree.ElementTree as ET
+
+
+@task
+def release(c, version):
+    """"""
+    if version not in ["minor", "major", "patch"]:
+        print("Version can be either major, minor or patch.")
+        return
+
+    ns = {"maven": "http://maven.apache.org/POM/4.0.0"}
+    tree = ET.ElementTree(ET.fromstring(Path("pom.xml").read_text()))
+    version_node = tree.find("./maven:version", ns)
+    __version__ = version_node.text
+    __version_info__ = tuple((int(num) if num.isdigit() else num for num in __version__.replace("-", ".", 1).split(".")))
+    _major, _minor, _patch = __version_info__
+
+    if version == "patch":
+        _patch = _patch + 1
+    elif version == "minor":
+        _minor = _minor + 1
+        _patch = 0
+    elif version == "major":
+        _major = _major + 1
+        _minor = 0
+        _patch = 0
+
+    c.run(f"git checkout -b release-{_major}.{_minor}.{_patch} dev")
+    #     This pollutes the xml file, we'll just use sed
+    #     version_node.text = f"{_major}.{_minor}.{_patch}"
+    #     tree.write("pom.xml", ns)
+    c.run(f"sed -i '0,/<version>{__version__}/ s/<version>{__version__}/<version>{_major}.{_minor}.{_patch}/g' pom.xml")
+    print(f"Update the readme for version {_major}.{_minor}.{_patch}.")
+    input("Press enter when ready.")
+    c.run(f"git add -u")
+    c.run(f'git commit -m "Update changelog version {_major}.{_minor}.{_patch}"')
+    c.run(f"git push --set-upstream origin release-{_major}.{_minor}.{_patch}")
+    c.run(f"git checkout main")
+    c.run(f"git merge --no-ff release-{_major}.{_minor}.{_patch}")
+    c.run(f'git tag -a {_major}.{_minor}.{_patch} -m "Release {_major}.{_minor}.{_patch}"')
+    c.run(f"git push")
+    c.run(f"git checkout dev")
+    c.run(f"git merge --no-ff release-{_major}.{_minor}.{_patch}")
+    c.run(f"git push")
+    c.run(f"git branch -d release-{_major}.{_minor}.{_patch}")
+    c.run(f"git push origin --tags")