Author: ate
Date: Sat Mar 29 19:53:53 2014
New Revision: 1583057

URL: http://svn.apache.org/r1583057
Log:
SCXML-200: NotificationRegistry cannot (and should not) be Serializable as it 
hold on to external SCXMLListener instances.
It also holds on to SCXML Observable which may be serialized and deserialized, 
which would make break the internal references.
To fix this, instead we'll 'register' only the newly added Integer 
Observable.getOservableId(), which is a generated unique id within the context 
of an SCXML document.
Also, fix / improve the SimpleTransition.getTransitionDomain() to be inline 
with the current SCXML specification

Modified:
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/NotificationRegistry.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/DocumentOrder.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Observable.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SCXML.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SimpleTransition.java
    
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/TransitionTarget.java

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/NotificationRegistry.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/NotificationRegistry.java?rev=1583057&r1=1583056&r2=1583057&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/NotificationRegistry.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/NotificationRegistry.java
 Sat Mar 29 19:53:53 2014
@@ -16,8 +16,6 @@
  */
 package org.apache.commons.scxml2;
 
-import java.io.Serializable;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
@@ -37,23 +35,18 @@ import org.apache.commons.scxml2.model.T
  * listeners of the events that interest them.
  *
  */
-public final class NotificationRegistry implements Serializable {
+public final class NotificationRegistry {
 
     /**
-     * Serial version UID.
+     * The Map of all listeners keyed by {@link Observable#getObservableId()}.
      */
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * The Map of all listeners keyed by Observable.
-     */
-    private final Map<Observable, Set<SCXMLListener>> regs;
+    private final Map<Integer, Set<SCXMLListener>> regs;
 
     /**
      * Constructor.
      */
     public NotificationRegistry() {
-        this.regs = Collections.synchronizedMap(new HashMap<Observable, 
Set<SCXMLListener>>());
+        this.regs = new HashMap<Integer, Set<SCXMLListener>>();
     }
 
     /**
@@ -63,12 +56,14 @@ public final class NotificationRegistry 
      * @param lst The listener
      */
     synchronized void addListener(final Observable source, final SCXMLListener 
lst) {
-        Set<SCXMLListener> entries = regs.get(source);
-        if (entries == null) {
-            entries = new LinkedHashSet<SCXMLListener>();
-            regs.put(source, entries);
+        if (source != null && source.getObservableId() != null) {
+            Set<SCXMLListener> entries = regs.get(source.getObservableId());
+            if (entries == null) {
+                entries = new LinkedHashSet<SCXMLListener>();
+                regs.put(source.getObservableId(), entries);
+            }
+            entries.add(lst);
         }
-        entries.add(lst);
     }
 
     /**
@@ -78,11 +73,13 @@ public final class NotificationRegistry 
      * @param lst The listener
      */
     synchronized void removeListener(final Observable source, final 
SCXMLListener lst) {
-        Set<SCXMLListener> entries = regs.get(source);
-        if (entries != null) {
-            entries.remove(lst);
-            if (entries.size() == 0) {
-                regs.remove(source);
+        if (source != null && source.getObservableId() != null) {
+            Set<SCXMLListener> entries = regs.get(source.getObservableId());
+            if (entries != null) {
+                entries.remove(lst);
+                if (entries.size() == 0) {
+                    regs.remove(source.getObservableId());
+                }
             }
         }
     }
@@ -96,10 +93,12 @@ public final class NotificationRegistry 
      */
     public synchronized void fireOnEntry(final Observable source,
             final EnterableState state) {
-        Set<SCXMLListener> entries = regs.get(source);
-        if (entries != null) {
-            for (SCXMLListener lst : entries) {
-                lst.onEntry(state);
+        if (source != null && source.getObservableId() != null) {
+            Set<SCXMLListener> entries = regs.get(source.getObservableId());
+            if (entries != null) {
+                for (SCXMLListener lst : entries) {
+                    lst.onEntry(state);
+                }
             }
         }
     }
@@ -113,10 +112,12 @@ public final class NotificationRegistry 
      */
     public synchronized void fireOnExit(final Observable source,
             final EnterableState state) {
-        Set<SCXMLListener> entries = regs.get(source);
-        if (entries != null) {
-            for (SCXMLListener lst : entries) {
-                lst.onExit(state);
+        if (source != null && source.getObservableId() != null) {
+            Set<SCXMLListener> entries = regs.get(source.getObservableId());
+            if (entries != null) {
+                for (SCXMLListener lst : entries) {
+                    lst.onExit(state);
+                }
             }
         }
     }
@@ -132,13 +133,14 @@ public final class NotificationRegistry 
     public synchronized void fireOnTransition(final Observable source,
             final TransitionTarget from, final TransitionTarget to,
             final Transition transition) {
-        Set<SCXMLListener> entries = regs.get(source);
-        if (entries != null) {
-            for (SCXMLListener lst : entries) {
-                lst.onTransition(from, to, transition);
+        if (source != null && source.getObservableId() != null) {
+            Set<SCXMLListener> entries = regs.get(source.getObservableId());
+            if (entries != null) {
+                for (SCXMLListener lst : entries) {
+                    lst.onTransition(from, to, transition);
+                }
             }
         }
     }
-
 }
 

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java?rev=1583057&r1=1583056&r2=1583057&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/TriggerEvent.java
 Sat Mar 29 19:53:53 2014
@@ -41,7 +41,7 @@ public class TriggerEvent implements Ser
     public TriggerEvent(final String name, final int type,
             final Object payload) {
         super();
-        this.name = name;
+        this.name = name != null ? name.trim() : "";
         this.type = type;
         this.payload = payload;
     }

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java?rev=1583057&r1=1583056&r2=1583057&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/ModelUpdater.java
 Sat Mar 29 19:53:53 2014
@@ -152,7 +152,7 @@ final class ModelUpdater {
      * @throws ModelException If the object model is flawed
      */
     static void updateSCXML(final SCXML scxml) throws ModelException {
-        initDocumentOrder(scxml.getChildren(), 0);
+        initDocumentOrder(scxml.getChildren(), 1);
 
         String initial = scxml.getInitial();
         SimpleTransition initialTransition = new SimpleTransition();
@@ -182,16 +182,25 @@ final class ModelUpdater {
                 updateParallel((Parallel) es, targets);
             }
         }
+
+        scxml.getInitialTransition().setObservableId(1);
+        initObservables(scxml.getChildren(), 2);
     }
 
-    private static int initDocumentOrder(final List<EnterableState> states, 
final int currentOrder) {
-        int nextOrder = currentOrder;
+    /**
+     * Initialize all {@link org.apache.commons.scxml2.model.DocumentOrder} 
instances (EnterableState or Transition)
+     * by iterating them in document order setting their document order value.
+     * @param states The list of children states of a parent TransitionalState 
or the SCXML document itself
+     * @param nextOrder The next to be used order value
+     * @return Returns the next to be used order value
+     */
+    private static int initDocumentOrder(final List<EnterableState> states, 
int nextOrder) {
         for (EnterableState state : states) {
-            state.setOrder(++nextOrder);
+            state.setOrder(nextOrder++);
             if (state instanceof TransitionalState) {
                 TransitionalState ts = (TransitionalState)state;
                 for (Transition t : ts.getTransitionsList()) {
-                    t.setOrder(++nextOrder);
+                    t.setOrder(nextOrder++);
                 }
                 nextOrder = initDocumentOrder(ts.getChildren(), nextOrder);
             }
@@ -200,6 +209,39 @@ final class ModelUpdater {
     }
 
     /**
+     * Initialize all {@link org.apache.commons.scxml2.model.Observable} 
instances in the SCXML document
+     * by iterating them in document order and seeding them with a unique 
obeservable id.
+     * @param states The list of children states of a parent TransitionalState 
or the SCXML document itself
+     * @param nextObservableId The next observable id sequence value to be used
+     * @return Returns the next to be used observable id sequence value
+     */
+    private static int initObservables(final List<EnterableState>states, int 
nextObservableId) {
+        for (EnterableState es : states) {
+            es.setObservableId(nextObservableId++);
+            if (es instanceof TransitionalState) {
+                TransitionalState ts = (TransitionalState)es;
+                if (ts instanceof State) {
+                    State s = (State)ts;
+                    if (s.getInitial() != null && 
s.getInitial().getTransition() != null) {
+                        
s.getInitial().getTransition().setObservableId(nextObservableId++);
+                    }
+                }
+                for (Transition t : ts.getTransitionsList()) {
+                    t.setObservableId(nextObservableId++);
+                }
+                for (History h : ts.getHistory()) {
+                    h.setObservableId(nextObservableId++);
+                    if (h.getTransition() != null) {
+                        h.getTransition().setObservableId(nextObservableId++);
+                    }
+                }
+                nextObservableId = initObservables(ts.getChildren(), 
nextObservableId);
+            }
+        }
+        return nextObservableId;
+    }
+
+    /**
      * Update this State object (part of post-read processing).
      * Also checks for any errors in the document.
      *

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/DocumentOrder.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/DocumentOrder.java?rev=1583057&r1=1583056&r2=1583057&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/DocumentOrder.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/DocumentOrder.java
 Sat Mar 29 19:53:53 2014
@@ -25,7 +25,7 @@ import java.util.Comparator;
  *   They are ordered with ancestor states before their descendant states,
  *   and the transitions within a state in document order before any 
descendant states.
  * </p>
- * <p>Note: it is assumed there will be no more than Intger.MAX_VALUE of such 
elements in a single SCXML document</p>
+ * <p>Note: it is assumed there will be no more than Integer.MAX_VALUE of such 
elements in a single SCXML document</p>
  */
 public interface DocumentOrder {
 

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Observable.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Observable.java?rev=1583057&r1=1583056&r2=1583057&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Observable.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/Observable.java
 Sat Mar 29 19:53:53 2014
@@ -17,12 +17,18 @@
 package org.apache.commons.scxml2.model;
 
 /**
- * Marker interface to flag elements of the SCXML object model whose progress
+ * Interface for elements of the SCXML object model whose progress
  * can be observed using the {@link 
org.apache.commons.scxml2.NotificationRegistry}. These include
- * individual {@link TransitionTarget}s, {@link Transition}s or entire state
- * machines, {@link SCXML}.
+ * individual {@link TransitionTarget}s, {@link Transition}s or the entire 
state
+ * machine {@link SCXML}.
  *
+ * <p>Note: it is assumed there will be no more than Integer.MAX_VALUE of such 
elements in a single SCXML document</p>
  */
 public interface Observable {
+
+    /**
+     * @return Returns the id for this Observable which is unique within the 
SCXML state machine
+     */
+    Integer getObservableId();
 }
 

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SCXML.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SCXML.java?rev=1583057&r1=1583056&r2=1583057&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SCXML.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SCXML.java
 Sat Mar 29 19:53:53 2014
@@ -39,6 +39,7 @@ public class SCXML implements Serializab
     /**
      * The SCXML XMLNS.
      */
+    @SuppressWarnings("unused")
     public static final String XMLNS = "http://www.w3.org/2005/07/scxml";;
 
     /**
@@ -47,6 +48,16 @@ public class SCXML implements Serializab
     public static final String GENERATED_TT_ID_PREFIX = "_generated_tt_id_";
 
     /**
+     * The pseudo SCXML {@link SimpleTransition#getTransitionDomain()}
+     */
+    public static final TransitionalState SCXML_TRANSITION_DOMAIN = new 
TransitionalState(){};
+
+    /**
+     * The predefined observableId with value 0 (zero) for this SCXML state 
machine
+     */
+    private static final Integer SCXML_OBSERVABLE_ID = 0;
+
+    /**
      * The xmlns attribute on the root &lt;smxml&gt; element.
      * This must match XMLNS above.
      */
@@ -115,7 +126,6 @@ public class SCXML implements Serializab
      * The next auto-generated transition target unique id value
      * @see #generateTransitionTargetId()
      */
-
     private long ttNextId;
 
     /**
@@ -127,6 +137,13 @@ public class SCXML implements Serializab
     }
 
     /**
+     * {@inheritDoc}
+     */
+    public final Integer getObservableId() {
+        return SCXML_OBSERVABLE_ID;
+    }
+
+    /**
      * Simple unique TransitionTarget id value generation
      * @return a unique TransitionTarget id for this SCXML instance
      */

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SimpleTransition.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SimpleTransition.java?rev=1583057&r1=1583056&r2=1583057&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SimpleTransition.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/SimpleTransition.java
 Sat Mar 29 19:53:53 2014
@@ -17,7 +17,6 @@
 package org.apache.commons.scxml2.model;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -30,34 +29,25 @@ import java.util.Map;
 public class SimpleTransition extends Executable
         implements NamespacePrefixesHolder, Observable {
 
-    private static final State SCXML_TRANSITION_DOMAIN = new State(){};
-
     /**
      * Serial version UID.
      */
     private static final long serialVersionUID = 2L;
 
     /**
+     * The id for this {@link Observable} which is unique within the SCXML 
state machine
+     */
+    private Integer observableId;
+
+    /**
      * The Transition type: internal or external (default)
-     * @see {@link #isTypeInternal()}
+     * @see #isTypeInternal()
      */
     private TransitionType type;
 
     /**
-     * The transition parent itself, or a compound state parent, or null
-     * <p>
-     * If the transition has no targets, its TransitionalState (State or 
Parallel) parent represents its own transition
-     * domain.
-     * </p>
-     * <p>
-     * If the transition has targets then the transition domain is the 
compound State parent such that:
-     * <ul>
-     *   <li>all states that are exited or entered as a result of taking this 
transition are descendants of it</li>
-     *   <li>no descendant of it has this property</li>
-     * </ul>
-     * If there is no such compound State parent, the transition domain 
effectively becomes the SCXML document itself,
-     * which is indicated by a null (empty) transitionDomain.
-     * </p>
+     * The transition domain for this transition.
+     * @see #getTransitionDomain()
      */
     private TransitionalState transitionDomain;
 
@@ -107,6 +97,21 @@ public class SimpleTransition extends Ex
     }
 
     /**
+     * {@inheritDoc}
+     */
+    public final Integer getObservableId() {
+        return observableId;
+    }
+
+    /**
+     * Sets the observableId for this Observable, which must be unique within 
the SCXML state machine
+     * @param observableId the observableId
+     */
+    public final void setObservableId(Integer observableId) {
+        this.observableId = observableId;
+    }
+
+    /**
      * Get the TransitionalState (State or Parallel) parent.
      *
      * @return Returns the parent.
@@ -183,11 +188,7 @@ public class SimpleTransition extends Ex
     /**
      * Returns the transition domain of this transition
      * <p>
-     * The returned transition domain is either the transition parent itself, 
or a compound state parent, or null
-     * </p>
-     * <p>
-     * If the transition has no targets, its TransitionalState (State or 
Parallel) parent represents its own transition
-     * domain.
+     * If this transition is target-less, null is returned.
      * </p>
      * <p>
      * If the transition has targets then the transition domain is the 
compound State parent such that:
@@ -195,20 +196,17 @@ public class SimpleTransition extends Ex
      *   <li>all states that are exited or entered as a result of taking this 
transition are descendants of it</li>
      *   <li>no descendant of it has this property</li>
      * </ul>
-     * If there is no such compound State parent, the transition domain 
effectively becomes the SCXML document itself,
-     * which is indicated by a null (empty) transitionDomain.
+     * If there is no such compound state parent, the transition domain 
effectively becomes the SCXML document itself,
+     * which is indicated by the returned pseudo {@link 
SCXML#SCXML_TRANSITION_DOMAIN} transitionDomain.
      * </p>
      *
      * @return The transition domain of this transition
      */
     public TransitionalState getTransitionDomain() {
-        if (transitionDomain == null) {
+        if (transitionDomain == null && targets.size() > 0) {
 
-            if (getParent() == null) {
-                transitionDomain = SCXML_TRANSITION_DOMAIN;
-            }
-            else {
-                if (targets.size() == 0 || isTypeInternal()) {
+            if (getParent() != null) {
+                if (isTypeInternal()) {
                     transitionDomain = getParent();
                 }
                 else {
@@ -234,12 +232,12 @@ public class SimpleTransition extends Ex
                         }
                     }
                 }
-                if (transitionDomain == null) {
-                    transitionDomain = SCXML_TRANSITION_DOMAIN;
-                }
+            }
+            if (transitionDomain == null) {
+                transitionDomain = SCXML.SCXML_TRANSITION_DOMAIN;
             }
         }
-        return transitionDomain == SCXML_TRANSITION_DOMAIN ? null : 
transitionDomain;
+        return transitionDomain;
     }
 
     /**

Modified: 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/TransitionTarget.java
URL: 
http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/TransitionTarget.java?rev=1583057&r1=1583056&r2=1583057&view=diff
==============================================================================
--- 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/TransitionTarget.java
 (original)
+++ 
commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/model/TransitionTarget.java
 Sat Mar 29 19:53:53 2014
@@ -28,6 +28,11 @@ public abstract class TransitionTarget i
     private static final EnterableState[] ZERO_ANCESTORS = new 
EnterableState[0];
 
     /**
+     * The id for this {@link Observable} which is unique within the SCXML 
state machine
+     */
+    private Integer observableId;
+
+    /**
      * Identifier for this transition target. Other parts of the SCXML
      * document may refer to this &lt;state&gt; using this ID.
      */
@@ -50,6 +55,21 @@ public abstract class TransitionTarget i
     }
 
     /**
+     * {@inheritDoc}
+     */
+    public final Integer getObservableId() {
+        return observableId;
+    }
+
+    /**
+     * Sets the observableId for this Observable, which must be unique within 
the SCXML state machine
+     * @param observableId the observableId
+     */
+    public final void setObservableId(Integer observableId) {
+        this.observableId = observableId;
+    }
+
+    /**
      * Get the identifier for this transition target (may be null).
      *
      * @return Returns the id.


Reply via email to