diff --git a/build.gradle b/build.gradle index e32107d9d22970405636c285cfc8b905fac5b899..242490466bc0d44269cfd9db0457df8da7a84293 100644 --- a/build.gradle +++ b/build.gradle @@ -141,11 +141,11 @@ jar { } task fatJar(type: Jar) { - dependsOn jar group = "build" archiveAppendix = "fatjar" from sourceSets.main.output + from sourceSets.main.allSource from { configurations.runtimeClasspath.collect {it.isDirectory() ? it : zipTree(it) } } diff --git a/src/main/jastadd/engine/balloonMarking/BalloonExecution.jadd b/src/main/jastadd/engine/balloonMarking/BalloonExecution.jadd index 32df0c72edf68516c8177e871f691bb7b8999f05..38d668233419f979dd0f41a65268e5d384079cea 100644 --- a/src/main/jastadd/engine/balloonMarking/BalloonExecution.jadd +++ b/src/main/jastadd/engine/balloonMarking/BalloonExecution.jadd @@ -119,9 +119,9 @@ aspect BalloonExecution{ } } - if(node.isServerInstancePlace(place)){ - connectedResServerPlace = true; - connectedResServerPlaceId = place.getId(); + if(node.isServerInstancePlace(place.getId())){ + connectedResServerPlace = true; + connectedResServerPlaceId = place.getId(); } BalloonMarkedPlace bmp=this.resolveBalloonPlace(place); @@ -176,13 +176,6 @@ aspect BalloonExecution{ return storage; } - syn PetriNet PetriNet.registerHandler(String transitionId, int priority, Function<List<Map<String, Object>>, List<Map<String, Object>>> processTokenFunction){ - - TransitionHandlerService ths = TransitionHandlerService.getInstance(); - ths.registerHandler(this, transitionId, priority, processTokenFunction); - return this; - } - syn BalloonCallbackStorage BalloonCallbackStorage.initializePageCallbackStorage(Page page, PetriNet petriNet, boolean requireFlush) { for (PnObject pnObject : page.getObjects()) { diff --git a/src/main/java/de/tudresden/inf/st/pnml/engine/Main.java b/src/main/java/de/tudresden/inf/st/pnml/engine/Main.java index 763e621cd298ca21cd221dac9e79c3995c78f0a4..3c289d70882d7b30feb73318b7a6afb54d907590 100644 --- a/src/main/java/de/tudresden/inf/st/pnml/engine/Main.java +++ b/src/main/java/de/tudresden/inf/st/pnml/engine/Main.java @@ -1,6 +1,37 @@ package de.tudresden.inf.st.pnml.engine; +import de.tudresden.inf.st.pnml.engine.example.Client; +import de.tudresden.inf.st.pnml.engine.example.Server; +import org.ros.node.DefaultNodeMainExecutor; +import org.ros.node.NodeConfiguration; +import org.ros.node.NodeMainExecutor; + +import java.net.URI; + public class Main { - public static void main(java.lang.String[] args) {} + private static final String ROS_HOST = "localhost"; + private static final String ROS_MASTER_URI = "http://localhost:11311"; + + private static final NodeConfiguration nodeConfiguration = NodeConfiguration.newPublic(ROS_HOST); + private static final NodeMainExecutor nodeMainExecutor = DefaultNodeMainExecutor.newDefault(); + + public static void main(java.lang.String[] args) { + + Server server = new Server(); + Client client = new Client(); + nodeConfiguration.setMasterUri(URI.create(ROS_MASTER_URI)); + + /*System.out.println("---- STARTING SERVER ----"); + new Thread(() -> nodeMainExecutor.execute(server, nodeConfiguration)) {{start();}}; + + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + }*/ + + System.out.println("---- STARTING CLIENT ----"); + new Thread(() -> nodeMainExecutor.execute(client, nodeConfiguration)) {{start();}}; + } } diff --git a/src/main/java/de/tudresden/inf/st/pnml/engine/example/Client.java b/src/main/java/de/tudresden/inf/st/pnml/engine/example/Client.java index 28b2d78ece492dd92acd1babc433ce582e791476..754b0fc349588e8a2fbbe3e0be852f55f0bb6bbe 100644 --- a/src/main/java/de/tudresden/inf/st/pnml/engine/example/Client.java +++ b/src/main/java/de/tudresden/inf/st/pnml/engine/example/Client.java @@ -36,12 +36,13 @@ public class Client extends AbstractNodeMain { } final StringServiceRequest request = serviceClient.newMessage(); - request.setInput("(1) Hello there!"); + //request.setInput("(1) Hello there!"); + request.setInput("{color:\"blue\",pickPlaceSuccess:false}"); - serviceClient.call(request, new ServiceResponseListener<StringServiceResponse>() { + serviceClient.call(request, new ServiceResponseListener<>() { @Override public void onSuccess(StringServiceResponse response) { - System.out.println(String.format("(1) The response is : " + response.getOutput())); + System.out.println("(1) The response is : " + response.getOutput()); } @Override diff --git a/src/main/java/de/tudresden/inf/st/pnml/engine/execution/TransitionHandler.java b/src/main/java/de/tudresden/inf/st/pnml/engine/execution/TransitionHandler.java index b7af8f682441889ed8fdd3f15af49017e76ca973..5697bd3c03adacd4d3a3bf9fd5d2d068519d24f5 100644 --- a/src/main/java/de/tudresden/inf/st/pnml/engine/execution/TransitionHandler.java +++ b/src/main/java/de/tudresden/inf/st/pnml/engine/execution/TransitionHandler.java @@ -39,7 +39,7 @@ public class TransitionHandler { private Map<String, Object> parseToken(String s) { Gson gson = new GsonBuilder().create(); - Type mapType = new TypeToken<Map<Integer, Object>>(){}.getType(); + Type mapType = new TypeToken<Map<String, Object>>(){}.getType(); return gson.fromJson(s, mapType); } diff --git a/src/main/java/de/tudresden/inf/st/pnml/engine/execution/TransitionHandlerExecutor.java b/src/main/java/de/tudresden/inf/st/pnml/engine/execution/TransitionHandlerExecutor.java index 2884e36637be00ed286ff60830561b6725fb1e4b..d19c4126feba60141996bde8a1048fd0a52eae03 100644 --- a/src/main/java/de/tudresden/inf/st/pnml/engine/execution/TransitionHandlerExecutor.java +++ b/src/main/java/de/tudresden/inf/st/pnml/engine/execution/TransitionHandlerExecutor.java @@ -5,7 +5,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -16,30 +15,28 @@ public class TransitionHandlerExecutor { protected static final Logger logger = LoggerFactory.getLogger(TransitionHandlerExecutor.class); - public static final BalloonToken execute(List<BalloonToken> inTokens, List<TransitionHandler> callbacks){ + public static BalloonToken execute(List<BalloonToken> inTokens, List<TransitionHandler> callbacks){ - List<TransitionHandler> callbacksSorted = new ArrayList<>(); - List<BalloonToken> outTokens = new ArrayList<>(); - outTokens.addAll(inTokens); - callbacksSorted.addAll(callbacks); + List<BalloonToken> outTokens = new ArrayList<>(inTokens); + List<TransitionHandler> callbacksSorted = new ArrayList<>(callbacks); - Collections.sort(callbacksSorted, Comparator.comparingInt(TransitionHandler::getPriority)); + callbacksSorted.sort(Comparator.comparingInt(TransitionHandler::getPriority)); for(int i = 0; i < callbacksSorted.size(); i++){ if(i < callbacksSorted.size() - 1){ outTokens = callbacksSorted.get(i).processToken(outTokens); } else { - BalloonToken tb = (BalloonToken) callbacksSorted.get(i).processToken(outTokens).get(0); + BalloonToken tb = callbacksSorted.get(i).processToken(outTokens).get(0); outTokens = new ArrayList<>(); outTokens.add(tb); } } if(outTokens.size() != 1){ - logger.error("Error! Wrong output token size."); + logger.error("[TransitionHandlerExecutor] Error! Wrong output token size."); } - logger.info("Created new output token: " + outTokens.get(0)); + logger.info("[TransitionHandlerExecutor] Created new output token: " + outTokens.get(0)); return outTokens.get(0); } diff --git a/src/main/java/de/tudresden/inf/st/pnml/engine/ros/DiNeRosNode.java b/src/main/java/de/tudresden/inf/st/pnml/engine/ros/DiNeRosNode.java index ef9086e940c94506c03d56c58735133c129f36b7..96280b4d4038eb7a3d22c859b3700ad62e4ca230 100644 --- a/src/main/java/de/tudresden/inf/st/pnml/engine/ros/DiNeRosNode.java +++ b/src/main/java/de/tudresden/inf/st/pnml/engine/ros/DiNeRosNode.java @@ -4,6 +4,7 @@ import de.tudresden.inf.st.pnml.base.constants.PnmlConstants; import de.tudresden.inf.st.pnml.base.data.ClauseValuesDefinition; import de.tudresden.inf.st.pnml.engine.event.DiNeRosEvent; import de.tudresden.inf.st.pnml.engine.event.DiNeRosEventTypes; +import de.tudresden.inf.st.pnml.engine.execution.TransitionHandler; import de.tudresden.inf.st.pnml.engine.transform.PetriNetInitializer; import de.tudresden.inf.st.pnml.engine.transform.ServiceInstanceUtil; import de.tudresden.inf.st.pnml.jastadd.model.*; @@ -28,6 +29,7 @@ import std_msgs.String; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.util.*; +import java.util.function.Function; public abstract class DiNeRosNode extends AbstractNodeMain { @@ -39,9 +41,8 @@ public abstract class DiNeRosNode extends AbstractNodeMain { protected InputSignalConnector inputSignalConnector = new InputSignalConnector(); private boolean stopNode = false; - private final Map<DinerosPlace, Subscriber> dinerosSubscribers = new HashMap<>(); private final Map<DinerosPlace, Publisher<String>> dinerosPublishers = new HashMap<>(); - private final Map<java.lang.String, java.lang.String> responsePlaceToInstance = new HashMap<>(); + private final Set<java.lang.String> responsePlaces = new HashSet<>(); private final Set<java.lang.String> activeServerInstances = new HashSet<>(); public DiNeRosNode(java.lang.String nodeName, PetriNet petriNet, java.lang.String rcHost, java.lang.String gcProtocol) { @@ -57,6 +58,15 @@ public abstract class DiNeRosNode extends AbstractNodeMain { } } + public void registerHandler(java.lang.String transitionId, int priority, + Function<List<Map<java.lang.String, Object>>, + List<Map<java.lang.String, Object>>> processTokenFunction) { + + TransitionHandler transitionHandler = new TransitionHandler(priority, processTokenFunction); + BalloonTransition balloonTransition = callbackStorage.resolveBalloonTransition(petriNet.getTransitionById(transitionId)); + balloonTransition.getTransitionHandlers().add(transitionHandler); + } + public DiNeRosNode(java.lang.String nodeName, PetriNet petriNet, BalloonMarking marking, BalloonCallbackStorage callbackStorage, InputSignalConnector inputSignalConnector) { this.nodeName = nodeName; @@ -128,9 +138,9 @@ public abstract class DiNeRosNode extends AbstractNodeMain { private void onServiceResponseAvailableOnServerSide(java.lang.String placeId) { - for(Map.Entry<java.lang.String, java.lang.String> entry : responsePlaceToInstance.entrySet()){ - if(entry.getKey().equals(placeId)){ - activeServerInstances.remove(entry.getValue()); + for (java.lang.String entry : responsePlaces) { + if (entry.equals(placeId)) { + activeServerInstances.remove(entry); return; } } @@ -212,7 +222,9 @@ public abstract class DiNeRosNode extends AbstractNodeMain { private void getTransitionSelectionResult(TransitionSelectionResult res) { - if(res.isFiringSelectionNone()){ return; } + if (res.isFiringSelectionNone()) { + return; + } if (res.isFiringSelectionFail()) { System.err.println("[DiNeROS-Node] [" + nodeName + "] Firing selection action failed!"); @@ -256,20 +268,105 @@ public abstract class DiNeRosNode extends AbstractNodeMain { this.connectedNode = connectedNode; - System.out.println("[INIT NODE] Initializing node: " + nodeName); + System.out.println("[" + nodeName + "] Initializing node"); + System.out.println("[" + nodeName + "] Setting Default Names for Objects"); + setDefaultNames(); + System.out.println("[" + nodeName + "] Initializing servers"); // init service servers mechanism // is a 1:1 mapping, because there is always just on server HashMap<java.lang.String, ArrayList<java.lang.String>> channelServerReqElementMap = petriNet.getChannelElemensByKey(PnmlConstants.CHANNEL_PLACE_TYPE_SERVER_REQ_KEY); for (java.lang.String key : channelServerReqElementMap.keySet()) { - connectedNode.newServiceServer(key, StringService._TYPE, + for (Page p : petriNet.allPages()) { + if (p.getServiceName() != null && p.getServiceName().equals(key)) { + // service names are unique so we basically have a 1:1 mapping + int limit = petriNet.getChannelElementLimitById(channelServerReqElementMap.get(key).get(0)); + + for (int i = 0; i < limit; i++) { + + System.out.println("[" + nodeName + "] Copying server page " + key + "(" + i + ")."); + Page copy = p.treeCopy(); + ServiceInstanceUtil.updateInstanceIds(copy, "-INSTANCE-" + i); + copy.setId(p.getId() + "-INSTANCE-" + i); + copy.getName().setText(copy.getId()); + ServiceInstanceUtil.updateArcs(copy, "-INSTANCE-" + i); + + petriNet.addPage(copy); + + try { + System.out.println("[" + nodeName + "] --> Initializing BalloonMarking for " + copy.getId()); + marking.initializePageBalloonMarking(copy, false); + System.out.println("[" + nodeName + "] --> Initializing CallbackStorage for " + copy.getId()); + callbackStorage.initializePageCallbackStorage(copy, petriNet, false); + System.out.println("[" + nodeName + "] --> Finished Initialization CallbackStorage for " + copy.getId()); + } catch (IOException | ParserConfigurationException | SAXException e) { + e.printStackTrace(); + } + } + + petriNet.flushTreeCache(); + petriNet.flushAttrAndCollectionCache(); + + HashMap<java.lang.String, ArrayList<java.lang.String>> channelServerResElementMap + = petriNet.getChannelElemensByKey(PnmlConstants.CHANNEL_PLACE_TYPE_SERVER_RES_KEY); + + for (java.lang.String resKey : channelServerResElementMap.keySet()) { + for (int i = 0; i < limit; i++) { + responsePlaces.add(channelServerResElementMap.get(resKey).get(0) + "-INSTANCE-" + i); + } + } + + connectedNode.newServiceServer(key, StringService._TYPE, + (ServiceResponseBuilder<StringServiceRequest, StringServiceResponse>) (request, response) -> { + + System.out.println("[" + nodeName + "] Assigning instance to request on service " + key); + java.lang.String selectedInstanceId = null; + while(selectedInstanceId == null) { + synchronized (this) { + for (int i = 0; i < limit; i++) { + java.lang.String iterInstanceId = + channelServerReqElementMap.get(key).get(0) + "-INSTANCE-" + i; + if (!activeServerInstances.contains(iterInstanceId)) { + selectedInstanceId = iterInstanceId; + activeServerInstances.add(iterInstanceId); + break; + } + } + } + } + + System.out.println("[" + nodeName + "] Inserting request in " + selectedInstanceId); + Place instanceEntryPlace = petriNet.getPlaceById(selectedInstanceId); + marking.resolveBalloonPlace(instanceEntryPlace).addBalloonMarking( + new BalloonToken(request.getInput(), System.currentTimeMillis())); + this.notify(new DiNeRosEvent(DiNeRosEventTypes.NOTIFICATION_MARKING_CHANGE)); + + while(activeServerInstances.contains(selectedInstanceId)){} + System.out.println("[" + nodeName + "] Instance " + selectedInstanceId + " is ready to return"); + + for(java.lang.String entry : responsePlaces){ + if(entry.equals(selectedInstanceId)){ + // set response value based on output token + response.setOutput(marking.resolveBalloonPlace(petriNet. + getPlaceById(entry)).getBalloonMarking(0).getValue()); + break; + } + } + }); + break; + } + } + + /* connectedNode.newServiceServer(key, StringService._TYPE, (ServiceResponseBuilder<StringServiceRequest, StringServiceResponse>) (request, response) -> { java.lang.String instanceId = UUID.randomUUID().toString().replace("-", ""); Page copy = null; + System.out.println("[" + nodeName + "] Copying server page."); + // create a suffixed deep copy for (Page p : petriNet.allPages()) { if (p.getServiceName() != null && p.getServiceName().equals(key)) { @@ -278,12 +375,16 @@ public abstract class DiNeRosNode extends AbstractNodeMain { copy.setId(p.getId() + "-INSTANCE-" + instanceId); copy.getName().setText(copy.getId()); petriNet.addPage(copy); - petriNet.flushTreeCache(); - petriNet.flushCollectionCache(); + // petriNet.flushTreeCache(); + // petriNet.flushCollectionCache(); try { - marking.initializePageBalloonMarking(copy, true); - callbackStorage.initializePageCallbackStorage(copy, petriNet, true); + System.out.println("[" + nodeName + "] Initializing BalloonMarking for " + copy.getId()); + marking.initializePageBalloonMarking(copy, false); + System.out.println("[" + nodeName + "] Initializing CallbackStorage for " + copy.getId()); + callbackStorage.initializePageCallbackStorage(copy, petriNet, false); + petriNet.flushCollectionCache(); + System.out.println("[" + nodeName + "] Finished Initialization CallbackStorage for " + copy.getId()); } catch (IOException | ParserConfigurationException | SAXException e) { e.printStackTrace(); } @@ -291,8 +392,10 @@ public abstract class DiNeRosNode extends AbstractNodeMain { } } + // HashMap<java.lang.String, ArrayList<java.lang.String>> channelServerResElementMap + // = petriNet.getChannelElemensByKey(PnmlConstants.CHANNEL_PLACE_TYPE_SERVER_RES_KEY); HashMap<java.lang.String, ArrayList<java.lang.String>> channelServerResElementMap - = petriNet.getChannelElemensByKey(PnmlConstants.CHANNEL_PLACE_TYPE_SERVER_RES_KEY); + = petriNet.getChannelElemensByKey(PnmlConstants.CHANNEL_PLACE_TYPE_SERVER_REQ_KEY); for (java.lang.String resKey : channelServerResElementMap.keySet()) { if (resKey.equals(key)) { @@ -302,7 +405,8 @@ public abstract class DiNeRosNode extends AbstractNodeMain { activeServerInstances.add(instanceId); Place instanceEntryPlace = petriNet.getPlaceById(channelServerResElementMap. get(resKey).get(0) + "-INSTANCE-" + instanceId); - marking.resolveBalloonPlace(instanceEntryPlace).addBalloonMarking(new BalloonToken(request.getInput(), System.currentTimeMillis())); + marking.resolveBalloonPlace(instanceEntryPlace).addBalloonMarking( + new BalloonToken(request.getInput(), System.currentTimeMillis())); this.notify(new DiNeRosEvent(DiNeRosEventTypes.NOTIFICATION_MARKING_CHANGE)); break; } @@ -320,26 +424,30 @@ public abstract class DiNeRosNode extends AbstractNodeMain { } try { + assert copy != null; marking.deinitializePage(copy, callbackStorage); } catch (IOException | SAXException | ParserConfigurationException e) { e.printStackTrace(); } ServiceInstanceUtil.removeServiceServerInstance(petriNet, key + "-INSTANCE-" + instanceId); - }); + });*/ } // init publishers + System.out.println("[" + nodeName + "] Initializing publishers"); HashMap<java.lang.String, ArrayList<java.lang.String>> channelPubElementMap = petriNet.getChannelElemensByKey(PnmlConstants.CHANNEL_PLACE_TYPE_PUB_KEY); for (java.lang.String key : channelPubElementMap.keySet()) { for (java.lang.String placeId : channelPubElementMap.get(key)) { + System.out.println("[" + nodeName + "] Initializing publisher on " + placeId); final Publisher<String> publisher = connectedNode.newPublisher(key, String._TYPE); dinerosPublishers.put(petriNet.getPlaceById(placeId).asDinerosPlace(), publisher); } } // init subscribers + System.out.println("[" + nodeName + "] Initializing subscribers"); HashMap<java.lang.String, ArrayList<java.lang.String>> channelSubElementMap = petriNet.getChannelElemensByKey(PnmlConstants.CHANNEL_PLACE_TYPE_SUB_KEY); @@ -353,6 +461,7 @@ public abstract class DiNeRosNode extends AbstractNodeMain { BalloonToken bt = new BalloonToken(); bt.setValue(message.getData()); + bt.setCreationTime(System.currentTimeMillis()); BalloonMarkedPlace bmp = marking.resolveBalloonPlace(targetPlace); bmp.getBalloonMarkingList().add(bt); @@ -360,16 +469,27 @@ public abstract class DiNeRosNode extends AbstractNodeMain { this.notify(new DiNeRosEvent(DiNeRosEventTypes.NOTIFICATION_MARKING_CHANGE)); }, petriNet.getChannelElementLimitById(placeId)); - - dinerosSubscribers.put(targetPlace, subscriber); + //dinerosSubscribers.put(targetPlace, subscriber); } } - System.out.println("[INIT NODE] Executing first marking query."); + System.out.println("[" + nodeName + "] Executing first marking query."); this.notify(new DiNeRosEvent(DiNeRosEventTypes.NOTIFICATION_STARTUP_ENDED)); this.internalNodeLoop(); } + private void setDefaultNames() { + for (PnObject pnObject : petriNet.allObjects()) { + if (!pnObject.hasName()) { + Name name = new Name(); + name.setText(pnObject.getId()); + pnObject.setName(name); + } + } + + petriNet.flushTreeCache(); + } + public Publisher<String> getPublisherByPlaceId(java.lang.String placeId) { for (DinerosPlace dp : dinerosPublishers.keySet()) { if (dp.getId().equals(placeId)) { @@ -386,7 +506,7 @@ public abstract class DiNeRosNode extends AbstractNodeMain { return fsc; } - public boolean isServerInstancePlace(Place place) { - return responsePlaceToInstance.containsKey(place); + public boolean isServerInstancePlace(java.lang.String placeId) { + return responsePlaces.contains(placeId); } } \ No newline at end of file diff --git a/src/main/java/de/tudresden/inf/st/pnml/engine/transform/ServiceInstanceUtil.java b/src/main/java/de/tudresden/inf/st/pnml/engine/transform/ServiceInstanceUtil.java index 76bca0ff90b4dd29106f7fe3697cdfcee3864cec..1962fe222602a2beae2eaa5b17a80ef06ecd12df 100644 --- a/src/main/java/de/tudresden/inf/st/pnml/engine/transform/ServiceInstanceUtil.java +++ b/src/main/java/de/tudresden/inf/st/pnml/engine/transform/ServiceInstanceUtil.java @@ -8,7 +8,14 @@ public class ServiceInstanceUtil { for(PnObject pnObject : page.getObjects()){ pnObject.setId(pnObject.getId() + suffix); - pnObject.getName().setText(pnObject.getId()); + + if(pnObject.hasName()){ + Name name = new Name(); + name.setText(pnObject.getId()); + pnObject.setName(name); + } else { + pnObject.getName().setText(pnObject.getId()); + } if(pnObject.isPageNode()){ updateInstanceIds(pnObject.asPage(), suffix); @@ -16,6 +23,31 @@ public class ServiceInstanceUtil { } } + public static void updateArcs(Page page, String suffix){ + + for(PnObject pnObject : page.getObjects()){ + + if(pnObject.isArcNode()){ + for(PnObject pnObjectIn : page.getObjects()){ + if(pnObjectIn.isPlaceObject() && + pnObjectIn.asDinerosPlace().getId() + .equals(pnObject.asArc().getSource().getId() + suffix)){ + pnObject.asArc().setSource(pnObjectIn.asNode()); + } + if(pnObjectIn.isPlaceObject() && + pnObjectIn.asDinerosPlace().getId() + .equals(pnObject.asArc().getTarget().getId() + suffix)){ + pnObject.asArc().setTarget(pnObjectIn.asNode()); + } + } + } + + if(pnObject.isPageNode()){ + updateArcs(pnObject.asPage(), suffix); + } + } + } + public static void removeServiceServerInstance(PetriNet petriNet, String pageId){ for(Page page : petriNet.allPages()){