commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ra...@apache.org
Subject svn commit: r737824 [2/3] - in /commons/proper/scxml/branches/J6/src: main/java/org/apache/commons/scxml/ main/java/org/apache/commons/scxml/env/ main/java/org/apache/commons/scxml/invoke/ main/java/org/apache/commons/scxml/io/ main/java/org/apache/com...
Date Mon, 26 Jan 2009 20:31:23 GMT
Added: commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/SCXMLReader.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/SCXMLReader.java?rev=737824&view=auto
==============================================================================
--- commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/SCXMLReader.java (added)
+++ commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/SCXMLReader.java Mon Jan 26 20:31:22 2009
@@ -0,0 +1,2451 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.scxml.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLConnection;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EmptyStackException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLReporter;
+import javax.xml.stream.XMLResolver;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.util.XMLEventAllocator;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.scxml.PathResolver;
+import org.apache.commons.scxml.env.SimpleErrorHandler;
+import org.apache.commons.scxml.env.URLResolver;
+import org.apache.commons.scxml.model.Action;
+import org.apache.commons.scxml.model.Assign;
+import org.apache.commons.scxml.model.Cancel;
+import org.apache.commons.scxml.model.CustomAction;
+import org.apache.commons.scxml.model.Data;
+import org.apache.commons.scxml.model.Datamodel;
+import org.apache.commons.scxml.model.Else;
+import org.apache.commons.scxml.model.ElseIf;
+import org.apache.commons.scxml.model.Event;
+import org.apache.commons.scxml.model.Executable;
+import org.apache.commons.scxml.model.Exit;
+import org.apache.commons.scxml.model.ExternalContent;
+import org.apache.commons.scxml.model.Final;
+import org.apache.commons.scxml.model.Finalize;
+import org.apache.commons.scxml.model.History;
+import org.apache.commons.scxml.model.If;
+import org.apache.commons.scxml.model.Initial;
+import org.apache.commons.scxml.model.Invoke;
+import org.apache.commons.scxml.model.Log;
+import org.apache.commons.scxml.model.ModelException;
+import org.apache.commons.scxml.model.NamespacePrefixesHolder;
+import org.apache.commons.scxml.model.OnEntry;
+import org.apache.commons.scxml.model.OnExit;
+import org.apache.commons.scxml.model.Parallel;
+import org.apache.commons.scxml.model.Param;
+import org.apache.commons.scxml.model.SCXML;
+import org.apache.commons.scxml.model.Script;
+import org.apache.commons.scxml.model.Send;
+import org.apache.commons.scxml.model.State;
+import org.apache.commons.scxml.model.Transition;
+import org.apache.commons.scxml.model.TransitionTarget;
+import org.apache.commons.scxml.model.Var;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * <p>The SCXMLReader provides the ability to read a SCXML document into
+ * the Java object model provided in the model package.</p>
+ *
+ * <p>See latest version of the SCXML Working Draft for more details.</p>
+ *
+ * <p><b>NOTE:</b> The SCXMLReader assumes that the SCXML document to be
+ * parsed is well-formed and correct. If that assumption does not hold,
+ * any subsequent behavior is undefined.</p>
+ *
+ * @since 1.0
+ */
+public final class SCXMLReader {
+
+    //---------------------- PRIVATE CONSTANTS ----------------------//
+    //---- NAMESPACES ----//
+    /**
+     * The SCXML namespace that this Reader is built for. Any document
+     * that is intended to be parsed by this reader <b>must</b>
+     * bind the SCXML elements to this namespace.
+     */
+    private static final String XMLNS_SCXML =
+        "http://www.w3.org/2005/07/scxml";
+
+    /**
+     * The namespace that defines any custom actions defined by the Commons
+     * SCXML implementation. Any document that intends to use these custom
+     * actions needs to ensure that they are in the correct namespace. Use
+     * of actions in this namespace makes the document non-portable across
+     * implementations.
+     */
+    private static final String XMLNS_COMMONS_SCXML =
+        "http://commons.apache.org/scxml";
+
+    /**
+     * The default namespace for attributes.
+     */
+    private static final String XMLNS_DEFAULT = null;
+
+    //---- ERROR MESSAGES ----//
+    /**
+     * Null URL passed as argument.
+     */
+    private static final String ERR_NULL_URL = "Cannot parse null URL";
+
+    /**
+     * Null path passed as argument.
+     */
+    private static final String ERR_NULL_PATH = "Cannot parse null path";
+
+    /**
+     * Null InputStream passed as argument.
+     */
+    private static final String ERR_NULL_ISTR = "Cannot parse null InputStream";
+
+    /**
+     * Null Reader passed as argument.
+     */
+    private static final String ERR_NULL_READ = "Cannot parse null Reader";
+
+    /**
+     * Null Source passed as argument.
+     */
+    private static final String ERR_NULL_SRC = "Cannot parse null Source";
+
+    /**
+     * Error message while attempting to define a custom action which does
+     * not extend the Commons SCXML Action base class.
+     */
+    private static final String ERR_CUSTOM_ACTION_TYPE = "Custom actions list"
+        + " contained unknown object, class not a Commons SCXML Action class subtype: ";
+
+    /**
+     * Parser configuration error while trying to parse stream to DOM node(s).
+     */
+    private static final String ERR_PARSER_CFG = "ParserConfigurationException while trying"
+        + " to parse stream into DOM node(s).";
+
+    /**
+     * Error message when the URI in a &lt;state&gt;'s &quot;src&quot;
+     * attribute does not point to a valid SCXML document, and thus cannot be
+     * parsed.
+     */
+    private static final String ERR_STATE_SRC =
+        "Source attribute in <state src=\"{0}\"> cannot be parsed";
+
+    /**
+     * Error message when the target of the URI fragment in a &lt;state&gt;'s
+     * &quot;src&quot; attribute is not defined in the referenced document.
+     */
+    private static final String ERR_STATE_SRC_FRAGMENT = "URI Fragment in "
+        + "<state src=\"{0}\"> is an unknown state in referenced document";
+
+    /**
+     * Error message when the target of the URI fragment in a &lt;state&gt;'s
+     * &quot;src&quot; attribute is not a &lt;state&gt; or &lt;final&gt; in
+     * the referenced document.
+     */
+    private static final String ERR_STATE_SRC_FRAGMENT_TARGET = "URI Fragment"
+        + " in <state src=\"{0}\"> does not point to a <state> or <final>";
+
+    //--------------------------- XML VOCABULARY ---------------------------//
+    //---- ELEMENT NAMES ----//
+    private static final String ELEM_ASSIGN = "assign";
+    private static final String ELEM_CANCEL = "cancel";
+    private static final String ELEM_CONTENT = "content";
+    private static final String ELEM_DATA = "data";
+    private static final String ELEM_DATAMODEL = "datamodel";
+    private static final String ELEM_ELSE = "else";
+    private static final String ELEM_ELSEIF = "elseif";
+    private static final String ELEM_EVENT = "event";
+    private static final String ELEM_EXIT = "exit";
+    private static final String ELEM_FINAL = "final";
+    private static final String ELEM_FINALIZE = "finalize";
+    private static final String ELEM_HISTORY = "history";
+    private static final String ELEM_IF = "if";
+    private static final String ELEM_INITIAL = "initial";
+    private static final String ELEM_INVOKE = "invoke";
+    private static final String ELEM_LOG = "log";
+    private static final String ELEM_ONENTRY = "onentry";
+    private static final String ELEM_ONEXIT = "onexit";
+    private static final String ELEM_PARALLEL = "parallel";
+    private static final String ELEM_PARAM = "param";
+    private static final String ELEM_SCRIPT = "script";
+    private static final String ELEM_SCXML = "scxml";
+    private static final String ELEM_SEND = "send";
+    private static final String ELEM_STATE = "state";
+    private static final String ELEM_TRANSITION = "transition";
+    private static final String ELEM_VALIDATE = "validate";
+    private static final String ELEM_VAR = "var";
+
+    //---- ATTRIBUTE NAMES ----//
+    private static final String ATTR_COND = "cond";
+    private static final String ATTR_DELAY = "delay";
+    private static final String ATTR_EVENT = "event";
+    private static final String ATTR_EXMODE = "exmode";
+    private static final String ATTR_EXPR = "expr";
+    private static final String ATTR_FINAL = "final";
+    private static final String ATTR_HINTS = "hints";
+    private static final String ATTR_ID = "id";
+    private static final String ATTR_INITIAL = "initial";
+    private static final String ATTR_LABEL = "label";
+    private static final String ATTR_LOCATION = "location";
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_NAMELIST = "namelist";
+    private static final String ATTR_PROFILE = "profile";
+    private static final String ATTR_SENDID = "sendid";
+    private static final String ATTR_SRC = "src";
+    private static final String ATTR_TARGET = "target";
+    private static final String ATTR_TARGETTYPE = "targettype";
+    private static final String ATTR_TYPE = "type";
+    private static final String ATTR_VERSION = "version";
+
+    //------------------------- PUBLIC API METHODS -------------------------//
+    /*
+     * Public methods
+     */
+    /**
+     * Parse the SCXML document at the supplied path.
+     *
+     * @param scxmlPath The real path to the SCXML document.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final String scxmlPath)
+    throws IOException, ModelException, XMLStreamException {
+
+        return read(scxmlPath, new Configuration());
+
+    }
+
+    /**
+     * Parse the SCXML document at the supplied path with the given {@link Configuration}.
+     *
+     * @param scxmlPath The real path to the SCXML document.
+     * @param configuration The {@link Configuration} to use when parsing the SCXML document.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final String scxmlPath, final Configuration configuration)
+    throws IOException, ModelException, XMLStreamException {
+
+        if (scxmlPath == null) {
+            throw new IllegalArgumentException(ERR_NULL_PATH);
+        }
+        SCXML scxml = readInternal(configuration, null, scxmlPath, null, null, null);
+        if (scxml != null) {
+            ModelUpdater.updateSCXML(scxml);
+        }
+        return scxml;
+
+    }
+
+    /**
+     * Parse the SCXML document at the supplied {@link URL}.
+     *
+     * @param scxmlURL The SCXML document {@link URL} to parse.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final URL scxmlURL)
+    throws IOException, ModelException, XMLStreamException {
+
+        return read(scxmlURL, new Configuration());
+
+    }
+
+    /**
+     * Parse the SCXML document at the supplied {@link URL} with the given {@link Configuration}.
+     *
+     * @param scxmlURL The SCXML document {@link URL} to parse.
+     * @param configuration The {@link Configuration} to use when parsing the SCXML document.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final URL scxmlURL, final Configuration configuration)
+    throws IOException, ModelException, XMLStreamException {
+
+        if (scxmlURL == null) {
+            throw new IllegalArgumentException(ERR_NULL_URL);
+        }
+        SCXML scxml = readInternal(configuration, scxmlURL, null, null, null, null);
+        if (scxml != null) {
+            ModelUpdater.updateSCXML(scxml);
+        }
+        return scxml;
+
+    }
+
+    /**
+     * Parse the SCXML document supplied by the given {@link InputStream}.
+     *
+     * @param scxmlStream The {@link InputStream} supplying the SCXML document to parse.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final InputStream scxmlStream)
+    throws IOException, ModelException, XMLStreamException {
+
+        return read(scxmlStream, new Configuration());
+
+    }
+
+    /**
+     * Parse the SCXML document supplied by the given {@link InputStream} with the given {@link Configuration}.
+     *
+     * @param scxmlStream The {@link InputStream} supplying the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use when parsing the SCXML document.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final InputStream scxmlStream, final Configuration configuration)
+    throws IOException, ModelException, XMLStreamException {
+
+        if (scxmlStream == null) {
+            throw new IllegalArgumentException(ERR_NULL_ISTR);
+        }
+        SCXML scxml = readInternal(configuration, null, null, scxmlStream, null, null);
+        if (scxml != null) {
+            ModelUpdater.updateSCXML(scxml);
+        }
+        return scxml;
+
+    }
+
+    /**
+     * Parse the SCXML document supplied by the given {@link Reader}.
+     *
+     * @param scxmlReader The {@link Reader} supplying the SCXML document to parse.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final Reader scxmlReader)
+    throws IOException, ModelException, XMLStreamException {
+
+        return read(scxmlReader, new Configuration());
+
+    }
+
+    /**
+     * Parse the SCXML document supplied by the given {@link Reader} with the given {@link Configuration}.
+     *
+     * @param scxmlReader The {@link Reader} supplying the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use when parsing the SCXML document.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final Reader scxmlReader, final Configuration configuration)
+    throws IOException, ModelException, XMLStreamException {
+
+        if (scxmlReader == null) {
+            throw new IllegalArgumentException(ERR_NULL_READ);
+        }
+        SCXML scxml = readInternal(configuration, null, null, null, scxmlReader, null);
+        if (scxml != null) {
+            ModelUpdater.updateSCXML(scxml);
+        }
+        return scxml;
+
+    }
+
+    /**
+     * Parse the SCXML document supplied by the given {@link Source}.
+     *
+     * @param scxmlSource The {@link Source} supplying the SCXML document to parse.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final Source scxmlSource)
+    throws IOException, ModelException, XMLStreamException {
+
+        return read(scxmlSource, new Configuration());
+
+    }
+
+    /**
+     * Parse the SCXML document supplied by the given {@link Source} with the given {@link Configuration}.
+     *
+     * @param scxmlSource The {@link Source} supplying the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use when parsing the SCXML document.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    public static SCXML read(final Source scxmlSource, final Configuration configuration)
+    throws IOException, ModelException, XMLStreamException {
+
+        if (scxmlSource == null) {
+            throw new IllegalArgumentException(ERR_NULL_SRC);
+        }
+        SCXML scxml = readInternal(configuration, null, null, null, null, scxmlSource);
+        if (scxml != null) {
+            ModelUpdater.updateSCXML(scxml);
+        }
+        return scxml;
+
+    }
+
+    //---------------------- PRIVATE UTILITY METHODS ----------------------//
+    /**
+     * Parse the SCXML document at the supplied {@link URL} using the supplied {@link Configuration}, but do not
+     * wire up the object model to be usable just yet. Exactly one of the url, path, stream, reader or source
+     * parameters must be provided.
+     *
+     * @param configuration The {@link Configuration} to use when parsing the SCXML document.
+     * @param scxmlURL The optional SCXML document {@link URL} to parse.
+     * @param scxmlPath The optional real path to the SCXML document as a string.
+     * @param scxmlStream The optional {@link InputStream} providing the SCXML document.
+     * @param scxmlReader The optional {@link Reader} providing the SCXML document.
+     * @param scxmlSource The optional {@link Source} providing the SCXML document.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document
+     *         (not wired up to be immediately usable).
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static SCXML readInternal(final Configuration configuration, final URL scxmlURL, final String scxmlPath,
+            final InputStream scxmlStream, final Reader scxmlReader, final Source scxmlSource)
+    throws IOException, ModelException, XMLStreamException {
+
+        if (configuration.pathResolver == null) {
+            if (scxmlURL != null) {
+                configuration.pathResolver = new URLResolver(scxmlURL);
+            } else if (scxmlPath != null) {
+                configuration.pathResolver = new URLResolver(new URL(scxmlPath));
+            }
+        }
+
+        XMLStreamReader reader = getReader(configuration, scxmlURL, scxmlPath, scxmlStream, scxmlReader, scxmlSource);
+
+        return readDocument(reader, configuration);
+
+    }
+
+    /*
+     * Private utility functions for reading the SCXML document.
+     */
+    /**
+     * Read the SCXML document through the {@link XMLStreamReader}.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     *
+     * @return The parsed output, the Commons SCXML object model corresponding to the SCXML document
+     *         (not wired up to be immediately usable).
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static SCXML readDocument(final XMLStreamReader reader, final Configuration configuration)
+    throws IOException, ModelException, XMLStreamException {
+
+        SCXML scxml = new SCXML();
+        while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_SCXML.equals(name)) {
+                            readSCXML(reader, configuration, scxml);
+                        } else {
+                            reportIgnoredElement(reader, configuration, "DOCUMENT_ROOT", nsURI, name);
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, "DOCUMENT_ROOT", nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.NAMESPACE:
+                    System.err.println(reader.getNamespaceCount());
+                    break;
+                default:
+            }
+        }
+        return scxml;
+
+    }
+
+    /**
+     * Read the contents of this &lt;scxml&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param scxml The root of the object model being parsed.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readSCXML(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml)
+    throws IOException, ModelException, XMLStreamException {
+
+        scxml.setExmode(readAV(reader, ATTR_EXMODE));
+        scxml.setInitial(readAV(reader, ATTR_INITIAL));
+        scxml.setName(readAV(reader, ATTR_NAME));
+        scxml.setProfile(readAV(reader, ATTR_PROFILE));
+        scxml.setVersion(readAV(reader, ATTR_VERSION));
+        readNamespaces(configuration, scxml);
+
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_STATE.equals(name)) {
+                            readState(reader, configuration, scxml, null);
+                        } else if (ELEM_PARALLEL.equals(name)) {
+                            readParallel(reader, configuration, scxml, null);
+                        } else if (ELEM_FINAL.equals(name)) {
+                            readFinal(reader, configuration, scxml, null);
+                        } else if (ELEM_DATAMODEL.equals(name)) {
+                            readDatamodel(reader, configuration, scxml, null);
+                        } else {
+                            reportIgnoredElement(reader, configuration, ELEM_SCXML, nsURI, name);
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, ELEM_SCXML, nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI) && ELEM_SCXML.equals(name)) {
+                        break loop;
+                    }
+                    break;
+                default:
+            }
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;state&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param scxml The root of the object model being parsed.
+     * @param parent The parent {@link TransitionTarget} for this state (null for top level state).
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readState(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
+            final TransitionTarget parent)
+    throws IOException, ModelException, XMLStreamException {
+
+        State state = new State();
+        state.setId(readAV(reader, ATTR_ID));
+        String initial = readAV(reader, ATTR_INITIAL);
+        if (initial != null) {
+            state.setFirst(initial);
+        }
+        String isFinal = readAV(reader, ATTR_FINAL);
+        if ("true".equals(isFinal)) {
+            state.setFinal(true);
+        }
+        String src = readAV(reader, ATTR_SRC);
+        if (src != null) {
+            String source = src;
+            Configuration copy = new Configuration(configuration);
+            if (copy.parent == null) {
+                copy.parent = scxml;
+            }
+            if (configuration.pathResolver != null) {
+                source = configuration.pathResolver.resolvePath(src);
+                copy.pathResolver = configuration.pathResolver.getResolver(src);
+            }
+            readTransitionTargetSrc(copy, source, state);
+        }
+
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_TRANSITION.equals(name)) {
+                            readTransition(reader, configuration, state);
+                        } else if (ELEM_STATE.equals(name)) {
+                            readState(reader, configuration, scxml, state);
+                        } else if (ELEM_INITIAL.equals(name)) {
+                            readInitial(reader, configuration, state);
+                        } else if (ELEM_FINAL.equals(name)) {
+                            readFinal(reader, configuration, scxml, state);
+                        } else if (ELEM_ONENTRY.equals(name)) {
+                            readOnEntry(reader, configuration, scxml, state);
+                        } else if (ELEM_ONEXIT.equals(name)) {
+                            readOnExit(reader, configuration, scxml, state);
+                        } else if (ELEM_PARALLEL.equals(name)) {
+                            readParallel(reader, configuration, scxml, state);
+                        } else if (ELEM_DATAMODEL.equals(name)) {
+                            readDatamodel(reader, configuration, null, state);
+                        } else if (ELEM_INVOKE.equals(name)) {
+                            readInvoke(reader, configuration, state);
+                        } else if (ELEM_HISTORY.equals(name)) {
+                            readHistory(reader, configuration, scxml, state);
+                        } else {
+                            reportIgnoredElement(reader, configuration, ELEM_STATE, nsURI, name);
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, ELEM_STATE, nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI) && ELEM_STATE.equals(name)) {
+                        break loop;
+                    }
+                    break;
+                default:
+            }
+        }
+
+        if (parent == null) {
+            scxml.addChild(state);
+        } else if (parent instanceof State) {
+            ((State) parent).addChild(state);
+        } else if (parent instanceof Parallel) {
+            ((Parallel) parent).addChild(state);
+        }
+        scxml.addTarget(state);
+        if (configuration.parent != null) {
+            configuration.parent.addTarget(state);
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;parallel&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param scxml The root of the object model being parsed.
+     * @param parent The parent {@link TransitionTarget} for this parallel (null for top level state).
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readParallel(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
+            final TransitionTarget parent)
+    throws IOException, ModelException, XMLStreamException {
+
+        Parallel parallel = new Parallel();
+        parallel.setId(readAV(reader, ATTR_ID));
+        String src = readAV(reader, ATTR_SRC);
+        if (src != null) {
+            String source = src;
+            Configuration copy = new Configuration(configuration);
+            if (copy.parent == null) {
+                copy.parent = scxml;
+            }
+            if (configuration.pathResolver != null) {
+                source = configuration.pathResolver.resolvePath(src);
+                copy.pathResolver = configuration.pathResolver.getResolver(src);
+            }
+            readTransitionTargetSrc(copy, source, parallel);
+        }
+
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_TRANSITION.equals(name)) {
+                            readTransition(reader, configuration, parallel);
+                        } else if (ELEM_STATE.equals(name)) {
+                            readState(reader, configuration, scxml, parallel);
+                        } else if (ELEM_ONENTRY.equals(name)) {
+                            readOnEntry(reader, configuration, scxml, parallel);
+                        } else if (ELEM_ONEXIT.equals(name)) {
+                            readOnExit(reader, configuration, scxml, parallel);
+                        } else if (ELEM_DATAMODEL.equals(name)) {
+                            readDatamodel(reader, configuration, null, parallel);
+                        } else if (ELEM_HISTORY.equals(name)) { // TODO Check parallel history
+                            readHistory(reader, configuration, scxml, parallel);
+                        } else {
+                            reportIgnoredElement(reader, configuration, ELEM_PARALLEL, nsURI, name);
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, ELEM_PARALLEL, nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI) && ELEM_PARALLEL.equals(name)) {
+                        break loop;
+                    }
+                    break;
+                default:
+            }
+        }
+
+        if (parent == null) {
+            scxml.addChild(parallel);
+        } else if (parent instanceof State) {
+            ((State) parent).addChild(parallel);
+        }
+        // TODO parallel child of parallel?
+        scxml.addTarget(parallel);
+        if (configuration.parent != null) {
+            configuration.parent.addTarget(parallel);
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;final&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param scxml The root of the object model being parsed.
+     * @param parent The parent {@link TransitionTarget} for this final (null for top level state).
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readFinal(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
+            final TransitionTarget parent)
+    throws XMLStreamException {
+
+        Final end = new Final();
+        end.setId(readAV(reader, ATTR_ID));
+
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_ONENTRY.equals(name)) {
+                            readOnEntry(reader, configuration, scxml, end);
+                        } else if (ELEM_ONEXIT.equals(name)) {
+                            readOnExit(reader, configuration, scxml, end);
+                        } else {
+                            reportIgnoredElement(reader, configuration, ELEM_FINAL, nsURI, name);
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, ELEM_FINAL, nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI) && ELEM_FINAL.equals(name)) {
+                        break loop;
+                    }
+                    break;
+                default:
+            }
+        }
+
+        if (parent == null) {
+            scxml.addChild(end);
+        } else if (parent instanceof State) {
+            ((State) parent).addChild(end);
+        }
+        scxml.addTarget(end);
+
+    }
+
+    /**
+     * Parse the contents of the SCXML document that this "src" attribute value of a &lt;state&gt; or &lt;parallel&gt;
+     * element points to. Without a URL fragment, the entire state machine is imported as contents of the
+     * &lt;state&gt; or &lt;parallel&gt;. If a URL fragment is present, the fragment must specify the id of the
+     * corresponding &lt;state&gt; or &lt;parallel&gt; to import.
+     *
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param src The "src" attribute value.
+     * @param tt The parent {@link TransitionTarget} that specifies this "src" attribute.
+     *
+     * @throws IOException An IO error during parsing.
+     * @throws ModelException The Commons SCXML object model is incomplete or inconsistent (includes
+     *                        errors in the SCXML document that may not be identified by the schema).
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readTransitionTargetSrc(final Configuration configuration, final String src,
+            final TransitionTarget tt)
+    throws IOException, ModelException, XMLStreamException {
+
+        // Check for URI fragment
+        String[] fragments = src.split("#", 2);
+        String location = fragments[0];
+        String fragment = null;
+        if (fragments.length > 1) {
+            fragment = fragments[1];
+        }
+
+        // Parse external document
+        SCXML externalSCXML = null;
+        try {
+            externalSCXML = SCXMLReader.readInternal(configuration, new URL(location), null, null, null, null);
+        } catch (Exception e) {
+            MessageFormat msgFormat = new MessageFormat(ERR_STATE_SRC);
+            String errMsg = msgFormat.format(new Object[] {src});
+            throw new ModelException(errMsg + " : " + e.getMessage(), e);
+        }
+
+        // Pull in the parts of the external document as needed
+        State s = (State) tt;
+        if (fragment == null) {
+            // All targets pulled in since its not a src fragment
+            if (tt instanceof State) {
+                Initial ini = new Initial();
+                Transition t = new Transition();
+                t.setNext(externalSCXML.getInitial());
+                ini.setTransition(t);
+                s.setInitial(ini);
+                Collection<TransitionTarget> children = externalSCXML.getChildren().values();
+                for (TransitionTarget child : children) {
+                    s.addChild(child);
+                }
+                s.setDatamodel(externalSCXML.getDatamodel());
+            } else if (tt instanceof Parallel) {
+                // TODO src attribute for <parallel>
+            }
+        } else {
+            // Need to pull in only descendent targets
+            Object source = externalSCXML.getTargets().get(fragment);
+            if (source == null) {
+                MessageFormat msgFormat = new MessageFormat(ERR_STATE_SRC_FRAGMENT);
+                String errMsg = msgFormat.format(new Object[] {src});
+                throw new ModelException(errMsg);
+            }
+            if (source instanceof State) {
+                State include = (State) source;
+                s.setOnEntry(include.getOnEntry());
+                s.setOnExit(include.getOnExit());
+                s.setDatamodel(include.getDatamodel());
+                List<History> histories = include.getHistory();
+                for (History h : histories) {
+                    s.addHistory(h);
+                    configuration.parent.addTarget(h);
+                }
+                Collection<TransitionTarget> children = include.getChildren().
+                    values();
+                for (TransitionTarget child : children) {
+                    s.addChild(child);
+                    configuration.parent.addTarget(child);
+                    readInExternalTargets(configuration.parent, child);
+                }
+                s.setInvoke(include.getInvoke());
+                s.setFinal(include.isFinal());
+                if (include.getInitial() != null) {
+                    s.setInitial(include.getInitial());
+                }
+                List<Transition> transitions = include.getTransitionsList();
+                for (Transition t : transitions) {
+                    s.addTransition(t);
+                }
+            } else if (tt instanceof Parallel) {
+                // TODO src attribute for <parallel>
+            } else {
+                MessageFormat msgFormat =
+                    new MessageFormat(ERR_STATE_SRC_FRAGMENT_TARGET);
+                String errMsg = msgFormat.format(new Object[] {src});
+                throw new ModelException(errMsg);
+            }
+        }
+    }
+
+    /**
+     * Add all the nested targets from given target to given parent state machine.
+     *
+     * @param parent The state machine
+     * @param tt The transition target to import
+     */
+    private static void readInExternalTargets(final SCXML parent, final TransitionTarget tt) {
+        List<History> histories = tt.getHistory();
+        for (History h : histories) {
+            parent.addTarget(h);
+        }
+        if (tt instanceof State) {
+            Collection<TransitionTarget> children = ((State) tt).getChildren().
+                values();
+            for (TransitionTarget child : children) {
+                parent.addTarget(child);
+                readInExternalTargets(parent, child);
+            }
+        } else if (tt instanceof Parallel) {
+            Collection<TransitionTarget> children = ((Parallel) tt).getChildren();
+            for (TransitionTarget child : children) {
+                parent.addTarget(child);
+                readInExternalTargets(parent, child);
+            }
+        }
+    }
+
+    /**
+     * Read the contents of this &lt;datamodel&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param scxml The root of the object model being parsed.
+     * @param parent The parent {@link TransitionTarget} for this datamodel (null for top level).
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readDatamodel(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
+            final TransitionTarget parent)
+    throws XMLStreamException {
+
+        Datamodel dm = new Datamodel();
+
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_DATA.equals(name)) {
+                            readData(reader, configuration, dm);
+                        } else {
+                            reportIgnoredElement(reader, configuration, ELEM_DATAMODEL, nsURI, name);
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, ELEM_DATAMODEL, nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI) && ELEM_DATAMODEL.equals(name)) {
+                        break loop;
+                    }
+                    break;
+                default:
+            }
+        }
+
+        if (parent == null) {
+            scxml.setDatamodel(dm);
+        } else {
+            parent.setDatamodel(dm);
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;data&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param dm The parent {@link Datamodel} for this data.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readData(final XMLStreamReader reader, final Configuration configuration, final Datamodel dm)
+    throws XMLStreamException {
+
+        Data datum = new Data();
+        datum.setId(readAV(reader, ATTR_ID));
+        datum.setNode(readNode(reader, configuration, XMLNS_SCXML, ELEM_DATA, new String[] {"id"}));
+        dm.addData(datum);
+
+    }
+
+    /**
+     * Read the contents of this &lt;invoke&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param parent The parent {@link State} for this invoke.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readInvoke(final XMLStreamReader reader, final Configuration configuration,
+            final State parent)
+    throws XMLStreamException {
+
+        Invoke invoke = new Invoke();
+        invoke.setSrc(readAV(reader, ATTR_SRC));
+        invoke.setTargettype(readAV(reader, ATTR_TARGETTYPE));
+        invoke.setPathResolver(configuration.pathResolver);
+        readNamespaces(configuration, invoke);
+
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_PARAM.equals(name)) {
+                            readParam(reader, configuration, invoke);
+                        } else if (ELEM_FINALIZE.equals(name)) {
+                            readFinalize(reader, configuration, parent, invoke);
+                        } else if (ELEM_CONTENT.equals(name)) {
+                            readContent(reader, configuration, parent, invoke);
+                        } else {
+                            reportIgnoredElement(reader, configuration, ELEM_INVOKE, nsURI, name);
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, ELEM_INVOKE, nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI) && ELEM_INVOKE.equals(name)) {
+                        break loop;
+                    }
+                    break;
+                default:
+            }
+        }
+
+        parent.setInvoke(invoke);
+
+    }
+
+    /**
+     * Read the contents of this &lt;param&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param parent The parent {@link Invoke} for this param.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readParam(final XMLStreamReader reader, final Configuration configuration,
+            final Invoke parent)
+    throws XMLStreamException {
+
+        Param param = new Param();
+        param.setName(readAV(reader, ATTR_NAME));
+        param.setExpr(readAV(reader, ATTR_EXPR));
+        readNamespaces(configuration, param);
+        parent.addParam(param);
+
+    }
+
+    /**
+     * Read the contents of this &lt;finalize&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param state The {@link State} which contains the parent {@link Invoke}.
+     * @param invoke The parent {@link Invoke} for this finalize.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readFinalize(final XMLStreamReader reader, final Configuration configuration,
+            final State state, final Invoke invoke)
+    throws XMLStreamException {
+
+        Finalize finalize = new Finalize();
+        readExecutableContext(reader, configuration, state, finalize, null);
+        invoke.setFinalize(finalize);
+        finalize.setParent(state);
+
+    }
+
+    /**
+     * Read the contents of this &lt;content&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param state The {@link State} which contains the parent {@link Invoke}.
+     * @param invoke The parent {@link Invoke} for this content.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readContent(final XMLStreamReader reader, final Configuration configuration,
+            final State state, final Invoke invoke)
+    throws XMLStreamException {
+
+        // TODO content support
+
+    }
+
+    /**
+     * Read the contents of this &lt;initial&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param state The parent composite {@link State} for this initial.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readInitial(final XMLStreamReader reader, final Configuration configuration,
+            final State state)
+    throws XMLStreamException {
+
+        Initial initial = new Initial();
+
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_TRANSITION.equals(name)) {
+                            readTransition(reader, configuration, initial);
+                        } else {
+                            reportIgnoredElement(reader, configuration, ELEM_INITIAL, nsURI, name);
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, ELEM_INITIAL, nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI) && ELEM_INITIAL.equals(name)) {
+                        break loop;
+                    }
+                    break;
+                default:
+            }
+        }
+
+        initial.setParent(state);
+        state.setInitial(initial);
+
+    }
+
+    /**
+     * Read the contents of this &lt;history&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param scxml The root of the object model being parsed.
+     * @param tt The parent {@link TransitionTarget} for this history.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readHistory(final XMLStreamReader reader, final Configuration configuration,
+            final SCXML scxml, final TransitionTarget tt)
+    throws XMLStreamException {
+
+        History history = new History();
+        history.setId(readAV(reader, ATTR_ID));
+        history.setType(readAV(reader, ATTR_TYPE));
+
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_TRANSITION.equals(name)) {
+                            readTransition(reader, configuration, history);
+                        } else {
+                            reportIgnoredElement(reader, configuration, ELEM_HISTORY, nsURI, name);
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, ELEM_HISTORY, nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI) && ELEM_HISTORY.equals(name)) {
+                        break loop;
+                    }
+                    break;
+                default:
+            }
+        }
+
+        history.setParent(tt);
+        tt.addHistory(history);
+        scxml.addTarget(history);
+
+    }
+
+    /**
+     * Read the contents of this &lt;onentry&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param scxml The root of the object model being parsed.
+     * @param tt The parent {@link TransitionTarget} for this onentry.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readOnEntry(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
+            final TransitionTarget tt)
+    throws XMLStreamException {
+
+        OnEntry onentry = new OnEntry();
+        readExecutableContext(reader, configuration, tt, onentry, null);
+        tt.setOnEntry(onentry);
+
+    }
+
+    /**
+     * Read the contents of this &lt;onexit&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param scxml The root of the object model being parsed.
+     * @param tt The parent {@link TransitionTarget} for this onexit.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readOnExit(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
+            final TransitionTarget tt)
+    throws XMLStreamException {
+
+        OnExit onexit = new OnExit();
+        readExecutableContext(reader, configuration, tt, onexit, null);
+        tt.setOnExit(onexit);
+
+    }
+
+    /**
+     * Read the contents of this &lt;transition&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this transition.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readTransition(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt)
+    throws XMLStreamException {
+
+        Transition t = new Transition();
+        t.setCond(readAV(reader, ATTR_COND));
+        t.setEvent(readAV(reader, ATTR_EVENT));
+        t.setNext(readAV(reader, ATTR_TARGET));
+        readNamespaces(configuration, t);
+
+        readExecutableContext(reader, configuration, tt, t, null);
+
+        if (tt instanceof State || tt instanceof Parallel) {
+            tt.addTransition(t);
+        } else if (tt instanceof Initial) {
+            ((Initial) tt).setTransition(t);
+        } else if (tt instanceof History) {
+            ((History) tt).setTransition(t);
+        } else {
+            // TODO Error
+        }
+
+    }
+
+    /**
+     * Read this set of executable content elements.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this executable content.
+     * @param executable The parent {@link Executable} to which this content belongs.
+     * @param iff The optional parent {@link If} if this is child content of an if action.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readExecutableContext(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        String end = "";
+        if (iff != null) {
+            end = ELEM_IF;
+        } else if (executable instanceof Transition) {
+            end = ELEM_TRANSITION;
+        } else if (executable instanceof OnEntry) {
+            end = ELEM_ONENTRY;
+        } else if (executable instanceof OnExit) {
+            end = ELEM_ONEXIT;
+        } else if (executable instanceof Finalize) {
+            end = ELEM_FINALIZE;
+        }
+
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI)) {
+                        if (ELEM_EVENT.equals(name)) {
+                            readEvent(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_IF.equals(name)) {
+                            readIf(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_LOG.equals(name)) {
+                            readLog(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_ASSIGN.equals(name)) {
+                            readAssign(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_VALIDATE.equals(name)) {
+                            readValidate(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_SEND.equals(name)) {
+                            readSend(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_CANCEL.equals(name)) {
+                            readCancel(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_SCRIPT.equals(name)) {
+                            readScript(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_IF.equals(end) && ELEM_ELSEIF.equals(name)) {
+                            readElseIf(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_IF.equals(end) && ELEM_ELSE.equals(name)) {
+                            readElse(reader, configuration, tt, executable, iff);
+                        } else {
+                            reportIgnoredElement(reader, configuration, end, nsURI, name);
+                        }
+                    } else if (XMLNS_COMMONS_SCXML.equals(nsURI)) {
+                        if (ELEM_VAR.equals(name)) {
+                            readVar(reader, configuration, tt, executable, iff);
+                        } else if (ELEM_EXIT.equals(name)) {
+                            readExit(reader, configuration, tt, executable, iff);
+                        } else {
+                            reportIgnoredElement(reader, configuration, end, nsURI, name);
+                        }
+                    } else if (configuration.customActions.size() > 0) {
+                        for (CustomAction ca : configuration.customActions) {
+                            if (ca.getNamespaceURI().equals(nsURI) && ca.getLocalName().equals(name)) {
+                                readCustomAction(reader, configuration, ca, tt, executable, iff);
+                            }
+                        }
+                    } else {
+                        reportIgnoredElement(reader, configuration, end, nsURI, name);
+                    }
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (XMLNS_SCXML.equals(nsURI) && end.equals(name)) {
+                        break loop;
+                    }
+                    break;
+                default:
+            }
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;event&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The optional parent {@link If} if this action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readEvent(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        Event event = new Event();
+        event.setName(readAV(reader, ATTR_NAME));
+        readNamespaces(configuration, event);
+        event.setParent(executable);
+        if (iff != null) {
+            iff.addAction(event);
+        } else {
+            executable.addAction(event);
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;if&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param parent The optional parent {@link If} if this &lt;if&gt; is a child of another.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readIf(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If parent)
+    throws XMLStreamException {
+
+        If iff = new If();
+        iff.setCond(readAV(reader, ATTR_COND));
+        readNamespaces(configuration, iff);
+        iff.setParent(executable);
+        if (parent != null) {
+            parent.addAction(iff);
+        } else {
+            executable.addAction(iff);
+        }
+        readExecutableContext(reader, configuration, tt, executable, iff);
+
+    }
+
+    /**
+     * Read the contents of this &lt;elseif&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The parent {@link If} for this &lt;elseif&gt;.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readElseIf(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        ElseIf elseif = new ElseIf();
+        elseif.setCond(readAV(reader, ATTR_COND));
+        readNamespaces(configuration, elseif);
+        elseif.setParent(executable);
+        iff.addAction(elseif);
+
+    }
+
+    /**
+     * Read the contents of this &lt;else&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The parent {@link If} for this &lt;else&gt;.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readElse(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        Else els = new Else();
+        readNamespaces(configuration, els);
+        els.setParent(executable);
+        iff.addAction(els);
+
+    }
+
+    /**
+     * Read the contents of this &lt;log&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The optional parent {@link If} if this action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readLog(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        Log log = new Log();
+        log.setExpr(readAV(reader, ATTR_EXPR));
+        log.setLabel(readAV(reader, ATTR_LABEL));
+        readNamespaces(configuration, log);
+        log.setParent(executable);
+        if (iff != null) {
+            iff.addAction(log);
+        } else {
+            executable.addAction(log);
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;assign&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The optional parent {@link If} if this action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readAssign(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        Assign assign = new Assign();
+        assign.setExpr(readAV(reader, ATTR_EXPR));
+        assign.setLocation(readAV(reader, ATTR_LOCATION));
+        assign.setName(readAV(reader, ATTR_NAME));
+        assign.setSrc(readAV(reader, ATTR_SRC));
+        assign.setPathResolver(configuration.pathResolver);
+        readNamespaces(configuration, assign);
+        assign.setParent(executable);
+        if (iff != null) {
+            iff.addAction(assign);
+        } else {
+            executable.addAction(assign);
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;validate&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The optional parent {@link If} if this action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readValidate(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        // TODO validate support
+
+    }
+
+    /**
+     * Read the contents of this &lt;send&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The optional parent {@link If} if this action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readSend(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        Send send = new Send();
+        send.setDelay(readAV(reader, ATTR_DELAY));
+        send.setEvent(readAV(reader, ATTR_EVENT));
+        send.setHints(readAV(reader, ATTR_HINTS));
+        send.setNamelist(readAV(reader, ATTR_NAMELIST));
+        send.setSendid(readAV(reader, ATTR_SENDID));
+        send.setTarget(readAV(reader, ATTR_TARGET));
+        send.setTargettype(readAV(reader, ATTR_TARGETTYPE));
+        readNamespaces(configuration, send);
+
+        Node body = readNode(reader, configuration, XMLNS_SCXML, ELEM_SEND, new String [] {});
+        NodeList childNodes = body.getChildNodes();
+        List<Node> externalNodes = send.getExternalNodes();
+        for (int i = 0; i < childNodes.getLength(); i++) {
+            externalNodes.add(childNodes.item(i));
+        }
+
+        send.setParent(executable);
+        if (iff != null) {
+            iff.addAction(send);
+        } else {
+            executable.addAction(send);
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;cancel&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The optional parent {@link If} if this action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readCancel(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        Cancel cancel = new Cancel();
+        readNamespaces(configuration, cancel);
+        cancel.setParent(executable);
+        if (iff != null) {
+            iff.addAction(cancel);
+        } else {
+            executable.addAction(cancel);
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;script&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The optional parent {@link If} if this action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readScript(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        Script script = new Script();
+        readNamespaces(configuration, script);
+        script.setParent(executable);
+        if (iff != null) {
+            iff.addAction(script);
+        } else {
+            executable.addAction(script);
+        }
+
+    }
+
+    /**
+     * Read the contents of this &lt;var&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The optional parent {@link If} if this action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readVar(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        Var var = new Var();
+        var.setName(readAV(reader, ATTR_NAME));
+        var.setExpr(readAV(reader, ATTR_EXPR));
+        readNamespaces(configuration, var);
+        var.setParent(executable);
+        if (iff != null) {
+            iff.addAction(var);
+        } else {
+            executable.addAction(var);
+        }
+
+    }
+
+    // TODO Remove <exit> support
+    /**
+     * Read the contents of this &lt;exit&gt; element.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param tt The parent {@link TransitionTarget} for this action.
+     * @param executable The parent {@link Executable} for this action.
+     * @param iff The optional parent {@link If} if this action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readExit(final XMLStreamReader reader, final Configuration configuration,
+            final TransitionTarget tt, final Executable executable, final If iff)
+    throws XMLStreamException {
+
+        Exit exit = new Exit();
+        readNamespaces(configuration, exit);
+        exit.setParent(executable);
+        if (iff != null) {
+            iff.addAction(exit);
+        } else {
+            executable.addAction(exit);
+        }
+
+    }
+
+    /**
+     * Read the contents of this custom action.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param customAction The {@link CustomAction} to read.
+     * @param tt The parent {@link TransitionTarget} for this custom action.
+     * @param executable The parent {@link Executable} for this custom action.
+     * @param iff The optional parent {@link If} if this custom action is a child of one.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static void readCustomAction(final XMLStreamReader reader, final Configuration configuration,
+            final CustomAction customAction, final TransitionTarget tt, final Executable executable,
+            final If iff)
+    throws XMLStreamException {
+
+        // Instantiate custom action
+        Object actionObject = null;
+        String className = customAction.getActionClass().getName();
+        ClassLoader cl = configuration.customActionClassLoader;
+        if (configuration.useContextClassLoaderForCustomActions) {
+            cl = Thread.currentThread().getContextClassLoader();
+        }
+        if (cl == null) {
+            cl = SCXMLReader.class.getClassLoader();
+        }
+        Class<?> clazz = null;
+        try {
+            clazz = cl.loadClass(className);
+            actionObject = clazz.newInstance();
+        } catch (ClassNotFoundException cnfe) {
+            throw new XMLStreamException("Cannot find custom action class:" + className, cnfe);
+        } catch (IllegalAccessException iae) {
+            throw new XMLStreamException("Cannot access custom action class:" + className, iae);
+        } catch (InstantiationException ie) {
+            throw new XMLStreamException("Cannot instantiate custom action class:" + className, ie);
+        }
+        if (!(actionObject instanceof Action)) {
+            throw new IllegalArgumentException(ERR_CUSTOM_ACTION_TYPE + className);
+        }
+
+        // Set the attribute values as properties
+        Action action = (Action) actionObject;
+        for (int i = 0; i < reader.getAttributeCount(); i++) {
+            String name = reader.getAttributeLocalName(i);
+            String value = reader.getAttributeValue(i);
+            String setter = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
+            Method method = null;
+            try {
+                method = clazz.getMethod(setter, String.class);
+                method.invoke(action, value);
+            } catch (NoSuchMethodException nsme) {
+                throw new XMLStreamException("No setter in class:" + className + ", for string property:" + name,
+                        nsme);
+            } catch (InvocationTargetException ite) {
+                throw new XMLStreamException("Exception calling setter for string property:" + name + " in class:"
+                        + className, ite);
+            } catch (IllegalAccessException iae) {
+                throw new XMLStreamException("Cannot access setter for string property:" + name + " in class:"
+                        + className, iae);
+            }
+        }
+
+        // Add any body content if necessary
+        if (action instanceof ExternalContent) {
+            Node body = readNode(reader, configuration, customAction.getNamespaceURI(),
+                    customAction.getLocalName(), new String [] {});
+            NodeList childNodes = body.getChildNodes();
+            List<Node> externalNodes = ((ExternalContent) action).getExternalNodes();
+            for (int i = 0; i < childNodes.getLength(); i++) {
+                externalNodes.add(childNodes.item(i));
+            }
+        }
+
+        // Wire in the action and add to parent
+        readNamespaces(configuration, action);
+        action.setParent(executable);
+        if (iff != null) {
+            iff.addAction(action);
+        } else {
+            executable.addAction(action);
+        }
+
+    }
+
+    /**
+     * Read the following contents into a DOM {@link Node}.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param configuration The {@link Configuration} to use while parsing.
+     * @param namespaceURI The namespace URI of the parent element (we will stop parsing into DOM nodes when we reach
+     *                     the corresponding end tag)
+     * @param localName The local name of the parent element (we will stop parsing into DOM nodes when we reach the
+     *                  corresponding end tag)
+     * @param attrs The attributes that will be read into the root DOM node.
+     *
+     * @return The parsed content as a DOM {@link Node}.
+     *
+     * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     */
+    private static Node readNode(final XMLStreamReader reader, final Configuration configuration,
+            final String namespaceURI, final String localName, final String[] attrs)
+    throws XMLStreamException {
+
+        // Create a document in which to build the DOM node
+        Document document = null;
+        try {
+            document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+        } catch (ParserConfigurationException pce) {
+            throw new XMLStreamException(ERR_PARSER_CFG);
+        }
+
+        // This root element will be returned, add any attributes as specified
+        Element root = document.createElementNS(namespaceURI, localName);
+        for (int i = 0; i < attrs.length; i++) {
+            Attr attr = document.createAttributeNS(XMLNS_DEFAULT, attrs[i]);
+            attr.setValue(readAV(reader, attrs[i]));
+            root.setAttributeNodeNS(attr);
+        }
+        document.appendChild(root);
+
+        // <data> can have only one child element, flags to skip any text nodes on either side
+        boolean one = (XMLNS_SCXML.equals(namespaceURI) && ELEM_DATA.equals(localName));
+        boolean text = false;
+        Node parent = root;
+        String nodeNSURI = null, nodeName = null;
+
+        // Convert stream to DOM node(s) while maintaining parent child relationships
+        loop : while (reader.hasNext()) {
+            String name, nsURI;
+            Node child = null;
+            switch (reader.next()) {
+                case XMLStreamConstants.START_ELEMENT:
+                    pushNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (!text) {
+                        nodeNSURI = nsURI;
+                        nodeName = name;
+                        text = true;
+                    }
+                    Element elem = document.createElementNS(nsURI, name);
+                    for (int i = 0; i < reader.getAttributeCount(); i++) {
+                        nsURI = reader.getAttributeNamespace(i);
+                        name = reader.getAttributeLocalName(i);
+                        String prefix = reader.getAttributePrefix(i);
+                        if (prefix != null && prefix.length() > 0) {
+                            name = prefix + ":" + name;
+                        }
+                        Attr attr = document.createAttributeNS(nsURI, name);
+                        attr.setValue(reader.getAttributeValue(i));
+                        elem.setAttributeNodeNS(attr);
+                    }
+                    parent.appendChild(elem);
+                    parent = elem;
+                    break;
+                case XMLStreamConstants.SPACE:
+                case XMLStreamConstants.CHARACTERS:
+                case XMLStreamConstants.ENTITY_REFERENCE:
+                    if (text || !one) {
+                        child = document.createTextNode(reader.getText());
+                    }
+                    break;
+                case XMLStreamConstants.CDATA:
+                    child = document.createCDATASection(reader.getText());
+                    break;
+                case XMLStreamConstants.COMMENT:
+                    child = document.createComment(reader.getText());
+                    break;
+                case XMLStreamConstants.END_ELEMENT:
+                    popNamespaces(reader, configuration);
+                    nsURI = reader.getNamespaceURI();
+                    name = reader.getLocalName();
+                    if (namespaceURI.equals(nsURI) && localName.equals(name)) {
+                        break loop;
+                    }
+                    if (((nodeNSURI == null && nsURI == null) || (nodeNSURI != null && nodeNSURI.equals(nsURI)))
+                            && name.equals(nodeName)) {
+                        text = false;
+                    }
+                    parent = parent.getParentNode();
+                    if (parent == document) {
+                        parent = root;
+                    }
+                    break;
+                default: // rest is ignored
+            }
+            if (child != null) {
+                parent.appendChild(child);
+            }
+        }
+        return root;
+    }
+
+    /**
+     * Get the attribute value at the current reader location.
+     *
+     * @param reader The {@link XMLStreamReader} providing the SCXML document to parse.
+     * @param attrLocalName The attribute name whose value is needed.
+     *
+     * @return The value of the attribute.
+     */
+    private static String readAV(final XMLStreamReader reader, final String attrLocalName) {
+        return reader.getAttributeValue(XMLNS_DEFAULT, attrLocalName);
+    }
+
+    /**

[... 468 lines stripped ...]


Mime
View raw message