Просмотр исходного кода

Adding support to upload files for artifacts in ending events.

Lucas Albertins 2 лет назад
Родитель
Сommit
fabf422e61

+ 54 - 3
src/main/java/ua/be/wee/controller/EnactementControllerMVC.java

@@ -6,6 +6,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.Part;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -27,6 +28,7 @@ import ua.be.wee.model.pm.PM;
 import ua.be.wee.model.pt.Event;
 import ua.be.wee.model.pt.PT;
 import ua.be.wee.model.repository.FusekiWrapper;
+import ua.be.wee.service.FileStorageService;
 
 @Controller
 @RequestMapping("/")
@@ -36,6 +38,9 @@ public class EnactementControllerMVC {
   
 	@Autowired
 	private Environment env;
+	
+	@Autowired
+	FileStorageService storageService;
 
     @Value("${base_url}")
     private String baseUrl;
@@ -47,8 +52,7 @@ public class EnactementControllerMVC {
 
     @RequestMapping("/")
     public String index(Model model) throws FileNotFoundException, IOException {
-    	
-		if (!env.getProperty("endpoint").equals("")) {
+    	if (!env.getProperty("endpoint").equals("")) {
 			model.addAttribute("savedEndpoint", env.getProperty("endpoint"));
 			model.addAttribute("hasEndpoint", true);
 		} else {
@@ -147,6 +151,53 @@ public class EnactementControllerMVC {
     	
     	controller.addEndEvent(pt,act,arts,p);
     	endacts.remove(act);
+ 
+    	
+    	request.getSession().setAttribute("trace", pt);
+    	request.getSession().setAttribute("previous", p.getIri());
+		model.addAttribute("arts", null);
+		model.addAttribute("current", "1");
+    	return "enact";
+    }
+    
+    @PostMapping("/endActArt")
+    public String endActivityWithArtifacts(Model model, @RequestParam String port, @RequestParam String activity, HttpServletRequest request) throws Exception {
+    	PM pm = (PM)request.getSession().getAttribute("pm");
+    	List<Node> acts = (List<Node>)request.getSession().getAttribute("acts");
+    	List<Node> endacts = (List<Node>)request.getSession().getAttribute("endacts");
+    	PT pt = (PT)request.getSession().getAttribute("trace");
+    	Activity act = (Activity)pm.getNode(activity);
+    	List<ControlOutputPort> ctrlOutPorts = act.getCtrlOutPorts();
+    	ControlOutputPort p = null;
+    	for (ControlOutputPort out : ctrlOutPorts) {
+    		if (out.getIri().equals(port)) {
+				p = out;
+				break;
+			}
+		}
+    	
+    	List<Artifact> arts = act.getOutputs();
+    	for (Artifact artifact : arts) {
+    		ArrayList<Part> parts = (ArrayList<Part>)request.getParts();
+    		for (Part part : parts) {
+				if (part.getName().equals(artifact.getName())) {
+					artifact.setLocation(part.getSubmittedFileName());
+					artifact.setTag("v1"); //TODO fix the tag generation
+					artifact.setGUID(part.getSubmittedFileName()+"-" +artifact.getTag());
+					storageService.save(part);
+				}
+			}  
+		}
+    	
+    	List<String> iris = controller.findNextNodes(p.getIri());
+		for (String iri : iris) {
+			acts.add(pm.getNode(iri));
+		}
+    	
+    	controller.addEndEvent(pt,act,arts,p);
+    	endacts.remove(act);
+    	
+    	
     	
     	request.getSession().setAttribute("trace", pt);
     	request.getSession().setAttribute("previous", p.getIri());
@@ -162,7 +213,7 @@ public class EnactementControllerMVC {
         	if (pm.getNode(iri) instanceof Activity) {
         		Activity act = (Activity)pm.getNode(iri);
             	model.addAttribute("act", pm.getNode(iri));
-            	model.addAttribute("arts", act.getOutputs() == null ? (new ArrayList<Artifact>()) : act.getOutputs());
+            	model.addAttribute("arts", act.getOutputs());
 			} else { 
 				model.addAttribute("endBool", true);
 			}

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

@@ -37,8 +37,8 @@ public class EnactmentController {
 		return pm;
 	}
 
-	public List<String> findNextNodes(String initialNode) {
-		return pmRepo.findNextNodes(initialNode); 
+	public List<String> findNextNodes(String iri) {
+		return pmRepo.findNextNodes(iri); 
 	}
 
 	public PT createTrace(PM pm) throws Exception {

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

@@ -1,5 +1,6 @@
 package ua.be.wee.model.nodes;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import ua.be.wee.model.nodes.ports.ControlInputPort;
@@ -22,6 +23,11 @@ public class Activity extends Node {
 	private List<DataInputPort> datalInPorts;
 	
 	private String transformationName;
+	
+	public Activity() {
+		inputs = new ArrayList<Artifact>();
+		outputs = new ArrayList<Artifact>();
+	}
 
 	public List<Artifact> getInputs() {
 		return inputs;
@@ -78,6 +84,18 @@ public class Activity extends Node {
 	public void setDatalInPorts(List<DataInputPort> datalInPorts) {
 		this.datalInPorts = datalInPorts;
 	}
+	
+	public void addInputArtifact(Artifact art) {
+		if (inputs != null) {
+			inputs.add(art);
+		}
+	}
+	
+	public void addOutputArtifact(Artifact art) {
+		if (outputs != null) {
+			outputs.add(art);
+		}
+	}
 
 	
 

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

@@ -4,6 +4,12 @@ public class Artifact extends Node {
 	
 	private String type;
 
+	private String location;
+	
+	private String tag;
+	
+	private String GUID;
+
 	public String getType() {
 		return type;
 	}
@@ -12,4 +18,31 @@ public class Artifact extends Node {
 		this.type = type;
 	}
 
+	public String getLocation() {
+		return location;
+	}
+
+	public void setLocation(String location) {
+		this.location = location;
+	}
+
+	public String getTag() {
+		return tag;
+	}
+
+	public void setTag(String tag) {
+		this.tag = tag;
+	}
+
+	public String getGUID() {
+		return GUID;
+	}
+
+	public void setGUID(String gUID) {
+		GUID = gUID;
+	}
+	
+	
+	
+
 }

+ 60 - 9
src/main/java/ua/be/wee/model/nodes/NodeRespository.java

@@ -42,11 +42,56 @@ public class NodeRespository {
 			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()) {
@@ -73,19 +118,25 @@ public class NodeRespository {
 	}
 	
 	private Node createArtifact(String iri) {
-		Artifact act = new Artifact();
+		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"
-				+ "SELECT ?act ?name WHERE {\n"
-				+ "	?act owl:sameAs <" + iri + ">;\n"
-				+ "   		pm:hasName ?name .  \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");
-		act.setIri(iri);
-		act.setName(name.toString());
-		return act;
+		RDFNode type = soln.get("?typename");
+		art.setIri(iri);
+		art.setName(name.toString());
+		art.setType(type.toString());
+		
+		return art;
 	}
 
 	private Node createActivity(String iri) {
@@ -128,7 +179,7 @@ public class NodeRespository {
 			DataOutputPort cout = new DataOutputPort();
 			cout.setIri(iri.toString());
 			cout.setName(name.toString());
-			cout.setAct(act);
+			cout.setActivity(act);
 			list.add(cout);
 		}
 		return list;
@@ -152,7 +203,7 @@ public class NodeRespository {
 			DataInputPort cout = new DataInputPort();
 			cout.setIri(iri.toString());
 			cout.setName(name.toString());
-			cout.setAct(act);
+			cout.setActivity(act);
 			list.add(cout);
 		}
 		return list;

+ 3 - 2
src/main/java/ua/be/wee/model/nodes/ports/DataInputPort.java

@@ -3,13 +3,14 @@ package ua.be.wee.model.nodes.ports;
 import ua.be.wee.model.nodes.Activity;
 
 public class DataInputPort extends Port {
+	
 	private Activity act;
 
-	public Activity getAct() {
+	public Activity getActivity() {
 		return act;
 	}
 
-	public void setAct(Activity act) {
+	public void setActivity(Activity act) {
 		this.act = act;
 	}
 }

+ 3 - 2
src/main/java/ua/be/wee/model/nodes/ports/DataOutputPort.java

@@ -5,11 +5,12 @@ import ua.be.wee.model.nodes.Activity;
 public class DataOutputPort extends Port {
 	private Activity act;
 
-	public Activity getAct() {
+	public Activity getActivity() {
 		return act;
 	}
 
-	public void setAct(Activity act) {
+	public void setActivity(Activity act) {
 		this.act = act;
 	}
+	
 }

+ 1 - 2
src/main/java/ua/be/wee/model/pm/PM.java

@@ -1,6 +1,5 @@
 package ua.be.wee.model.pm;
 
-import java.util.Iterator;
 import java.util.List;
 
 import javax.persistence.ElementCollection;
@@ -65,6 +64,6 @@ public class PM {
 			}
 		}
 		return null;
-	}	
+	}
 
 }

+ 48 - 13
src/main/java/ua/be/wee/model/pt/PTRepository.java

@@ -21,10 +21,10 @@ public class PTRepository {
 		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/base/processtraces#>\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/processtraces#Event> , <http://ua.be/sdo2l/vocabulary/base/processtraces#StartTraceEvent> , owl:Thing , <http://ua.be/sdo2l/vocabulary/base/acyclic#element> , <http://ua.be/sdo2l/vocabulary/base/processtraces#element> ;\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"
 				+ "}";
@@ -43,7 +43,7 @@ public class PTRepository {
 	
 	private int getNextIndex(PM pm) {
 		int index = 0;
-		String query = "PREFIX tr: <http://ua.be/sdo2l/vocabulary/base/processtraces#>\n"
+		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"
@@ -65,11 +65,11 @@ public class PTRepository {
 		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/base/processtraces#>\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/base/processtraces#StartActivityEvent> , <http://ua.be/sdo2l/vocabulary/base/processtraces#element> , <http://ua.be/sdo2l/vocabulary/base/processtraces#Event> , owl:Thing , <http://ua.be/sdo2l/vocabulary/base/acyclic#element> ;\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"
@@ -96,7 +96,7 @@ public class PTRepository {
 		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/base/processtraces#>\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"
@@ -106,7 +106,7 @@ public class PTRepository {
 				+ "  ?pt ?p ?v .\n"
 				+ "};\n"
 				+ "INSERT DATA {\n"
-				+ "	<" + pt.getIri() + "> rdf:type    <http://ua.be/sdo2l/vocabulary/base/processtraces#Event> , <http://ua.be/sdo2l/vocabulary/base/processtraces#StartTraceEvent> , owl:Thing , <http://ua.be/sdo2l/vocabulary/base/acyclic#element> , <http://ua.be/sdo2l/vocabulary/base/processtraces#element> ;\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"
@@ -137,16 +137,49 @@ public class PTRepository {
 		String startiri = pt.getIri().replace('#', '/') + "#" + "start_activity" + index;
 		String endiri = pt.getIri().replace('#', '/') + "#" + "end_activity" + index;
 		
+		List<String> artifactsIRI = new ArrayList<String>();
+		for (Artifact art : arts) {
+			String artifactIRI = pt.getIri().replace('#', '/') + "#" + art.getGUID();
+			artifactsIRI.add(artifactIRI);
+			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"
+					+ " <" + artifactIRI + "> rdf:type base:Versionable , pt:Artifact , owl:Thing , pt:element , base:ImmutableThing ;\n"
+					+ "        base:hasGUID \"" + art.getGUID() + "\" ;\n"
+					+ "        base:hasTag \"" + art.getTag() + "\" ;\n"
+					+ "        pt:hasLocation \"" + art.getLocation() + "\" ;\n"
+					//+ "        pt:isConsumedBy <http://ua.be/sdo2l/description/traces/my_pt#start_activity1> ;\n"
+					//+ "        pt:isModel <http://ua.be/sdo2l/description/artifacts/my_xopp#model> ;\n"
+					+ "        pt:isProducedBy <" + endiri + "> ;\n"
+					+ "        pt:relatesTo <" + art.getIri() + "> ;\n"
+					+ "        owl:sameAs  <" + artifactIRI + "> .\n"
+					+ "}";
+			if (FusekiWrapper.getInstance().updateQuery(query) ) {
+				artifactsIRI.add(artifactIRI);
+			} else {
+				throw new Exception("Error inserting data.");
+			}
+			
+		}
+		
+	
 		String query = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
-				+ "PREFIX tr: <http://ua.be/sdo2l/vocabulary/base/processtraces#>\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/base/processtraces#StartActivityEvent> , <http://ua.be/sdo2l/vocabulary/base/processtraces#element> , <http://ua.be/sdo2l/vocabulary/base/processtraces#Event> , owl:Thing , <http://ua.be/sdo2l/vocabulary/base/acyclic#element> ;\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"
-				+ "    owl:sameAs <" + endiri + "> .\n"
+				+ "    tr:relatesTo <" + p.getIri() + "> ;\n";
+				
+		for (String iri : artifactsIRI) {
+			query += "    tr:produces <" + iri + "> ;\n" ;
+		}
+		query += "    owl:sameAs <" + endiri + "> .\n"
 				+ "}";
+		
 		if (FusekiWrapper.getInstance().updateQuery(query) ) {
 			EndActivityEvent ev = new EndActivityEvent();
 			ev.setIri(endiri);
@@ -157,15 +190,17 @@ public class PTRepository {
 			throw new Exception("Error inserting data.");
 		}
 		
+		
+		
 	}
 	
 	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/base/processtraces#>\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/base/processtraces#EndTraceEvent> , <http://ua.be/sdo2l/vocabulary/base/processtraces#Event> , <http://ua.be/sdo2l/vocabulary/base/processtraces#element> , owl:Thing ;\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"

+ 32 - 0
src/main/java/ua/be/wee/model/util/Pair.java

@@ -0,0 +1,32 @@
+package ua.be.wee.model.util;
+
+public class Pair<U,V> {
+	
+	private U fst;
+	public U getFst() {
+		return fst;
+	}
+
+	public void setFst(U fst) {
+		this.fst = fst;
+	}
+
+	public V getSnd() {
+		return snd;
+	}
+
+	public void setSnd(V snd) {
+		this.snd = snd;
+	}
+
+	private V snd;
+	
+	public Pair(U fst, V snd) {
+		this.fst = fst;
+		this.snd = snd;
+	}
+	
+	
+	
+
+}

+ 22 - 0
src/main/java/ua/be/wee/service/FileStorageService.java

@@ -0,0 +1,22 @@
+package ua.be.wee.service;
+
+import java.nio.file.Path;
+import java.util.stream.Stream;
+
+import javax.servlet.http.Part;
+
+import org.springframework.core.io.Resource;
+
+public interface FileStorageService {
+  public void init();
+
+  public void save(Part file);
+
+  public Resource load(String filename);
+
+  public boolean delete(String filename);
+  
+  public void deleteAll();
+
+  public Stream<Path> loadAll();
+}

+ 129 - 0
src/main/java/ua/be/wee/service/FileStorageServiceImpl.java

@@ -0,0 +1,129 @@
+package ua.be.wee.service;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Stream;
+
+import javax.servlet.http.Part;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.BasicResponseHandler;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.stereotype.Service;
+import org.springframework.util.FileSystemUtils;
+
+@Service
+public class FileStorageServiceImpl implements FileStorageService {
+	private final Path root = Paths.get("./uploads");
+
+	private String storageServiceURL;
+	
+	
+	@Autowired
+	private Environment env;
+
+	@Override
+	public void init() {
+		try {
+			//Files.createDirectories(root);
+			storageServiceURL = env.getProperty("storageURL");
+		} catch (Exception e) {
+			throw new RuntimeException("Could not get property storageURL from application.properties file!");
+		}
+	}
+
+	@Override
+	public void save(Part file) {
+		try {
+			if (storageServiceURL == null) {
+				init();
+			}
+			//Files.copy(file.getInputStream(), this.root.resolve(file.getOriginalFilename()));
+			String url = "";
+			String filename = file.getSubmittedFileName();
+			switch (filename.substring(filename.lastIndexOf('.'))) {
+			case ".xopp":
+				url = storageServiceURL + "/files/xopp/"+filename;				
+				break;
+			case ".csv":
+				url = storageServiceURL +"/files/csv/"+filename;				
+				break;
+			case ".drawio":
+				url = storageServiceURL + "/files/drawio/"+filename;				
+				break;
+			default:
+				url = storageServiceURL + "/files/file/"+filename; 
+				break;
+			}
+			
+			CloseableHttpClient httpclient = HttpClients.createDefault();
+
+			HttpPut httpPut = new HttpPut(url);
+			
+			// specify the PUT body to send to the server as part of the request
+			httpPut.setEntity(new StringEntity(file.getInputStream().toString()));
+
+			HttpResponse response = httpclient.execute(httpPut);
+
+			String responseBody = new BasicResponseHandler().handleResponse(response);			
+			
+		} catch (Exception e) {
+			if (e instanceof FileAlreadyExistsException) {
+				throw new RuntimeException("A file of that name already exists.");
+			}
+
+			throw new RuntimeException(e.getMessage());
+		}
+	}
+
+	@Override
+	public Resource load(String filename) {
+		try {
+			Path file = root.resolve(filename);
+			Resource resource = new UrlResource(file.toUri());
+
+			if (resource.exists() || resource.isReadable()) {
+				return resource;
+			} else {
+				throw new RuntimeException("Could not read the file!");
+			}
+		} catch (MalformedURLException e) {
+			throw new RuntimeException("Error: " + e.getMessage());
+		}
+	}
+
+	@Override
+	public boolean delete(String filename) {
+		try {
+			Path file = root.resolve(filename);
+			return Files.deleteIfExists(file);
+		} catch (IOException e) {
+			throw new RuntimeException("Error: " + e.getMessage());
+		}
+	}
+
+	@Override
+	public void deleteAll() {
+		FileSystemUtils.deleteRecursively(root.toFile());
+	}
+
+	@Override
+	public Stream<Path> loadAll() {
+		try {
+			return Files.walk(this.root, 1).filter(path -> !path.equals(this.root)).map(this.root::relativize);
+		} catch (IOException e) {
+			throw new RuntimeException("Could not load the files!");
+		}
+	}
+}

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

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

+ 33 - 3
src/main/resources/templates/enactEnd.html

@@ -29,7 +29,7 @@
 		.button1:hover {
 		  background-color: #5e9ca0;
 		  color: white;
-		}		
+		}
 	</style>
 	<script type="text/javascript">
 	function showDiv(select){
@@ -51,8 +51,17 @@
 <div style="float:left;width:50%;" >
 
 <h3 style="color: #5e9ca0;" th:inline="text">Enacting the Process Model: [[${session.pm.name}]] </h3>
+
+<div id="formArts" th:if="${arts.size > 0}" >
+	<form id="formA" th:action="@{/endActArt}" method="post" enctype="multipart/form-data" >	
+</div>
+
+<div id="formNoArts" th:if="${arts.size == 0}" >
+	<form id="formNoA"  th:action="@{/endAct}" method="post" >	
+</div>
 	
-<form th:action="@{/endAct}" method="post">	
+
+
 <table>
 
     <tr >
@@ -70,7 +79,28 @@
 <div id="hidden_div" style="display:none;" > 
 
 <table th:if="${arts != null && arts.size > 0}">
-	<tr> <td > Artifacts </td> </tr>
+	<tr> <th colspan="2"  style="padding: 20px; border-bottom: 1px solid red;" ><h3 style="color: #5e9ca0;"> Artifacts </h3></th> </tr>
+	
+	
+	<th:block th:each="art : ${arts}">
+    
+    <tr>
+        <td style="color: #5e9ca0;font-weight: bold;" > Artifact Name:</td>
+        <td style="color: #5e9ca0;" th:text="${art.name}">...</td>
+    </tr>
+    <tr>
+        <td style="color: #5e9ca0;font-weight: bold;" > Type:</td>
+        <td style="color: #5e9ca0;" th:text="${art.type}" > </td>
+    </tr>
+    
+    <tr>
+        <td colspan="2" style="color: #5e9ca0;font-weight: bold; padding: 20px;
+    		border-bottom: 1px solid red;"  > <input id="input-file-${art.name}" type="file" th:name="${art.name}" /> </td>
+
+    </tr>
+    
+  </th:block>
+	
 </table>
 <input class="button button1" type="submit" value="End Activity"/>