You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by wo...@apache.org on 2013/12/05 03:59:34 UTC

svn commit: r1548001 - in /commons/proper/scxml/trunk/src: main/java/org/apache/commons/scxml2/io/SCXMLReader.java test/java/org/apache/commons/scxml2/io/SCXMLReaderTest.java test/java/org/apache/commons/scxml2/io/scxml-with-invalid-elems.xml

Author: woonsan
Date: Thu Dec  5 02:59:34 2013
New Revision: 1548001

URL: http://svn.apache.org/r1548001
Log:
SCXML-177: adding strict option and silent option in SCXMLReader

Added:
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/scxml-with-invalid-elems.xml
Modified:
    commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
    commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/SCXMLReaderTest.java

Modified: commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java?rev=1548001&r1=1548000&r2=1548001&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java (original)
+++ commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml2/io/SCXMLReader.java Thu Dec  5 02:59:34 2013
@@ -818,10 +818,12 @@ public final class SCXMLReader {
      * @param parent The parent {@link TransitionTarget} for this final (null for top level state).
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readFinal(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
             final TransitionTarget parent)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         Final end = new Final();
         end.setId(readAV(reader, ATTR_ID));
@@ -1002,10 +1004,12 @@ public final class SCXMLReader {
      * @param parent The parent {@link TransitionTarget} for this datamodel (null for top level).
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readDatamodel(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
             final TransitionTarget parent)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         Datamodel dm = new Datamodel();
 
@@ -1075,10 +1079,12 @@ public final class SCXMLReader {
      * @param parent The parent {@link State} for this invoke.
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readInvoke(final XMLStreamReader reader, final Configuration configuration,
             final State parent)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         Invoke invoke = new Invoke();
         invoke.setSrc(readAV(reader, ATTR_SRC));
@@ -1153,10 +1159,12 @@ public final class SCXMLReader {
      * @param invoke The parent {@link Invoke} for this finalize.
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readFinalize(final XMLStreamReader reader, final Configuration configuration,
             final State state, final Invoke invoke)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         Finalize finalize = new Finalize();
         readExecutableContext(reader, configuration, state, finalize, null);
@@ -1191,10 +1199,12 @@ public final class SCXMLReader {
      * @param state The parent composite {@link State} for this initial.
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readInitial(final XMLStreamReader reader, final Configuration configuration,
             final State state)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         Initial initial = new Initial();
 
@@ -1241,10 +1251,12 @@ public final class SCXMLReader {
      * @param tt The parent {@link TransitionTarget} for this history.
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readHistory(final XMLStreamReader reader, final Configuration configuration,
             final SCXML scxml, final TransitionTarget tt)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         History history = new History();
         history.setId(readAV(reader, ATTR_ID));
@@ -1294,10 +1306,12 @@ public final class SCXMLReader {
      * @param tt The parent {@link TransitionTarget} for this onentry.
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readOnEntry(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
             final TransitionTarget tt)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         OnEntry onentry = new OnEntry();
         readExecutableContext(reader, configuration, tt, onentry, null);
@@ -1314,10 +1328,12 @@ public final class SCXMLReader {
      * @param tt The parent {@link TransitionTarget} for this onexit.
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readOnExit(final XMLStreamReader reader, final Configuration configuration, final SCXML scxml,
             final TransitionTarget tt)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         OnExit onexit = new OnExit();
         readExecutableContext(reader, configuration, tt, onexit, null);
@@ -1333,10 +1349,12 @@ public final class SCXMLReader {
      * @param tt The parent {@link TransitionTarget} for this transition.
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readTransition(final XMLStreamReader reader, final Configuration configuration,
             final TransitionTarget tt)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         Transition t = new Transition();
         t.setCond(readAV(reader, ATTR_COND));
@@ -1368,10 +1386,12 @@ public final class SCXMLReader {
      * @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}.
+     * @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).
      */
     private static void readExecutableContext(final XMLStreamReader reader, final Configuration configuration,
             final TransitionTarget tt, final Executable executable, final If iff)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         String end = "";
         if (iff != null) {
@@ -1492,10 +1512,12 @@ public final class SCXMLReader {
      * @param parent The optional parent {@link If} if this <if> is a child of another.
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void readIf(final XMLStreamReader reader, final Configuration configuration,
             final TransitionTarget tt, final Executable executable, final If parent)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         If iff = new If();
         iff.setCond(readAV(reader, ATTR_COND));
@@ -2066,16 +2088,23 @@ public final class SCXMLReader {
      * @param name The local name of the ignored element.
      *
      * @throws XMLStreamException An exception processing the underlying {@link XMLStreamReader}.
+     * @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).
      */
     private static void reportIgnoredElement(final XMLStreamReader reader, final Configuration configuration,
             final String parent, final String nsURI, final String name)
-    throws XMLStreamException {
+    throws XMLStreamException, ModelException {
 
         org.apache.commons.logging.Log log = LogFactory.getLog(SCXMLReader.class);
         StringBuffer sb = new StringBuffer();
         sb.append("Ignoring unknown or invalid element <").append(name).append("> in namespace \"").append(nsURI).append("\" as child ").
             append(" of <").append(parent).append("> at ").append(reader.getLocation());
-        log.warn(sb.toString());
+        if (!configuration.isSilent() && log.isWarnEnabled()) {
+            log.warn(sb.toString());
+        }
+        if (configuration.isStrict()) {
+            throw new ModelException(sb.toString());
+        }
         XMLReporter reporter = configuration.reporter;
         if (reporter != null) {
             reporter.report(sb.toString(), "COMMONS_SCXML", null, reader.getLocation());
@@ -2354,6 +2383,18 @@ public final class SCXMLReader {
          */
         PathResolver pathResolver;
 
+        /**
+         * Whether to silently ignore any unknown or invalid elements
+         * or to leave warning logs for those.
+         */
+        boolean silent;
+
+        /**
+         * Whether to strictly throw a model exception when there are any unknown or invalid elements
+         * or to leniently allow to read the model even with those.
+         */
+        boolean strict;
+
         /*
          * Public constructors
          */
@@ -2473,6 +2514,42 @@ public final class SCXMLReader {
                 final String encoding, final String systemId, final boolean validate, final PathResolver pathResolver,
                 final SCXML parent, final List<CustomAction> customActions, final ClassLoader customActionClassLoader,
                 final boolean useContextClassLoaderForCustomActions) {
+            this(factoryId, factoryClassLoader, allocator, properties, resolver, reporter, encoding, systemId,
+                    validate, pathResolver, parent, customActions, customActionClassLoader,
+                    useContextClassLoaderForCustomActions, false, false);
+        }
+
+        /**
+         * All-purpose package access constructor.
+         *
+         * @param factoryId The <code>factoryId</code> to use.
+         * @param factoryClassLoader The {@link ClassLoader} to use for the {@link XMLInputFactory} instance to
+         *                           create.
+         * @param allocator The {@link XMLEventAllocator} for the {@link XMLInputFactory}.
+         * @param properties The map of properties (keys are property name strings, values are object property values)
+         *                   for the {@link XMLInputFactory}.
+         * @param resolver The {@link XMLResolver} for the {@link XMLInputFactory}.
+         * @param reporter The {@link XMLReporter} for the {@link XMLInputFactory}.
+         * @param encoding The <code>encoding</code> to use for the {@link XMLStreamReader}
+         * @param systemId The <code>systemId</code> to use for the {@link XMLStreamReader}
+         * @param validate Whether to validate the input with the XML Schema for SCXML.
+         * @param pathResolver The Commons SCXML {@link PathResolver} to use for this document.
+         * @param parent The parent SCXML document if this document is src'ed in via the &lt;state&gt; or
+         *               &lt;parallel&gt; element's "src" attribute.
+         * @param customActions The list of Commons SCXML custom actions that will be available for this document.
+         * @param customActionClassLoader The {@link ClassLoader} to use for the {@link CustomAction} instances to
+         *                                create.
+         * @param useContextClassLoaderForCustomActions Whether to use the thread context {@link ClassLoader} for the
+         *                                             {@link CustomAction} instances to create.
+         * @param silent Whether to silently ignore any unknown or invalid elements or to leave warning logs for those.
+         * @param strict Whether to strictly throw a model exception when there are any unknown or invalid elements
+         *               or to leniently allow to read the model even with those.
+         */
+        Configuration(final String factoryId, final ClassLoader factoryClassLoader, final XMLEventAllocator allocator,
+                final Map<String, Object> properties, final XMLResolver resolver, final XMLReporter reporter,
+                final String encoding, final String systemId, final boolean validate, final PathResolver pathResolver,
+                final SCXML parent, final List<CustomAction> customActions, final ClassLoader customActionClassLoader,
+                final boolean useContextClassLoaderForCustomActions, final boolean silent, final boolean strict) {
             this.factoryId = factoryId;
             this.factoryClassLoader = factoryClassLoader;
             this.allocator = allocator;
@@ -2488,6 +2565,8 @@ public final class SCXMLReader {
             this.customActionClassLoader = customActionClassLoader;
             this.useContextClassLoaderForCustomActions = useContextClassLoaderForCustomActions;
             this.namespaces = new HashMap<String, Stack<String>>();
+            this.silent = silent;
+            this.strict = strict;
         }
 
         /*
@@ -2507,6 +2586,42 @@ public final class SCXMLReader {
             return currentNamespaces;
         }
 
+        /**
+         * Returns true if it is set to read models silently without any model error warning logs.
+         * @return
+         * @see {@link #silent}
+         */
+        public boolean isSilent() {
+            return silent;
+        }
+
+        /**
+         * Turn on/off silent mode (whether to read models silently without any model error warning logs)
+         * @param silent
+         * @see {@link #silent}
+         */
+        public void setSilent(boolean silent) {
+            this.silent = silent;
+        }
+
+        /**
+         * Returns true if it is set to check model strictly with throwing exceptions on any model error.
+         * @return
+         * @see {@link #strict}
+         */
+        public boolean isStrict() {
+            return strict;
+        }
+
+        /**
+         * Turn on/off strict model (whether to check model strictly with throwing exception on any model error)
+         * @param strict
+         * @see {@link #strict}
+         */
+        public void setStrict(boolean strict) {
+            this.strict = strict;
+        }
+
     }
 
 }

Modified: commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/SCXMLReaderTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/SCXMLReaderTest.java?rev=1548001&r1=1548000&r2=1548001&view=diff
==============================================================================
--- commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/SCXMLReaderTest.java (original)
+++ commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/SCXMLReaderTest.java Thu Dec  5 02:59:34 2013
@@ -20,17 +20,27 @@ import java.io.IOException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedList;
 import java.util.List;
 
+import javax.xml.stream.XMLStreamException;
+
 import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogConfigurationException;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.impl.LogFactoryImpl;
+import org.apache.commons.logging.impl.SimpleLog;
 import org.apache.commons.scxml2.ErrorReporter;
 import org.apache.commons.scxml2.EventDispatcher;
 import org.apache.commons.scxml2.SCInstance;
 import org.apache.commons.scxml2.SCXMLExpressionException;
 import org.apache.commons.scxml2.SCXMLTestHelper;
 import org.apache.commons.scxml2.TriggerEvent;
+import org.apache.commons.scxml2.io.SCXMLReader.Configuration;
 import org.apache.commons.scxml2.model.Action;
 import org.apache.commons.scxml2.model.CustomAction;
+import org.apache.commons.scxml2.model.Data;
+import org.apache.commons.scxml2.model.Datamodel;
 import org.apache.commons.scxml2.model.ExternalContent;
 import org.apache.commons.scxml2.model.Final;
 import org.apache.commons.scxml2.model.ModelException;
@@ -39,28 +49,49 @@ import org.apache.commons.scxml2.model.S
 import org.apache.commons.scxml2.model.State;
 import org.apache.commons.scxml2.model.Transition;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.w3c.dom.Node;
 
-import javax.xml.stream.XMLStreamException;
 /**
  * Unit tests {@link org.apache.commons.scxml2.io.SCXMLReader}.
  */
 public class SCXMLReaderTest {
 
+    private static String oldLogFactoryProperty;
+
     // Test data
     private URL microwave01, microwave02, transitions01, prefix01, send01,
-        microwave03, microwave04, scxmlinitialattr, action01;
+        microwave03, microwave04, scxmlinitialattr, action01,
+        scxmlWithInvalidElems;
     private SCXML scxml;
     private String scxmlAsString;
 
+    private Log scxmlReaderLog;
+
+    @BeforeClass
+    public static void beforeClass() {
+        oldLogFactoryProperty = System.getProperty(LogFactory.FACTORY_PROPERTY);
+        System.setProperty(LogFactory.FACTORY_PROPERTY, RecordingLogFactory.class.getName());
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        if (oldLogFactoryProperty == null) {
+            System.clearProperty(LogFactory.FACTORY_PROPERTY);
+        } else {
+            System.setProperty(LogFactory.FACTORY_PROPERTY, oldLogFactoryProperty);
+        }
+    }
+
     /**
      * Set up instance variables required by this test case.
      */
     @Before
-    public void setUp() {
+    public void before() {
         microwave01 = this.getClass().getClassLoader().
             getResource("org/apache/commons/scxml2/env/jsp/microwave-01.xml");
         microwave02 = this.getClass().getClassLoader().
@@ -79,14 +110,20 @@ public class SCXMLReaderTest {
             getResource("org/apache/commons/scxml2/io/scxml-initial-attr.xml");
         action01 = this.getClass().getClassLoader().
             getResource("org/apache/commons/scxml2/io/custom-action-body-test-1.xml");
+        scxmlWithInvalidElems = this.getClass().getClassLoader().
+            getResource("org/apache/commons/scxml2/io/scxml-with-invalid-elems.xml");
+
+        scxmlReaderLog = LogFactory.getLog(SCXMLReader.class);
+        clearRecordedLogMessages();
     }
 
     /**
      * Tear down instance variables required by this test case.
      */
     @After
-    public void tearDown() {
-        microwave01 = microwave02 = microwave03 = microwave04 = transitions01 = prefix01 = send01 = action01 = null;
+    public void after() {
+        microwave01 = microwave02 = microwave03 = microwave04 = transitions01 = prefix01 = send01 = action01 = 
+                scxmlinitialattr = scxmlWithInvalidElems = null;
         scxml = null;
         scxmlAsString = null;
     }
@@ -192,12 +229,113 @@ public class SCXMLReaderTest {
         Assert.assertTrue(my.getExternalNodes().size() > 0);
     }
 
+    @Test
+    public void testSCXMLReaderWithInvalidElements() throws Exception {
+        // In the default lenient/verbose mode (strict == false && silent == false),
+        // the model exception should be just logged without a model exception.
+        Configuration configuration = new Configuration();
+        scxml = SCXMLReader.read(scxmlWithInvalidElems, configuration);
+        Assert.assertNotNull(scxml);
+        scxmlAsString = serialize(scxml);
+        Assert.assertNotNull(scxmlAsString);
+        Final foo = (Final) scxml.getInitialTarget();
+        Assert.assertEquals("foo", foo.getId());
+        Datamodel dataModel = scxml.getDatamodel();
+        Assert.assertNotNull(dataModel);
+        List<Data> dataList = dataModel.getData();
+        Assert.assertEquals(1, dataList.size());
+        Assert.assertEquals("time", dataList.get(0).getId());
+        assertContainsRecordedLogMessage("Ignoring unknown or invalid element <baddata> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <datamodel>");
+        assertContainsRecordedLogMessage("Ignoring unknown or invalid element <baddata> in namespace \"http://www.example.com/scxml\" as child  of <datamodel>");
+        assertContainsRecordedLogMessage("Ignoring unknown or invalid element <trace> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <onentry>");
+        assertContainsRecordedLogMessage("Ignoring unknown or invalid element <onbeforeexit> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <final>");
+
+        // In the lenient/silent mode (strict == false && silent == true),
+        // no model exception is logged.
+        clearRecordedLogMessages();
+        scxml = null;
+        configuration = new Configuration();
+        configuration.setStrict(false);
+        configuration.setSilent(true);
+        scxml = SCXMLReader.read(scxmlWithInvalidElems, configuration);
+        Assert.assertNotNull(scxml);
+        scxmlAsString = serialize(scxml);
+        Assert.assertNotNull(scxmlAsString);
+        foo = (Final) scxml.getInitialTarget();
+        Assert.assertEquals("foo", foo.getId());
+        dataModel = scxml.getDatamodel();
+        Assert.assertNotNull(dataModel);
+        dataList = dataModel.getData();
+        Assert.assertEquals(1, dataList.size());
+        Assert.assertEquals("time", dataList.get(0).getId());
+        assertNotContainsRecordedLogMessage("Ignoring unknown or invalid element <baddata> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <datamodel>");
+        assertNotContainsRecordedLogMessage("Ignoring unknown or invalid element <baddata> in namespace \"http://www.example.com/scxml\" as child  of <datamodel>");
+        assertNotContainsRecordedLogMessage("Ignoring unknown or invalid element <trace> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <onentry>");
+        assertNotContainsRecordedLogMessage("Ignoring unknown or invalid element <onbeforeexit> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <final>");
+
+        // In strict/verbose mode (strict == true && silent == false), it should fail to read the model and catch a model exception
+        // with warning logs because of the invalid <baddata> element.
+        clearRecordedLogMessages();
+        scxml = null;
+        configuration = new Configuration();
+        configuration.setStrict(true);
+        configuration.setSilent(false);
+        try {
+            scxml = SCXMLReader.read(scxmlWithInvalidElems, configuration);
+            Assert.fail("In strict mode, it should have thrown a model exception.");
+        } catch (ModelException e) {
+            Assert.assertTrue(e.getMessage().contains("Ignoring unknown or invalid element <baddata>"));
+        }
+        assertContainsRecordedLogMessage("Ignoring unknown or invalid element <baddata> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <datamodel>");
+        assertContainsRecordedLogMessage("Ignoring unknown or invalid element <baddata> in namespace \"http://www.example.com/scxml\" as child  of <datamodel>");
+        assertContainsRecordedLogMessage("Ignoring unknown or invalid element <trace> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <onentry>");
+        assertContainsRecordedLogMessage("Ignoring unknown or invalid element <onbeforeexit> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <final>");
+
+        // In strict/silent mode (strict == true && silent == true), it should fail to read the model and catch a model exception
+        // without warning logs because of the invalid <baddata> element.
+        clearRecordedLogMessages();
+        scxml = null;
+        configuration = new Configuration();
+        configuration.setStrict(true);
+        configuration.setSilent(true);
+        try {
+            scxml = SCXMLReader.read(scxmlWithInvalidElems, configuration);
+            Assert.fail("In strict mode, it should have thrown a model exception.");
+        } catch (ModelException e) {
+            Assert.assertTrue(e.getMessage().contains("Ignoring unknown or invalid element <baddata>"));
+        }
+        assertNotContainsRecordedLogMessage("Ignoring unknown or invalid element <baddata> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <datamodel>");
+        assertNotContainsRecordedLogMessage("Ignoring unknown or invalid element <baddata> in namespace \"http://www.example.com/scxml\" as child  of <datamodel>");
+        assertNotContainsRecordedLogMessage("Ignoring unknown or invalid element <trace> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <onentry>");
+        assertNotContainsRecordedLogMessage("Ignoring unknown or invalid element <onbeforeexit> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <final>");
+    }
+
     private String serialize(final SCXML scxml) throws IOException, XMLStreamException {
         scxmlAsString = SCXMLWriter.write(scxml);
         Assert.assertNotNull(scxmlAsString);
         return scxmlAsString;
     }
 
+    private void assertContainsRecordedLogMessage(final String message) {
+        if (scxmlReaderLog instanceof RecordingSimpleLog) {
+            Assert.assertTrue(((RecordingSimpleLog) scxmlReaderLog).containsMessage(
+                    "Ignoring unknown or invalid element <baddata> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <datamodel>"));
+        }
+    }
+
+    private void assertNotContainsRecordedLogMessage(final String message) {
+        if (scxmlReaderLog instanceof RecordingSimpleLog) {
+            Assert.assertFalse(((RecordingSimpleLog) scxmlReaderLog).containsMessage(
+                    "Ignoring unknown or invalid element <baddata> in namespace \"http://www.w3.org/2005/07/scxml\" as child  of <datamodel>"));
+        }
+    }
+
+    private void clearRecordedLogMessages() {
+        if (scxmlReaderLog instanceof RecordingSimpleLog) {
+            ((RecordingSimpleLog) scxmlReaderLog).clearMessages();
+        }
+    }
+
     public static class MyAction extends Action implements ExternalContent {
         private static final long serialVersionUID = 1L;
 
@@ -218,5 +356,60 @@ public class SCXMLReaderTest {
 
     }
 
+    /**
+     * Custom LogFactory implementation to capture log messages for logging verification.
+     */
+    public static class RecordingLogFactory extends LogFactoryImpl {
+        @Override
+        protected Log newInstance(String name) throws LogConfigurationException {
+            return new RecordingSimpleLog(name);
+        }
+    }
+
+    /**
+     * Custom Simple Log implemenation capturing log messages
+     */
+    public static class RecordingSimpleLog extends SimpleLog {
+
+        private static final long serialVersionUID = 1L;
+
+        private List<String> messages = new LinkedList<String>();
+
+        public RecordingSimpleLog(String name) {
+            super(name);
+        }
+
+        /**
+         * Clear all the recorded log messages.
+         */
+        public void clearMessages() {
+            messages.clear();
+        }
+
+        /**
+         * Return true if msg is found in any recorded log messages.
+         * @param msg
+         * @return
+         */
+        public boolean containsMessage(final String msg) {
+            for (String message : messages) {
+                if (message.contains(msg)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        protected boolean isLevelEnabled(int logLevel) {
+            return (logLevel >= LOG_LEVEL_INFO);
+        }
+
+        @Override
+        protected void log(int type, Object message, Throwable t) {
+            super.log(type, message, t);
+            messages.add(message.toString());
+        }
+    }
 }
 

Added: commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/scxml-with-invalid-elems.xml
URL: http://svn.apache.org/viewvc/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/scxml-with-invalid-elems.xml?rev=1548001&view=auto
==============================================================================
--- commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/scxml-with-invalid-elems.xml (added)
+++ commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml2/io/scxml-with-invalid-elems.xml Thu Dec  5 02:59:34 2013
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!--
+ * 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.
+-->
+<!-- Used for SrcTest.java in io package -->
+<scxml xmlns="http://www.w3.org/2005/07/scxml"
+       xmlns:example="http://www.example.com/scxml"
+       version="1.0"
+       initial="foo">
+
+  <datamodel>
+    <data id="time"/>
+    <baddata id="badtime"/>
+    <example:baddata id="badtime2"/>
+  </datamodel>
+
+  <final id="foo">
+    <onentry>
+      <!-- <trace/> is invalid. -->
+      <trace expr="'tracing...'" />
+    </onentry>
+    <!-- <onbeforeexit/> is invalid. -->
+    <onbeforeexit>
+    </onbeforeexit>
+  </final>
+
+</scxml>