[jbpm-commits] JBoss JBPM SVN: r3284 - in jbpm4/trunk/modules: jpdl/src/test/java/org/jbpm/test/xml and 2 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Tue Dec 9 06:36:55 EST 2008


Author: tom.baeyens at jboss.com
Date: 2008-12-09 06:36:55 -0500 (Tue, 09 Dec 2008)
New Revision: 3284

Added:
   jbpm4/trunk/modules/jpdl/src/test/resources/org/jbpm/test/xml/nonamespace.jpdl.xml
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/DomBuilder.java
Modified:
   jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/xml/JpdlParser.java
   jbpm4/trunk/modules/jpdl/src/test/java/org/jbpm/test/xml/JpdlXmlTest.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/Parse.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/Parser.java
Log:
schema validation

Modified: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/xml/JpdlParser.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/xml/JpdlParser.java	2008-12-09 11:18:02 UTC (rev 3283)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/xml/JpdlParser.java	2008-12-09 11:36:55 UTC (rev 3284)
@@ -26,6 +26,9 @@
 import java.util.Enumeration;
 import java.util.List;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.SAXParser;
+
 import org.jbpm.activity.Activity;
 import org.jbpm.jpdl.JpdlProcessDefinition;
 import org.jbpm.log.Log;
@@ -34,9 +37,13 @@
 import org.jbpm.pvm.internal.model.TransitionImpl;
 import org.jbpm.pvm.internal.util.ReflectUtil;
 import org.jbpm.pvm.internal.util.XmlUtil;
+import org.jbpm.pvm.internal.xml.DomBuilder;
 import org.jbpm.pvm.internal.xml.Parse;
 import org.jbpm.pvm.internal.xml.Parser;
+import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
 
 /**
  * @author Tom Baeyens
@@ -53,9 +60,11 @@
   static ActivitiesParser activityParser = new ActivitiesParser();
 
   public JpdlParser() {
+    initialize(); 
+    
     Activities activitiesConfiguration = parseActivitiesConfiguration();
     setBindings(activitiesConfiguration.bindings);
-    // setSchemaResources(activitiesConfiguration.schemaResources);
+    setSchemaResources(activitiesConfiguration.schemaResources);
   }
 
   protected Activities parseActivitiesConfiguration() {
@@ -81,7 +90,6 @@
     return activities;
   }
 
-
   public Object parseDocumentElement(Element documentElement, Parse parse) {
     ProcessDefinitionImpl processDefinition = (ProcessDefinitionImpl) parse.getDocumentObject();
     if (processDefinition==null) {

Modified: jbpm4/trunk/modules/jpdl/src/test/java/org/jbpm/test/xml/JpdlXmlTest.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/test/java/org/jbpm/test/xml/JpdlXmlTest.java	2008-12-09 11:18:02 UTC (rev 3283)
+++ jbpm4/trunk/modules/jpdl/src/test/java/org/jbpm/test/xml/JpdlXmlTest.java	2008-12-09 11:36:55 UTC (rev 3284)
@@ -41,7 +41,7 @@
 
     assertEquals(problems.toString(), 0, problems.size());
   }
-
+  
   public void testInvalidXml() {
     List<Problem> problems = new JpdlParser()
       .createParse()
@@ -51,4 +51,14 @@
 
     assertEquals(problems.toString(), 1, problems.size());
   }
+
+  public void testNoNamespace() {
+    List<Problem> problems = new JpdlParser()
+      .createParse()
+      .setResource("org/jbpm/test/xml/nonamespace.jpdl.xml")
+      .execute()
+      .getProblems();
+
+    assertEquals(problems.toString(), 0, problems.size());
+  }
 }

Added: jbpm4/trunk/modules/jpdl/src/test/resources/org/jbpm/test/xml/nonamespace.jpdl.xml
===================================================================
--- jbpm4/trunk/modules/jpdl/src/test/resources/org/jbpm/test/xml/nonamespace.jpdl.xml	                        (rev 0)
+++ jbpm4/trunk/modules/jpdl/src/test/resources/org/jbpm/test/xml/nonamespace.jpdl.xml	2008-12-09 11:36:55 UTC (rev 3284)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<process name="Purchase order">
+
+  <start />
+
+  <buzzz>
+  
+  </buzzz>
+
+</process>

Added: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/DomBuilder.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/DomBuilder.java	                        (rev 0)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/DomBuilder.java	2008-12-09 11:36:55 UTC (rev 3284)
@@ -0,0 +1,851 @@
+/*
+ * 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.
+ */
+/*
+ * $Id: DebugDomBuilder.java 1434 2008-07-01 10:32:10Z heiko.braun at jboss.com $
+ */
+package org.jbpm.pvm.internal.xml;
+
+import java.util.Stack;
+import java.util.Vector;
+
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.DefaultHandler;
+
+/** builds the dom model from SAX events, optionally adding the line and 
+ * column number as attributes to every element. */
+public class DomBuilder extends DefaultHandler implements ContentHandler, LexicalHandler {  /** Root document */
+
+  public Document document;
+  
+  protected String debugNamespace = null;
+  protected String lineAttributeName = "line";
+  protected String columnAttributeName = null;
+
+  /** Current node */
+  protected Node currentNode = null;
+
+  /** The root node */
+  protected Node root = null;
+
+  /** The next sibling node */
+  protected Node nextSibling = null;
+
+  /** First node of document fragment or null if not a DocumentFragment */
+  public DocumentFragment docFrag = null;
+
+  /** Vector of element nodes */
+  protected Stack elemStack = new Stack();
+
+  /** Namespace support */
+  protected Vector prefixMappings = new Vector();
+
+  /** to obtain the line number information */
+  protected Locator locator = null;
+
+  /**
+   * Get the root document or DocumentFragment of the DOM being created.
+   * 
+   * @return The root document or document fragment if not null
+   */
+  public Node getRootDocument() {
+    return (null != this.docFrag) ? (Node) this.docFrag : (Node) this.document;
+  }
+
+  /**
+   * Get the root node of the DOM tree.
+   */
+  public Node getRootNode() {
+    return this.root;
+  }
+
+  /**
+   * Get the node currently being processed.
+   * 
+   * @return the current node being processed
+   */
+  public Node getCurrentNode() {
+    return this.currentNode;
+  }
+
+  /**
+   * Set the next sibling node, which is where the result nodes should be
+   * inserted before.
+   * 
+   * @param nextSibling
+   *          the next sibling node.
+   */
+  public void setNextSibling(Node nextSibling) {
+    this.nextSibling = nextSibling;
+  }
+
+  /**
+   * Return the next sibling node.
+   * 
+   * @return the next sibling node.
+   */
+  public Node getNextSibling() {
+    return this.nextSibling;
+  }
+
+  /**
+   * Return null since there is no Writer for this class.
+   * 
+   * @return null
+   */
+  public java.io.Writer getWriter() {
+    return null;
+  }
+
+  /**
+   * Append a node to the current container.
+   * 
+   * @param newNode
+   *          New node to append
+   */
+  protected void append(Node newNode) throws org.xml.sax.SAXException {
+
+    Node currentNode = this.currentNode;
+
+    if (null != currentNode) {
+      if (currentNode == this.root && this.nextSibling != null)
+        currentNode.insertBefore(newNode, this.nextSibling);
+      else
+        currentNode.appendChild(newNode);
+
+      // System.out.println(newNode.getNodeName());
+    } else if (null != this.docFrag) {
+      if (this.nextSibling != null)
+        this.docFrag.insertBefore(newNode, this.nextSibling);
+      else
+        this.docFrag.appendChild(newNode);
+    } else {
+      boolean ok = true;
+      short type = newNode.getNodeType();
+
+      if (type == Node.TEXT_NODE) {
+        String data = newNode.getNodeValue();
+
+        if ((null != data) && (data.trim().length() > 0)) {
+          throw new org.xml.sax.SAXException("Warning: can't output text before document element!  Ignoring...");
+        }
+
+        ok = false;
+      } else if (type == Node.ELEMENT_NODE) {
+        if (this.document.getDocumentElement() != null) {
+          ok = false;
+
+          throw new org.xml.sax.SAXException("Can't have more than one root on a DOM!");
+        }
+      }
+
+      if (ok) {
+        if (this.nextSibling != null)
+          this.document.insertBefore(newNode, this.nextSibling);
+        else
+          this.document.appendChild(newNode);
+      }
+    }
+  }
+
+  /**
+   * Receive an object for locating the origin of SAX document events.
+   * 
+   * <p>
+   * SAX parsers are strongly encouraged (though not absolutely required) to
+   * supply a locator: if it does so, it must supply the locator to the
+   * application by invoking this method before invoking any of the other
+   * methods in the ContentHandler interface.
+   * </p>
+   * 
+   * <p>
+   * The locator allows the application to determine the end position of any
+   * document-related event, even if the parser is not reporting an error.
+   * Typically, the application will use this information for reporting its own
+   * errors (such as character content that does not match an application's
+   * business rules). The information returned by the locator is probably not
+   * sufficient for use with a search engine.
+   * </p>
+   * 
+   * <p>
+   * Note that the locator will return correct information only during the
+   * invocation of the events in this interface. The application should not
+   * attempt to use it at any other time.
+   * </p>
+   * 
+   * @param locator
+   *          An object that can return the location of any SAX document event.
+   * @see org.xml.sax.Locator
+   */
+  public void setDocumentLocator(Locator locator) {
+    this.locator = locator;
+    // No action for the moment.
+  }
+
+  /**
+   * Receive notification of the beginning of a document.
+   * 
+   * <p>
+   * The SAX parser will invoke this method only once, before any other methods
+   * in this interface or in DTDHandler (except for setDocumentLocator).
+   * </p>
+   */
+  public void startDocument() throws org.xml.sax.SAXException {
+
+    // No action for the moment.
+  }
+
+  /**
+   * Receive notification of the end of a document.
+   * 
+   * <p>
+   * The SAX parser will invoke this method only once, and it will be the last
+   * method invoked during the parse. The parser shall not invoke this method
+   * until it has either abandoned parsing (because of an unrecoverable error)
+   * or reached the end of input.
+   * </p>
+   */
+  public void endDocument() throws org.xml.sax.SAXException {
+
+    // No action for the moment.
+  }
+
+  /**
+   * Receive notification of the beginning of an element.
+   * 
+   * <p>
+   * The Parser will invoke this method at the beginning of every element in the
+   * XML document; there will be a corresponding endElement() event for every
+   * startElement() event (even when the element is empty). All of the element's
+   * content will be reported, in order, before the corresponding endElement()
+   * event.
+   * </p>
+   * 
+   * <p>
+   * If the element name has a namespace prefix, the prefix will still be
+   * attached. Note that the attribute list provided will contain only
+   * attributes with explicit values (specified or defaulted): #IMPLIED
+   * attributes will be omitted.
+   * </p>
+   * 
+   * 
+   * @param ns
+   *          The namespace of the node
+   * @param localName
+   *          The local part of the qualified name
+   * @param name
+   *          The element name.
+   * @param atts
+   *          The attributes attached to the element, if any.
+   * @see #endElement
+   * @see org.xml.sax.Attributes
+   */
+  public void startElement(String ns, String localName, String name, Attributes atts) throws org.xml.sax.SAXException {
+
+    Element elem;
+
+    // Note that the namespace-aware call must be used to correctly
+    // construct a Level 2 DOM, even for non-namespaced nodes.
+    if ((null == ns) || (ns.length() == 0))
+      elem = this.document.createElementNS(null, name);
+    else
+      elem = this.document.createElementNS(ns, name);
+
+    append(elem);
+
+    try {
+      int nAtts = atts.getLength();
+
+      if (0 != nAtts) {
+        for (int i = 0; i < nAtts; i++) {
+
+          // System.out.println("type " + atts.getType(i) + " name " +
+          // atts.getLocalName(i) );
+          // First handle a possible ID attribute
+          if (atts.getType(i).equalsIgnoreCase("ID"))
+            setIDAttribute(atts.getValue(i), elem);
+
+          String attrNS = atts.getURI(i);
+
+          if ("".equals(attrNS))
+            attrNS = null; // DOM represents no-namespace as null
+
+          // System.out.println("attrNS: "+attrNS+", localName:
+          // "+atts.getQName(i)
+          // +", qname: "+atts.getQName(i)+", value: "+atts.getValue(i));
+          // Crimson won't let us set an xmlns: attribute on the DOM.
+          String attrQName = atts.getQName(i);
+
+          // In SAX, xmlns[:] attributes have an empty namespace, while in DOM
+          // they
+          // should have the xmlns namespace
+          if (attrQName.startsWith("xmlns:") || attrQName.equals("xmlns")) {
+            attrNS = "http://www.w3.org/2000/xmlns/";
+          }
+
+          // ALWAYS use the DOM Level 2 call!
+          elem.setAttributeNS(attrNS, attrQName, atts.getValue(i));
+        }
+      }
+
+      if (locator!=null) {
+        int lineNumber = locator.getLineNumber();
+        int columnNumber = locator.getColumnNumber();
+
+        if (debugNamespace==null) {
+          if (lineAttributeName!=null) {
+            elem.setAttribute(lineAttributeName, Integer.toString(lineNumber));
+          }
+          if (columnAttributeName!=null) {
+            elem.setAttribute(columnAttributeName, Integer.toString(columnNumber));
+          }
+          
+        } else {
+          if (lineAttributeName!=null) {
+            elem.setAttributeNS(debugNamespace, lineAttributeName, Integer.toString(lineNumber));
+          }
+          if (columnAttributeName!=null) {
+            elem.setAttributeNS(debugNamespace, columnAttributeName, Integer.toString(columnNumber));
+          }
+          
+        }
+      }
+
+
+      /*
+       * Adding namespace nodes to the DOM tree;
+       */
+      int nDecls = this.prefixMappings.size();
+
+      String prefix, declURL;
+
+      for (int i = 0; i < nDecls; i += 2) {
+        prefix = (String) this.prefixMappings.elementAt(i);
+
+        if (prefix == null)
+          continue;
+
+        declURL = (String) this.prefixMappings.elementAt(i + 1);
+
+        elem.setAttributeNS("http://www.w3.org/2000/xmlns/", prefix, declURL);
+      }
+
+      this.prefixMappings.clear();
+
+      // append(elem);
+
+      this.elemStack.push(elem);
+
+      this.currentNode = elem;
+
+      // append(elem);
+    } catch (java.lang.Exception de) {
+      // de.printStackTrace();
+      throw new org.xml.sax.SAXException(de);
+    }
+
+  }
+
+  /**
+   * 
+   * 
+   * 
+   * Receive notification of the end of an element.
+   * 
+   * <p>
+   * The SAX parser will invoke this method at the end of every element in the
+   * XML document; there will be a corresponding startElement() event for every
+   * endElement() event (even when the element is empty).
+   * </p>
+   * 
+   * <p>
+   * If the element name has a namespace prefix, the prefix will still be
+   * attached to the name.
+   * </p>
+   * 
+   * 
+   * @param ns
+   *          the namespace of the element
+   * @param localName
+   *          The local part of the qualified name of the element
+   * @param name
+   *          The element name
+   */
+  public void endElement(String ns, String localName, String name) throws org.xml.sax.SAXException {
+    this.elemStack.pop();
+    this.currentNode = this.elemStack.isEmpty() ? null : (Node) this.elemStack.peek();
+  }
+
+  /**
+   * Set an ID string to node association in the ID table.
+   * 
+   * @param id
+   *          The ID string.
+   * @param elem
+   *          The associated ID.
+   */
+  public void setIDAttribute(String id, Element elem) {
+
+    // Do nothing. This method is meant to be overiden.
+  }
+
+  /**
+   * Receive notification of character data.
+   * 
+   * <p>
+   * The Parser will call this method to report each chunk of character data.
+   * SAX parsers may return all contiguous character data in a single chunk, or
+   * they may split it into several chunks; however, all of the characters in
+   * any single event must come from the same external entity, so that the
+   * Locator provides useful information.
+   * </p>
+   * 
+   * <p>
+   * The application must not attempt to read from the array outside of the
+   * specified range.
+   * </p>
+   * 
+   * <p>
+   * Note that some parsers will report whitespace using the
+   * ignorableWhitespace() method rather than this one (validating parsers must
+   * do so).
+   * </p>
+   * 
+   * @param ch
+   *          The characters from the XML document.
+   * @param start
+   *          The start position in the array.
+   * @param length
+   *          The number of characters to read from the array.
+   * @see #ignorableWhitespace
+   * @see org.xml.sax.Locator
+   */
+  public void characters(char ch[], int start, int length) throws org.xml.sax.SAXException {
+    if (isOutsideDocElem() && isWhiteSpace(ch, start, length))
+      return; // avoid DOM006 Hierarchy request error
+
+    if (this.inCData) {
+      cdata(ch, start, length);
+
+      return;
+    }
+
+    String s = new String(ch, start, length);
+    Node childNode;
+    childNode = this.currentNode != null ? this.currentNode.getLastChild() : null;
+    if (childNode != null && childNode.getNodeType() == Node.TEXT_NODE) {
+      ((Text) childNode).appendData(s);
+    } else {
+      Text text = this.document.createTextNode(s);
+      append(text);
+    }
+  }
+
+  /**
+   * If available, when the disable-output-escaping attribute is used, output
+   * raw text without escaping. A PI will be inserted in front of the node with
+   * the name "lotusxsl-next-is-raw" and a value of "formatter-to-dom".
+   * 
+   * @param ch
+   *          Array containing the characters
+   * @param start
+   *          Index to start of characters in the array
+   * @param length
+   *          Number of characters in the array
+   */
+  public void charactersRaw(char ch[], int start, int length) throws org.xml.sax.SAXException {
+    if (isOutsideDocElem() && isWhiteSpace(ch, start, length))
+      return; // avoid DOM006 Hierarchy request error
+
+    String s = new String(ch, start, length);
+
+    append(this.document.createProcessingInstruction("xslt-next-is-raw", "formatter-to-dom"));
+    append(this.document.createTextNode(s));
+  }
+
+  /**
+   * Report the beginning of an entity.
+   * 
+   * The start and end of the document entity are not reported. The start and
+   * end of the external DTD subset are reported using the pseudo-name "[dtd]".
+   * All other events must be properly nested within start/end entity events.
+   * 
+   * @param name
+   *          The name of the entity. If it is a parameter entity, the name will
+   *          begin with '%'.
+   * @see #endEntity
+   * @see org.xml.sax.ext.DeclHandler#internalEntityDecl
+   * @see org.xml.sax.ext.DeclHandler#externalEntityDecl
+   */
+  public void startEntity(String name) throws org.xml.sax.SAXException {
+
+    // Almost certainly the wrong behavior...
+    // entityReference(name);
+  }
+
+  /**
+   * Report the end of an entity.
+   * 
+   * @param name
+   *          The name of the entity that is ending.
+   * @see #startEntity
+   */
+  public void endEntity(String name) throws org.xml.sax.SAXException {
+  }
+
+  /**
+   * Receive notivication of a entityReference.
+   * 
+   * @param name
+   *          name of the entity reference
+   */
+  public void entityReference(String name) throws org.xml.sax.SAXException {
+    append(this.document.createEntityReference(name));
+  }
+
+  /**
+   * Receive notification of ignorable whitespace in element content.
+   * 
+   * <p>
+   * Validating Parsers must use this method to report each chunk of ignorable
+   * whitespace (see the W3C XML 1.0 recommendation, section 2.10):
+   * non-validating parsers may also use this method if they are capable of
+   * parsing and using content models.
+   * </p>
+   * 
+   * <p>
+   * SAX parsers may return all contiguous whitespace in a single chunk, or they
+   * may split it into several chunks; however, all of the characters in any
+   * single event must come from the same external entity, so that the Locator
+   * provides useful information.
+   * </p>
+   * 
+   * <p>
+   * The application must not attempt to read from the array outside of the
+   * specified range.
+   * </p>
+   * 
+   * @param ch
+   *          The characters from the XML document.
+   * @param start
+   *          The start position in the array.
+   * @param length
+   *          The number of characters to read from the array.
+   * @see #characters
+   */
+  public void ignorableWhitespace(char ch[], int start, int length) throws org.xml.sax.SAXException {
+    if (isOutsideDocElem())
+      return; // avoid DOM006 Hierarchy request error
+
+    String s = new String(ch, start, length);
+
+    append(this.document.createTextNode(s));
+  }
+
+  /**
+   * Tell if the current node is outside the document element.
+   * 
+   * @return true if the current node is outside the document element.
+   */
+  private boolean isOutsideDocElem() {
+    return (null == this.docFrag) && this.elemStack.size() == 0 && (null == this.currentNode || this.currentNode.getNodeType() == Node.DOCUMENT_NODE);
+  }
+
+  /**
+   * Receive notification of a processing instruction.
+   * 
+   * <p>
+   * The Parser will invoke this method once for each processing instruction
+   * found: note that processing instructions may occur before or after the main
+   * document element.
+   * </p>
+   * 
+   * <p>
+   * A SAX parser should never report an XML declaration (XML 1.0, section 2.8)
+   * or a text declaration (XML 1.0, section 4.3.1) using this method.
+   * </p>
+   * 
+   * @param target
+   *          The processing instruction target.
+   * @param data
+   *          The processing instruction data, or null if none was supplied.
+   */
+  public void processingInstruction(String target, String data) throws org.xml.sax.SAXException {
+    append(this.document.createProcessingInstruction(target, data));
+  }
+
+  /**
+   * Report an XML comment anywhere in the document.
+   * 
+   * This callback will be used for comments inside or outside the document
+   * element, including comments in the external DTD subset (if read).
+   * 
+   * @param ch
+   *          An array holding the characters in the comment.
+   * @param start
+   *          The starting position in the array.
+   * @param length
+   *          The number of characters to use from the array.
+   */
+  public void comment(char ch[], int start, int length) throws org.xml.sax.SAXException {
+    append(this.document.createComment(new String(ch, start, length)));
+  }
+
+  /** Flag indicating that we are processing a CData section */
+  protected boolean inCData = false;
+
+  /**
+   * Report the start of a CDATA section.
+   * 
+   * @see #endCDATA
+   */
+  public void startCDATA() throws org.xml.sax.SAXException {
+    this.inCData = true;
+    append(this.document.createCDATASection(""));
+  }
+
+  /**
+   * Report the end of a CDATA section.
+   * 
+   * @see #startCDATA
+   */
+  public void endCDATA() throws org.xml.sax.SAXException {
+    this.inCData = false;
+  }
+
+  /**
+   * Receive notification of cdata.
+   * 
+   * <p>
+   * The Parser will call this method to report each chunk of character data.
+   * SAX parsers may return all contiguous character data in a single chunk, or
+   * they may split it into several chunks; however, all of the characters in
+   * any single event must come from the same external entity, so that the
+   * Locator provides useful information.
+   * </p>
+   * 
+   * <p>
+   * The application must not attempt to read from the array outside of the
+   * specified range.
+   * </p>
+   * 
+   * <p>
+   * Note that some parsers will report whitespace using the
+   * ignorableWhitespace() method rather than this one (validating parsers must
+   * do so).
+   * </p>
+   * 
+   * @param ch
+   *          The characters from the XML document.
+   * @param start
+   *          The start position in the array.
+   * @param length
+   *          The number of characters to read from the array.
+   * @see #ignorableWhitespace
+   * @see org.xml.sax.Locator
+   */
+  public void cdata(char ch[], int start, int length) throws org.xml.sax.SAXException {
+    if (isOutsideDocElem() && isWhiteSpace(ch, start, length))
+      return; // avoid DOM006 Hierarchy request error
+
+    String s = new String(ch, start, length);
+
+    CDATASection section = (CDATASection) this.currentNode.getLastChild();
+    section.appendData(s);
+  }
+
+  /**
+   * Report the start of DTD declarations, if any.
+   * 
+   * Any declarations are assumed to be in the internal subset unless otherwise
+   * indicated.
+   * 
+   * @param name
+   *          The document type name.
+   * @param publicId
+   *          The declared public identifier for the external DTD subset, or
+   *          null if none was declared.
+   * @param systemId
+   *          The declared system identifier for the external DTD subset, or
+   *          null if none was declared.
+   * @see #endDTD
+   * @see #startEntity
+   */
+  public void startDTD(String name, String publicId, String systemId) throws org.xml.sax.SAXException {
+
+    // Do nothing for now.
+  }
+
+  /**
+   * Report the end of DTD declarations.
+   * 
+   * @see #startDTD
+   */
+  public void endDTD() throws org.xml.sax.SAXException {
+
+    // Do nothing for now.
+  }
+
+  /**
+   * Begin the scope of a prefix-URI Namespace mapping.
+   * 
+   * <p>
+   * The information from this event is not necessary for normal Namespace
+   * processing: the SAX XML reader will automatically replace prefixes for
+   * element and attribute names when the http://xml.org/sax/features/namespaces
+   * feature is true (the default).
+   * </p>
+   * 
+   * <p>
+   * There are cases, however, when applications need to use prefixes in
+   * character data or in attribute values, where they cannot safely be expanded
+   * automatically; the start/endPrefixMapping event supplies the information to
+   * the application to expand prefixes in those contexts itself, if necessary.
+   * </p>
+   * 
+   * <p>
+   * Note that start/endPrefixMapping events are not guaranteed to be properly
+   * nested relative to each-other: all startPrefixMapping events will occur
+   * before the corresponding startElement event, and all endPrefixMapping
+   * events will occur after the corresponding endElement event, but their order
+   * is not guaranteed.
+   * </p>
+   * 
+   * @param prefix
+   *          The Namespace prefix being declared.
+   * @param uri
+   *          The Namespace URI the prefix is mapped to.
+   * @see #endPrefixMapping
+   * @see #startElement
+   */
+  public void startPrefixMapping(String prefix, String uri) throws org.xml.sax.SAXException {
+    if (null == prefix || prefix.equals(""))
+      prefix = "xmlns";
+    else
+      prefix = "xmlns:" + prefix;
+    this.prefixMappings.addElement(prefix);
+    this.prefixMappings.addElement(uri);
+  }
+
+  /**
+   * End the scope of a prefix-URI mapping.
+   * 
+   * <p>
+   * See startPrefixMapping for details. This event will always occur after the
+   * corresponding endElement event, but the order of endPrefixMapping events is
+   * not otherwise guaranteed.
+   * </p>
+   * 
+   * @param prefix
+   *          The prefix that was being mapping.
+   * @see #startPrefixMapping
+   * @see #endElement
+   */
+  public void endPrefixMapping(String prefix) throws org.xml.sax.SAXException {
+  }
+
+  /**
+   * Receive notification of a skipped entity.
+   * 
+   * <p>
+   * The Parser will invoke this method once for each entity skipped.
+   * Non-validating processors may skip entities if they have not seen the
+   * declarations (because, for example, the entity was declared in an external
+   * DTD subset). All processors may skip external entities, depending on the
+   * values of the http://xml.org/sax/features/external-general-entities and the
+   * http://xml.org/sax/features/external-parameter-entities properties.
+   * </p>
+   * 
+   * @param name
+   *          The name of the skipped entity. If it is a parameter entity, the
+   *          name will begin with '%'.
+   */
+  public void skippedEntity(String name) throws org.xml.sax.SAXException {
+  }
+
+  /**
+   * Returns whether the specified <var>ch</var> conforms to the XML 1.0
+   * definition of whitespace. Refer to <A
+   * href="http://www.w3.org/TR/1998/REC-xml-19980210#NT-S"> the definition of
+   * <CODE>S</CODE></A> for details.
+   * 
+   * @param ch
+   *          Character to check as XML whitespace.
+   * @return =true if <var>ch</var> is XML whitespace; otherwise =false.
+   */
+  public static boolean isWhiteSpace(char ch) {
+    return (ch == 0x20) || (ch == 0x09) || (ch == 0xD) || (ch == 0xA);
+  }
+
+  /**
+   * Tell if the string is whitespace.
+   * 
+   * @param ch
+   *          Character array to check as XML whitespace.
+   * @param start
+   *          Start index of characters in the array
+   * @param length
+   *          Number of characters in the array
+   * @return True if the characters in the array are XML whitespace; otherwise,
+   *         false.
+   */
+  public static boolean isWhiteSpace(char ch[], int start, int length) {
+
+    int end = start + length;
+
+    for (int s = start; s < end; s++) {
+      if (!isWhiteSpace(ch[s]))
+        return false;
+    }
+
+    return true;
+  }
+
+  public void setDebugNamespace(String debugNamespace) {
+    this.debugNamespace = debugNamespace;
+  }
+  public void setLineAttributeName(String lineAttributeName) {
+    this.lineAttributeName = lineAttributeName;
+  }
+  public void setColumnAttributeName(String columnAttributeName) {
+    this.columnAttributeName = columnAttributeName;
+  }
+  public String getDebugNamespace() {
+    return debugNamespace;
+  }
+  public String getLineAttributeName() {
+    return lineAttributeName;
+  }
+  public String getColumnAttributeName() {
+    return columnAttributeName;
+  }
+  public Document getDocument() {
+    return document;
+  }
+  public void setDocument(Document document) {
+    this.document = document;
+  }
+}

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/Parse.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/Parse.java	2008-12-09 11:18:02 UTC (rev 3283)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/Parse.java	2008-12-09 11:36:55 UTC (rev 3284)
@@ -57,7 +57,7 @@
   protected Parser parser;
   
   protected ClassLoader classLoader;
-  protected StreamInput streamSource;
+  protected StreamInput streamInput;
   protected InputStream inputStream;
   protected InputSource inputSource;
   
@@ -70,22 +70,24 @@
   protected Parse(Parser parser) {
     this.parser = parser;
   }
+  
+  // specifying the input source //////////////////////////////////////////////
 
   /** specify an input stream as the source for this parse */
   public Parse setInputStream(InputStream inputStream) {
-    this.streamSource = new InputStreamInput(inputStream);
+    this.streamInput = new InputStreamInput(inputStream);
     return this;
   }
 
   /** specify a URL as the source for this parse */
   public Parse setUrl(URL url) {
-    this.streamSource = new UrlStreamInput(url);
+    this.streamInput = new UrlStreamInput(url);
     return this;
   }
 
   /** specify a file as the source for this parse */
   public Parse setFile(File file) {
-    this.streamSource = new FileStreamInput(file);
+    this.streamInput = new FileStreamInput(file);
     return this;
   }
 
@@ -98,19 +100,19 @@
 
   /** specify a resource as the source for this parse */
   public Parse setResource(String resource) {
-    this.streamSource = new ResourceStreamInput(resource, classLoader);
+    this.streamInput = new ResourceStreamInput(resource, classLoader);
     return this;
   }
 
   /** specify an XML string as the source for this parse */
   public Parse setString(String xmlString) {
-    this.streamSource = new StringStreamInput(xmlString);
+    this.streamInput = new StringStreamInput(xmlString);
     return this;
   }
 
   /** specify a {@link StreamInput} as the source for this parse */
-  public Parse setStreamSource(StreamInput streamSource) {
-    this.streamSource = streamSource;
+  public Parse setStreamSource(StreamInput streamInput) {
+    this.streamInput = streamInput;
     return this;
   }
 
@@ -136,6 +138,24 @@
     return this;
   }
 
+  // retrieving input source //////////////////////////////////////////////////
+  
+  protected InputSource getInputSource() {
+    if (inputSource!=null) {
+      return inputSource;
+    }
+
+    if (streamInput!=null) {
+      inputStream = streamInput.openStream();
+      return new InputSource(inputStream);
+    }
+    
+    addProblem("no source specified to parse");
+    return null;
+  }
+
+  // parse execution //////////////////////////////////////////////////////////
+  
   /** perform the actual parse operation with the specified input source. */
   public Parse execute() {
     parser.execute(this);
@@ -165,6 +185,20 @@
     addProblem(problem);
   }
 
+  /** throws an exception with appropriate message in case the parse contains 
+   * errors or fatal errors.  This method also logs the problems with severity
+   * 'warning'. */
+  public Parse checkProblems(String description) {
+    if (hasProblems()) {
+      String errorMsg = "problems during parse of "+description+":"+getProblemsText();
+      log.info(errorMsg);
+      if (errorMsg!=null) {
+        throw new JbpmException(errorMsg);
+      }
+    }
+    return this;
+  }
+
   // contextual objects ///////////////////////////////////////////////////////
 
   /** push a contextual object on the stack of this parse. */
@@ -211,22 +245,8 @@
     return null;
   }
   
-  /** throws an exception with appropriate message in case the parse contains 
-   * errors or fatal errors.  This method also logs the problems with severity
-   * 'warning'. */
-  public Parse checkProblems(String description) {
-    if (hasProblems()) {
-      String errorMsg = "problems during parse of "+description+":"+getProblemsText();
-      log.info(errorMsg);
-      if (errorMsg!=null) {
-        throw new JbpmException(errorMsg);
-      }
-    }
-    return this;
-  }
+  // getters //////////////////////////////////////////////////////////////////
 
-  // getters and setters //////////////////////////////////////////////////////
-
   /** the result of this parse operation. */
   public Object getDocumentObject() {
     return documentObject;

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/Parser.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/Parser.java	2008-12-09 11:18:02 UTC (rev 3283)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/xml/Parser.java	2008-12-09 11:36:55 UTC (rev 3284)
@@ -21,20 +21,16 @@
  */
 package org.jbpm.pvm.internal.xml;
 
-import java.io.InputStream;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
-import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.Source;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
 
-import org.jbpm.JbpmException;
 import org.jbpm.log.Log;
 import org.jbpm.pvm.internal.stream.StreamInput;
 import org.jbpm.pvm.internal.util.UrlEntity;
@@ -43,6 +39,7 @@
 import org.w3c.dom.Element;
 import org.xml.sax.EntityResolver;
 import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
 
 /** makes typical usage of JAXP more convenient, adds a binding framework, 
  * entity resolution and error handling.
@@ -248,6 +245,9 @@
 public class Parser {
 
   private static Log log = Log.getLog(Parser.class.getName());
+
+  protected SAXParserFactory saxParserFactory;
+  protected String[] schemaResources;
   
   protected DocumentBuilderFactory documentBuilderFactory = null;
   
@@ -256,75 +256,73 @@
 
   /** the default parser */
   public Parser() {
+    initialize();
   }
 
   /** creates a new Parser with bindings that can be maintained statically in
    * specialized subclasses of Parser. */
   public Parser(Bindings bindings) {
+    initialize();
     this.bindings = bindings;
   }
 
   /** creates a new Parser with bindings and entities that can be maintained statically
-   * in specialized subclasses of Parser. */
+   * in specialized subclasses of Parser.
+   * @deprecated entities should be replaced by {@link #setSchemaResources(List)} */
   public Parser(Bindings bindings, Map<String, Entity> entities) {
+    initialize();
     this.bindings = bindings;
   }
+  
+  // initialization ///////////////////////////////////////////////////////////
 
-  // document builder methods /////////////////////////////////////////////////
+  public void initialize() {
+    initializeSaxParserFactory();
+    initializeDocumentBuilderFactory();
+  }
 
-  /** getter with lazy initialization of the document builder factory.
-   * If no document builder factory was set previously with the {@link #setDocumentBuilderFactory(DocumentBuilderFactory)}
-   * method, {@link #newDocumentBuilderFactory()} will be called to create one.
-   */
-  public synchronized DocumentBuilderFactory getDocumentBuilderFactory() {
-    if (documentBuilderFactory==null) {
-      documentBuilderFactory = newDocumentBuilderFactory();
-    }
-    return documentBuilderFactory;
+  public void initializeDocumentBuilderFactory() {
+    documentBuilderFactory = DocumentBuilderFactory.newInstance();
   }
 
-  /** setter for the document builder factory */
-  public void setDocumentBuilderFactory(DocumentBuilderFactory documentBuilderFactory) {
-    this.documentBuilderFactory = documentBuilderFactory;
+  public void initializeSaxParserFactory() {
+    saxParserFactory = SAXParserFactory.newInstance();
   }
 
-  /** factory method for {@link DocumentBuilderFactory} during lazy initialization
-   * of the documentBuilderFactory.  Can be overridden by subclasses to change
-   * the DocumentBuilderFactory implementation or to apply specific configurations. */
-  protected DocumentBuilderFactory newDocumentBuilderFactory() {
-    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-    return factory;
+  // document builder methods /////////////////////////////////////////////////
+
+  /** customizable creation of a new document builder.  Used by 
+   * {@link #buildDom(Parse)}. */
+  protected DocumentBuilder createDocumentBuilder(Parse parse) {
+    try {
+      parse.documentBuilder = documentBuilderFactory.newDocumentBuilder();
+    } catch (Exception e) {
+      parse.addProblem("couldn't get new document builder", e);
+      return null;
+    }
+    parse.documentBuilder.setErrorHandler(parse);
+    return parse.documentBuilder;
   }
 
   // schema validation ////////////////////////////////////////////////////////
   
-  protected void setSchemaResources(List<String> resources) {
-    if ( (resources==null)
-         || (resources.isEmpty())
-       ) {
-      throw new JbpmException("no schema resoures");
-    }
-    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
-    SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+  public void setSchemaResources(List<String> resources) {
+    saxParserFactory.setValidating(true);
+    saxParserFactory.setNamespaceAware(true);
 
-    List<Source> schemaSources = new ArrayList<Source>();
-    for (String resource: resources) {
-      InputStream schemaStream = classLoader.getResourceAsStream(resource);
-      if (schemaStream==null) {      
-        throw new JbpmException("schema resource "+resource+" unavailable");
+    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+    List<String> schemaLocations = new ArrayList<String>(resources.size()); 
+    for (String schemaResource: resources) {
+      URL schemaUrl = classLoader.getResource(schemaResource);
+      if (schemaUrl!=null) {
+        String schemaLocation = schemaUrl.toString();
+        log.debug("schema resource found: " + schemaResource);
+        schemaLocations.add(schemaLocation);
+      } else {
+        log.debug("skipping unavailble schema resource: " + schemaResource);
       }
-      StreamSource schemaSource = new StreamSource(schemaStream);
-      schemaSources.add(schemaSource);
     }
-    try {
-      Source[] schemaSourceArray = schemaSources.toArray(new Source[schemaSources.size()]);
-      Schema schema = schemaFactory.newSchema(schemaSourceArray);
-      DocumentBuilderFactory factory = getDocumentBuilderFactory();
-      factory.setSchema(schema);
-      factory.setNamespaceAware(true);
-    } catch (Exception e) {
-      log.error("couldn't install schema's for validation: "+e.toString());
-    }
+    schemaResources = schemaLocations.toArray(new String[schemaLocations.size()]);
   }
 
   // bindings /////////////////////////////////////////////////////////////////
@@ -360,11 +358,11 @@
   /** builds a dom from the importedStreamSource and appends the child elements 
    * of the document element to the destination element.  Problems are reported 
    * in the importingParse. */
-  public void importStream(StreamInput importedStreamSource, Element destination, Parse importingParse) {
+  public void importStream(StreamInput importedStreamInput, Element destination, Parse importingParse) {
     try {
       // build the dom of the imported document
       Parse importedParse = createParse();
-      importedParse.setStreamSource(importedStreamSource);
+      importedParse.setStreamSource(importedStreamInput);
       Document importedDocument = buildDom(importedParse);
       
       // loop over all the imported document elements 
@@ -375,7 +373,7 @@
       }
       
     } catch (Exception e) {
-      importingParse.addProblem("couldn't import "+importedStreamSource, e);
+      importingParse.addProblem("couldn't import "+importedStreamInput, e);
     }
   }
 
@@ -408,62 +406,54 @@
     }
   }
 
-  /** customizable DOM building.  Parses {@link #getInputSource(Parse) the 
-   * input specified in the parse} with a 
-   * {@link #createDocumentBuilder(parse) DocumentBuilder}.
-   * 
-   * @return a Document or null in case an exception occurs during XML 
-   *   parsing. */ 
   protected Document buildDom(Parse parse) {
-    DocumentBuilder documentBuilder = createDocumentBuilder(parse);
-    InputSource inputSource = getInputSource(parse); 
+    Document document = null;
 
     try {
-      // create the dom tree
-      parse.document = documentBuilder.parse(inputSource);
+      SAXParser saxParser = saxParserFactory.newSAXParser();
+      XMLReader xmlReader = saxParser.getXMLReader();
+      
+      try {
+        saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
+      } catch (Exception e){
+        log.info("couldn't set schema language property", e);
+      }
 
-    } catch (Exception e) {
-      parse.addProblem("couldn't parse xml document", e);
-    }
+      if (schemaResources!=null) {
+        try {
+          saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", schemaResources);
+        } catch (Exception e){
+          log.info("couldn't set schema source property", e);
+        }
+      }
 
-    return parse.document;
-  }
+      try {
+        xmlReader.setFeature("http://apache.org/xml/features/validation/dynamic", true);
+      } catch (Exception e){
+        log.info("couldn't set dynamic validation feature", e);
+      }
 
-  /** customizable creation of a new document builder.  Used by 
-   * {@link #buildDom(Parse)}. */
-  protected DocumentBuilder createDocumentBuilder(Parse parse) {
-    DocumentBuilderFactory documentBuilderFactory = getDocumentBuilderFactory();
-    try {
-      parse.documentBuilder = documentBuilderFactory.newDocumentBuilder();
-    } catch (Exception e) {
-      parse.addProblem("couldn't get new document builder", e);
-      return null;
-    }
-    parse.documentBuilder.setErrorHandler(parse);
-    return parse.documentBuilder;
-  }
+      DocumentBuilder documentBuilder = createDocumentBuilder(parse);
+      document = documentBuilder.newDocument();
+      parse.setDocument(document);
 
-  /** customizable extraction of the inputSource from the given parse.  
-   * 
-   * Returns null in case 
-   * the parse doesn't have an inputSource or a streamSource specified.
-   *  
-   * If an inputStream is created in this method, it is set in the parse
-   * so that it can be closed at the end of the {@link #execute(Parse)}. */
-  protected InputSource getInputSource(Parse parse) {
-    if (parse.inputSource!=null) {
-      return parse.inputSource;
-    }
+      DomBuilder domBuilder = new DomBuilder();
+      domBuilder.setDocument(document);
 
-    if (parse.streamSource!=null) {
-      parse.inputStream = parse.streamSource.openStream();
-      return new InputSource(parse.inputStream);
+      xmlReader.setContentHandler(domBuilder);
+      xmlReader.setErrorHandler(parse);
+      
+      InputSource inputSource = parse.getInputSource(); 
+      xmlReader.parse(inputSource);
+
+    } catch (Exception e) {
+      parse.addProblem("couldn't parse xml document", e);
     }
-    
-    parse.addProblem("no source specified to parse");
-    return null;
+
+    return document;
   }
 
+
   // Document Object Model walking ////////////////////////////////////////////
 
   /** start of the DOM walk.




More information about the jbpm-commits mailing list