Repository: commons-scxml
Updated Branches:
  refs/heads/master b39a4adf6 -> 144d205df


SCXML-266 SCXMLSemantics#matchTransition - code flow bug


Project: http://git-wip-us.apache.org/repos/asf/commons-scxml/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-scxml/commit/144d205d
Tree: http://git-wip-us.apache.org/repos/asf/commons-scxml/tree/144d205d
Diff: http://git-wip-us.apache.org/repos/asf/commons-scxml/diff/144d205d

Branch: refs/heads/master
Commit: 144d205df2fcceacd3898e9d9afe7cbcd5ed8340
Parents: b39a4ad
Author: Ate Douma <[email protected]>
Authored: Sun Dec 10 18:22:22 2017 +0100
Committer: Ate Douma <[email protected]>
Committed: Sun Dec 10 18:22:22 2017 +0100

----------------------------------------------------------------------
 src/changes/changes.xml                         |  4 +
 .../org/apache/commons/scxml2/SCInstance.java   | 24 ++++--
 .../apache/commons/scxml2/io/SCXMLReader.java   | 68 ++++++++++++++-
 .../apache/commons/scxml2/io/SCXMLWriter.java   | 14 +--
 .../org/apache/commons/scxml2/model/Assign.java | 91 ++++++++++++--------
 .../org/apache/commons/scxml2/w3c/tests.xml     |  6 +-
 6 files changed, 154 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/144d205d/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index f3b03ae..3238f53 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -35,6 +35,10 @@
     <release version="2.0" date="In Git master"
       description="Latest unreleased code">
 
+      <action dev="ate" type="add" issue="SCXML-267">
+        [12-10-2017] Support &lt;data&gt; src attribute and &lt;assign&gt; 
inline data
+      </action>
+
       <action dev="ate" type="fix" issue="SCXML-266">
         [12-10-2017] SCXMLSemantics#matchTransition - code flow bug
       </action>

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/144d205d/src/main/java/org/apache/commons/scxml2/SCInstance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/SCInstance.java 
b/src/main/java/org/apache/commons/scxml2/SCInstance.java
index 5fe715f..12d64e1 100644
--- a/src/main/java/org/apache/commons/scxml2/SCInstance.java
+++ b/src/main/java/org/apache/commons/scxml2/SCInstance.java
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.scxml2;
 
+import java.io.IOException;
 import java.io.Serializable;
 import java.util.Collections;
 import java.util.HashMap;
@@ -26,6 +27,7 @@ import java.util.Set;
 import java.util.UUID;
 
 import org.apache.commons.scxml2.env.SimpleContext;
+import org.apache.commons.scxml2.io.ContentParser;
 import org.apache.commons.scxml2.model.Data;
 import org.apache.commons.scxml2.model.Datamodel;
 import org.apache.commons.scxml2.model.EnterableState;
@@ -334,14 +336,24 @@ public class SCInstance implements Serializable {
             }
             Object value = null;
             boolean setValue = false;
-            /*
-            TODO: external data.src support (not yet implemented), including 
late-binding thereof
             // prefer "src" over "expr" over "inline"
             if (datum.getSrc() != null) {
-                ctx.setLocal(datum.getId(), valueNode);
-            } else
-            */
-            if (datum.getExpr() != null) {
+                String resolvedSrc = datum.getSrc();
+                final PathResolver pr = getStateMachine().getPathResolver();
+                if (pr != null) {
+                    resolvedSrc = pr.resolvePath(resolvedSrc);
+                }
+                try {
+                    value = 
ContentParser.DEFAULT_PARSER.parseResource(resolvedSrc);
+                    setValue = true;
+                } catch (IOException e) {
+                    if (internalIOProcessor != null) {
+                        internalIOProcessor.addEvent(new 
EventBuilder(TriggerEvent.ERROR_EXECUTION, TriggerEvent.ERROR_EVENT).build());
+                    }
+                    errorReporter.onError(ErrorConstants.EXECUTION_ERROR, 
e.getMessage(), datum);
+                }
+            }
+            else if (datum.getExpr() != null) {
                 try {
                     ctx.setLocal(Context.NAMESPACES_KEY, 
datum.getNamespaces());
                     value = evaluator.eval(ctx, datum.getExpr());

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/144d205d/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java 
b/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
index c9b0349..d5618d1 100644
--- a/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
+++ b/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
@@ -33,6 +33,7 @@ import java.util.Stack;
 
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.Location;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLReporter;
 import javax.xml.stream.XMLResolver;
@@ -1794,13 +1795,58 @@ public final class SCXMLReader {
         assign.setLocation(readRequiredAV(reader, ELEM_ASSIGN, ATTR_LOCATION));
         assign.setSrc(readAV(reader, ATTR_SRC));
         readNamespaces(configuration, assign);
+        if (assign.getExpr() != null && assign.getSrc() != null) {
+            reportConflictingAttribute(reader, configuration, ELEM_ASSIGN, 
ATTR_EXPR, ATTR_SRC);
+        }
+        else if (assign.getExpr() != null) {
+            skipToEndElement(reader);
+        }
+        else if (assign.getSrc() != null) {
+            skipToEndElement(reader);
+            String resolvedSrc = assign.getSrc();
+            if (configuration.pathResolver != null) {
+                resolvedSrc = 
configuration.pathResolver.resolvePath(resolvedSrc);
+            }
+            try {
+                
assign.setValue(ContentParser.DEFAULT_PARSER.parseResource(resolvedSrc));
+            } catch (IOException e) {
+                throw new ModelException(e);
+            }
+        }
+        else {
+            Location location = reader.getLocation();
+            Node node = readNode(reader, configuration, XMLNS_SCXML, 
ELEM_ASSIGN, new String[]{ATTR_LOCATION});
+            if (node.hasChildNodes()) {
+                assign.setNode(node);
+                NodeList children = node.getChildNodes();
+                if (children.getLength() == 1 && 
children.item(0).getNodeType() == Node.TEXT_NODE) {
+                    String text = 
configuration.contentParser.trimContent(children.item(0).getNodeValue());
+                    if (configuration.contentParser.hasJsonSignature(text)) {
+                        try {
+                            
assign.setValue(configuration.contentParser.parseJson(text));
+                        } catch (IOException e) {
+                            throw new ModelException(e);
+                        }
+                    }
+                    else {
+                        
assign.setValue(configuration.contentParser.spaceNormalizeContent(text));
+                    }
+                } else {
+                    // can only handle a single node: pick the first child
+                    assign.setValue(children.item(0));
+                }
+            } else {
+                // report missing expression (as most common use-case)
+                reportMissingAttribute(location, ELEM_ASSIGN, ATTR_EXPR);
+            }
+        }
+
         assign.setParent(executable);
         if (parent != null) {
             parent.addAction(assign);
         } else {
             executable.addAction(assign);
         }
-        skipToEndElement(reader);
     }
 
     /**
@@ -2348,9 +2394,7 @@ public final class SCXMLReader {
             throws ModelException {
         String value = nullIfEmpty(reader.getAttributeValue(XMLNS_DEFAULT, 
attrLocalName));
         if (value == null) {
-            MessageFormat msgFormat = new 
MessageFormat(ERR_REQUIRED_ATTRIBUTE_MISSING);
-            String errMsg = msgFormat.format(new Object[] {elementName, 
attrLocalName, reader.getLocation()});
-            throw new ModelException(errMsg);
+            reportMissingAttribute(reader.getLocation(), elementName, 
attrLocalName);
         }
         return value;
     }
@@ -2382,6 +2426,22 @@ public final class SCXMLReader {
     }
 
     /**
+     * Report a missing required attribute value at the current reader 
location,
+     *
+     * @param location The (approximate) {@link Location} where the attribute 
is expected.
+     * @param elementName The name of the element for which the attribute 
value is needed.
+     * @param attrLocalName The attribute name whose value is needed.
+     *
+     * @throws ModelException The required attribute is missing or empty.
+     */
+    private static void reportMissingAttribute(final Location location, final 
String elementName, final String attrLocalName)
+            throws ModelException {
+        MessageFormat msgFormat = new 
MessageFormat(ERR_REQUIRED_ATTRIBUTE_MISSING);
+        String errMsg = msgFormat.format(new Object[] {elementName, 
attrLocalName, location});
+        throw new ModelException(errMsg);
+    }
+
+    /**
      * Report an ignored element via the {@link XMLReporter} if available and 
the class
      * {@link org.apache.commons.logging.Log}.
      *

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/144d205d/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java 
b/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java
index 5f0a8b1..1a12531 100644
--- a/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java
+++ b/src/main/java/org/apache/commons/scxml2/io/SCXMLWriter.java
@@ -871,11 +871,15 @@ public class SCXMLWriter {
         for (Action a : actions) {
             if (a instanceof Assign) {
                 Assign asn = (Assign) a;
-                writer.writeStartElement(XMLNS_SCXML, ELEM_ASSIGN);
-                writeAV(writer, ATTR_LOCATION, asn.getLocation());
-                writeAV(writer, ATTR_SRC, asn.getSrc());
-                writeAV(writer, ATTR_EXPR, escapeXML(asn.getExpr()));
-                writer.writeEndElement();
+                if (asn.getNode() != null) {
+                    writeNode(writer, asn.getNode());
+                } else {
+                    writer.writeStartElement(XMLNS_SCXML, ELEM_ASSIGN);
+                    writeAV(writer, ATTR_LOCATION, asn.getLocation());
+                    writeAV(writer, ATTR_SRC, asn.getSrc());
+                    writeAV(writer, ATTR_EXPR, escapeXML(asn.getExpr()));
+                    writer.writeEndElement();
+                }
             } else if (a instanceof Send) {
                 writeSend(writer, (Send) a);
             } else if (a instanceof Cancel) {

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/144d205d/src/main/java/org/apache/commons/scxml2/model/Assign.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/scxml2/model/Assign.java 
b/src/main/java/org/apache/commons/scxml2/model/Assign.java
index f2ca819..4658f95 100644
--- a/src/main/java/org/apache/commons/scxml2/model/Assign.java
+++ b/src/main/java/org/apache/commons/scxml2/model/Assign.java
@@ -16,14 +16,11 @@
  */
 package org.apache.commons.scxml2.model;
 
-import java.io.IOException;
-import org.apache.commons.logging.LogFactory;
 import org.apache.commons.scxml2.ActionExecutionContext;
 import org.apache.commons.scxml2.Context;
 import org.apache.commons.scxml2.Evaluator;
-import org.apache.commons.scxml2.PathResolver;
 import org.apache.commons.scxml2.SCXMLExpressionException;
-import org.apache.commons.scxml2.io.ContentParser;
+import org.w3c.dom.Node;
 
 /**
  * The class in this SCXML object model that corresponds to the
@@ -44,7 +41,7 @@ public class Assign extends Action {
     private String location;
 
     /**
-     * The source where the new XML instance for this location exists.
+     * The source location where the new source data for this location exists.
      */
     private String src;
 
@@ -54,6 +51,16 @@ public class Assign extends Action {
     private String expr;
 
     /**
+     * The assign definition parsed as a standalone DocumentFragment Node 
(only used by the SCXMLWriter)
+     */
+    private Node node;
+
+    /**
+     * The parsed value for the child XML data tree or the content of the 
external src
+     */
+    private Object value;
+
+    /**
      * Constructor.
      */
     public Assign() {
@@ -115,6 +122,46 @@ public class Assign extends Action {
     }
 
     /**
+     * Get the assign definition parsed as standalone DocumentFragment Node.
+     *
+     * @return Node The assign definition parsed as a standalone 
DocumentFragment <code>Node</code>.
+     */
+    public final Node getNode() {
+        return node;
+    }
+
+    /**
+     * Set the assign definition parsed as standalone DocumentFragment Node.
+     *
+     * @param node The child XML data tree, parsed as a standalone 
DocumentFragment <code>Node</code>.
+     */
+    public final void setNode(final Node node) {
+        this.node = node;
+    }
+
+    /**
+     * Get the parsed value for the child XML data tree or the content of the 
external src
+     * @see #setValue(Object)
+     * @return The parsed value
+     */
+    public final Object getValue() {
+        return value;
+    }
+
+    /**
+     * Sets the parsed value for the child XML data tree or the content of the 
external src
+     * @param value a serializable object:
+     * <ul>
+     *   <li>"Raw" JSON mapped object tree (array->ArrayList, 
object->LinkedHashMap based)</li>
+     *   <li>XML Node (equals {@link #getNode()})</li>
+     *   <li>space-normalized String</li>
+     * </ul>
+     */
+    public final void setValue(final Object value) {
+        this.value = value;
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -124,11 +171,12 @@ public class Assign extends Action {
         Evaluator evaluator = exctx.getEvaluator();
         ctx.setLocal(getNamespacesKey(), getNamespaces());
         Object data;
-        if (src != null && src.trim().length() > 0) {
-            data = getSrcData(exctx.getStateMachine().getPathResolver());
-        } else {
+        if (expr != null) {
             data = evaluator.eval(ctx, expr);
         }
+        else {
+            data = evaluator.cloneData(value);
+        }
 
         evaluator.evalAssign(ctx, location, data);
         if (exctx.getAppLog().isDebugEnabled()) {
@@ -142,31 +190,4 @@ public class Assign extends Action {
         */
         ctx.setLocal(getNamespacesKey(), null);
     }
-
-    /**
-     * Get the data the "src" attribute points to.
-     *
-     * @return The data the "src" attribute points to.
-     */
-    private Object getSrcData(final PathResolver pathResolver) {
-        String resolvedSrc = src;
-        if (pathResolver != null) {
-            resolvedSrc = pathResolver.resolvePath(src);
-        }
-        try {
-            return ContentParser.DEFAULT_PARSER.parseResource(resolvedSrc);
-        } catch (IOException e) {
-            logError(e);
-            return null;
-        }
-    }
-
-    /**
-     * @param throwable The throwable to log about
-     */
-    private void logError(Throwable throwable) {
-        org.apache.commons.logging.Log log = LogFactory.
-            getLog(Assign.class);
-        log.error(throwable.getMessage(), throwable);
-    }
 }

http://git-wip-us.apache.org/repos/asf/commons-scxml/blob/144d205d/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/scxml2/w3c/tests.xml 
b/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
index 4a64872..f8719cb 100644
--- a/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
+++ b/src/test/java/org/apache/commons/scxml2/w3c/tests.xml
@@ -57,7 +57,7 @@
   <test id="280" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
   <test id="550" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
   <test id="551" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
-  <test id="552" mandatory="true"                    manual="false" 
jexl="false" ecma="false"/>
+  <test id="552" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
   <test id="286" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
   <test id="287" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
   <test id="487" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
@@ -148,7 +148,7 @@
   <test id="250" mandatory="true"                    manual="true"  
jexl="true"  ecma="true" finalState="final"/>
   <test id="252" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
   <test id="253" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
-  <test id="530" mandatory="true"                    manual="false" 
jexl="false" ecma="false"/>
+  <test id="530" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
   <test id="554" mandatory="true"                    manual="false" 
jexl="true"  ecma="true"/>
   <test id="436" mandatory="true"  profile="minimal" manual="false"            
               minimal="true"/>
   <test id="278" mandatory="false" profile="ecma"    manual="false"            
  ecma="true"/>
@@ -162,7 +162,7 @@
   <test id="456" mandatory="false" profile="ecma"    manual="false"            
  ecma="true"/>
   <test id="446" mandatory="false" profile="ecma"    manual="false"            
  ecma="false"/>
   <test id="557" mandatory="false" profile="ecma"    manual="false"            
  ecma="false"/>
-  <test id="558" mandatory="false" profile="ecma"    manual="false"            
  ecma="false"/>
+  <test id="558" mandatory="false" profile="ecma"    manual="false"            
  ecma="true"/>
   <test id="560" mandatory="false" profile="ecma"    manual="false"            
  ecma="true"/>
   <test id="578" mandatory="false" profile="ecma"    manual="false"            
  ecma="true"/>
   <test id="561" mandatory="false" profile="ecma"    manual="false"            
  ecma="false"/>

Reply via email to