Sfoglia il codice sorgente

added disassociate event

Simon Van Mierlo 8 anni fa
parent
commit
5f74db0d0f

+ 70 - 43
src/javascript_sccd_runtime/statecharts_core.js

@@ -197,6 +197,8 @@ ObjectManagerBase.prototype.handleEvent = function(e) {
 		this.handleCreateEvent(e.parameters);
 	} else if (e.name === "associate_instance") {
 		this.handleAssociateEvent(e.parameters);
+	} else if (e.name === "disassociate_instance") {
+		this.handleDisassociateEvent(e.parameters);
 	} else if (e.name === "start_instance") {
 		this.handleStartInstanceEvent(e.parameters);
 	} else if (e.name === "delete_instance") {
@@ -240,40 +242,7 @@ ObjectManagerBase.prototype.handleStartInstanceEvent = function(parameters) {
 		if (!instances.hasOwnProperty(i)) continue;
 		instances[i].instance.start();
 	}
-};
-
-ObjectManagerBase.prototype.handleDeleteInstanceEvent = function(parameters) {
-	if (parameters.length !== 2) {
-		throw new ParameterException("The delete instance event needs 2 parameters.");
-	}
-	var source = parameters[0];
-	var traversal_list = this.processAssociationReference(parameters[1]);
-	var instances = this.getInstances(source, traversal_list);
-	for (var i in instances) {
-		if (!instances.hasOwnProperty(i)) continue;
-		instances[i].instance.stop();
-		instances[i].instance.user_defined_destructor();
-		// delete association from source instance
-		var association_to_remove = instances[i].ref.associations[instances[i].assoc_name];
-		if (instances[i].assoc_index === -1) {
-			/*for (var x in association_to_remove.instances) {
-				if (!association_to_remove.instances.hasOwnProperty(x)) continue;
-				association_to_remove.instances = new Object();
-				//association_to_remove.instances[x] = null;
-			}*/
-			// empty instances object
-			association_to_remove.instances = new Object();
-			//association_to_remove.instances = new Array();
-		} else {
-			//association_to_remove.instances[instances[i].assoc_index] = null;
-			// remove property from instances object
-			delete association_to_remove.instances[instances[i].assoc_index];
-		}
-		// also remove instance from OM's list of instances
-		index = this.instances.indexOf(instances[i].instance);
-		this.instances.splice(index,1);
-	}
-	source.addEvent(new Event("instance_deleted", undefined, [parameters[1]]));
+    source.addEvent(new Event("instance_started", undefined, [parameters[1]]))
 };
 
 ObjectManagerBase.prototype.handleBroadcastEvent = function(parameters) {
@@ -323,6 +292,40 @@ ObjectManagerBase.prototype.handleCreateEvent = function(parameters) {
 	}
 };
 
+ObjectManagerBase.prototype.handleDeleteInstanceEvent = function(parameters) {
+	if (parameters.length !== 2) {
+		throw new ParameterException("The delete instance event needs 2 parameters.");
+	}
+	var source = parameters[0];
+	var traversal_list = this.processAssociationReference(parameters[1]);
+	var instances = this.getInstances(source, traversal_list);
+	for (var i in instances) {
+		if (!instances.hasOwnProperty(i)) continue;
+		instances[i].instance.stop();
+		instances[i].instance.user_defined_destructor();
+		// delete association from source instance
+		var association_to_remove = instances[i].ref.associations[instances[i].assoc_name];
+		if (instances[i].assoc_index === -1) {
+			/*for (var x in association_to_remove.instances) {
+				if (!association_to_remove.instances.hasOwnProperty(x)) continue;
+				association_to_remove.instances = new Object();
+				//association_to_remove.instances[x] = null;
+			}*/
+			// empty instances object
+			association_to_remove.instances = new Object();
+			//association_to_remove.instances = new Array();
+		} else {
+			//association_to_remove.instances[instances[i].assoc_index] = null;
+			// remove property from instances object
+			delete association_to_remove.instances[instances[i].assoc_index];
+		}
+		// also remove instance from OM's list of instances
+		index = this.instances.indexOf(instances[i].instance);
+		this.instances.splice(index,1);
+	}
+	source.addEvent(new Event("instance_deleted", undefined, [parameters[1]]));
+};
+
 ObjectManagerBase.prototype.handleAssociateEvent = function(parameters) {
 	if (parameters.length !== 3) {
 		throw new ParameterException("The associate_instance event needs 3 parameters.");
@@ -348,6 +351,29 @@ ObjectManagerBase.prototype.handleAssociateEvent = function(parameters) {
 		if (!instances.hasOwnProperty(i)) continue;
 		instances[i].instance.associations[last.name].addInstance(wrapped_to_copy_instance);
 	}
+    source.addEvent(new Event("instance_associated", undefined, [parameters[1], parameters[2]]))
+};
+
+ObjectManagerBase.prototype.handleDisassociateEvent = function(parameters) {
+	if (parameters.length !== 2) {
+		throw new ParameterException("The disassociate event needs 2 parameters.");
+	}
+	var source = parameters[0];
+	var traversal_list = this.processAssociationReference(parameters[1]);
+	var instances = this.getInstances(source, traversal_list);
+	for (var i in instances) {
+		if (!instances.hasOwnProperty(i)) continue;
+		// delete association from source instance
+		var association_to_remove = instances[i].ref.associations[instances[i].assoc_name];
+		if (instances[i].assoc_index === -1) {
+			// empty instances object
+			association_to_remove.instances = new Object();
+		} else {
+			// remove property from instances object
+			delete association_to_remove.instances[instances[i].assoc_index];
+		}
+	}
+	source.addEvent(new Event("instance_disassociated", undefined, [parameters[1]]));
 };
 
 ObjectManagerBase.prototype.handleNarrowCastEvent = function(parameters) {
@@ -691,15 +717,16 @@ StatechartSemantics = {
 
 var DefaultStatechartSemantics = function() {
 	this.big_step_maximality = this.TakeMany;
-	this.concurrency = this.Single
-	this.internal_event_lifeline = this.Queue;
+	this.concurrency = this.Single;
+    this.internal_event_lifeline = this.Queue;
 	this.input_event_lifeline = this.FirstComboStep;
 	this.priority = this.SourceParent;
 };
 
 // State
-function State(state_id, obj) {
+function State(state_id, name, obj) {
     this.state_id = state_id;
+    this.name = name;
     this.obj = obj;
     
     this.ancestors = new Array();
@@ -755,15 +782,15 @@ State.prototype.setExit = function(exit) {
 }
 
 // HistoryState
-function HistoryState(state_id, obj) {
-    State.call(this, state_id, obj);
+function HistoryState(state_id, name, obj) {
+    State.call(this, state_id, name, obj);
 }
 
 HistoryState.prototype = new State();
 
 // ShallowHistoryState
-function ShallowHistoryState(state_id, obj) {
-    HistoryState.call(this, state_id, obj);
+function ShallowHistoryState(state_id, name, obj) {
+    HistoryState.call(this, state_id, name, obj);
 }
 
 ShallowHistoryState.prototype = new HistoryState();
@@ -782,8 +809,8 @@ ShallowHistoryState.prototype.getEffectiveTargetStates = function() {
 }
 
 // DeepHistoryState
-function DeepHistoryState(state_id, obj) {
-    HistoryState.call(this, state_id, obj);
+function DeepHistoryState(state_id, name, obj) {
+    HistoryState.call(this, state_id, name, obj);
 }
 
 DeepHistoryState.prototype = new HistoryState();

+ 23 - 0
src/python_sccd/python_sccd_runtime/statecharts_core.py

@@ -119,6 +119,7 @@ class ObjectManagerBase(object):
                          "broad_cast": self.handleBroadCastEvent,
                          "create_instance": self.handleCreateEvent,
                          "associate_instance": self.handleAssociateEvent,
+                         "disassociate_instance": self.handleDisassociateEvent,
                          "start_instance": self.handleStartInstanceEvent,
                          "delete_instance": self.handleDeleteInstanceEvent}
         
@@ -276,6 +277,28 @@ class ObjectManagerBase(object):
                 
             for i in self.getInstances(source, dest_list):
                 i["instance"].associations[last[0]].addInstance(wrapped_to_copy_instance)
+                
+            source.addEvent(Event("instance_associated", parameters = [parameters[1], parameters[2]]))
+                
+    def handleDisassociateEvent(self, parameters):
+        if len(parameters) < 2:
+            raise ParameterException ("The delete event needs at least 2 parameters.")
+        else:
+            source = parameters[0]
+            association_name = parameters[1]
+            
+            traversal_list = self.processAssociationReference(association_name)
+            instances = self.getInstances(source, traversal_list)
+            # association = self.instances_map[source].getAssociation(traversal_list[0][0])
+            association = source.associations[traversal_list[0][0]]
+            
+            for i in instances:
+                try:
+                    association.removeInstance(i["instance"])
+                except AssociationException as exception:
+                    raise RuntimeException("Error disassociating '" + association_name + "': " + str(exception))
+                
+            source.addEvent(Event("instance_disassociated", parameters = [parameters[1]]))
         
     def handleNarrowCastEvent(self, parameters):
         if len(parameters) != 3:

+ 1 - 0
test/run_tests.html

@@ -45,6 +45,7 @@
 
 <script src="target_js/original_semantics/after.js"></script>
 <script src="target_js/original_semantics/associate_event.js"></script>
+<script src="target_js/original_semantics/disassociate_event.js"></script>
 <script src="target_js/original_semantics/correct_duplicate_state_id.js"></script>
 <script src="target_js/original_semantics/enter_exit_hierarchy.js"></script>
 <script src="target_js/original_semantics/event_consuming.js"></script>

+ 96 - 0
test/src/original_semantics/disassociate_event.xml

@@ -0,0 +1,96 @@
+<?xml version="1.0" ?>
+<diagram author="Glenn De Jonghe" name="TestAssociateEvent">
+    <description>
+        Testing the object manager
+    </description>
+    <inport name="test_input" />
+    <outport name="test_output" />
+    <class name="Class1" default="true">
+        <relationships>
+            <association class="Class2" name="test2_association" />
+			<association class="Class2" name="test3_association" />
+        </relationships>
+        <scxml initial="start">
+            <state id="start">
+                <transition port="test_input" event="create" target="../wait">
+                    <raise scope="cd" event="create_instance">
+                        <parameter expr='"test2_association"'/>
+                    </raise>
+                    <raise port="test_output" event="request_send"/>
+                    
+                </transition>
+            </state>
+
+            <state id="wait">
+                <transition event="instance_created" target="../waiting_for_associate">
+                    <parameter name="association_name" type="string"/>
+                    <raise port="test_output" event="instance_created"/>
+                    <raise scope="cd" event="start_instance">
+	                    <parameter expr='"test2_association"'/>
+	                </raise> 
+					<raise scope="cd" event="associate_instance">
+						<parameter expr='"test2_association"'/>
+						<parameter expr='"test3_association"'/>
+					</raise>
+                </transition>
+            </state>
+            
+            <state id="waiting_for_associate">
+                <transition event="instance_associated" target="../waiting_for_hello">
+                    <raise port="test_output" event="instance_associated"/>
+                    <raise target='"test3_association"' event="hello" />
+                </transition>
+            </state>
+            
+            <state id="waiting_for_hello">
+                <transition target="../waiting_for_disassociate" after="0.01">
+                    <raise scope="cd" event="disassociate_instance">
+                        <parameter expr="'test3_association'" />
+                    </raise>
+                </transition>
+            </state>
+            
+            <state id="waiting_for_disassociate">
+                <transition event="instance_disassociated" target="../done">
+                    <raise port="test_output" event="instance_disassociated"/>
+                    <!-- This should no longer work. -->
+                    <raise scope="narrow" target="'test3_association'" event="hello" />
+                </transition>
+            </state>
+            
+            <state id="done" />
+        </scxml>
+    </class>
+    <class name="Class2" default="false">
+        <scxml>
+            <state id="start">
+            	<log>started</log>
+                <transition event="hello" target=".">
+                    <raise port="test_output" event="second_working" />
+                </transition>
+            </state>
+        </scxml>
+    </class>
+    <test>
+    	<input>
+    		<event name="create" port="test_input" time="0.0"/>
+    	</input>
+       <expected>
+           <slot>
+               <event name="request_send" port="test_output"/>
+           </slot>
+           <slot>
+               <event name="instance_created" port="test_output"/>
+           </slot>
+           <slot>
+               <event name="instance_associated" port="test_output"/>
+           </slot>
+           <slot>
+               <event name="second_working" port="test_output"/>
+           </slot>
+           <slot>
+               <event name="instance_disassociated" port="test_output"/>
+           </slot>
+        </expected>
+    </test>
+</diagram>