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 <smxml> 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 <state> 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.