commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From simonetrip...@apache.org
Subject svn commit: r1066227 - /commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/digester3/DigesterImpl.java
Date Tue, 01 Feb 2011 21:28:11 GMT
Author: simonetripodi
Date: Tue Feb  1 21:28:10 2011
New Revision: 1066227

URL: http://svn.apache.org/viewvc?rev=1066227&view=rev
Log:
first checkin of DigesterImpl class, the concrete Digester implementation

Added:
    commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/digester3/DigesterImpl.java
  (with props)

Added: commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/digester3/DigesterImpl.java
URL: http://svn.apache.org/viewvc/commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/digester3/DigesterImpl.java?rev=1066227&view=auto
==============================================================================
--- commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/digester3/DigesterImpl.java
(added)
+++ commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/digester3/DigesterImpl.java
Tue Feb  1 21:28:10 2011
@@ -0,0 +1,1238 @@
+/* $Id$
+ *
+ * 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.digester3;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.apache.commons.digester3.spi.Rules;
+import org.apache.commons.digester3.spi.Substitutor;
+import org.apache.commons.digester3.spi.TypeConverter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+
+/**
+ * {@link Digester} concrete implementation.
+ */
+final class DigesterImpl implements Digester {
+
+    /**
+     * The Log to which most logging calls will be made.
+     */
+    private final Log log = LogFactory.getLog("org.apache.commons.digester3.Digester");
+
+    /**
+     * The Log to which all SAX event related logging calls will be made.
+     */
+    private final Log saxLog = LogFactory.getLog("org.apache.commons.digester3.Digester.sax");
+
+    /**
+     * Registered namespaces we are currently processing.  The key is the
+     * namespace prefix that was declared in the document.  The value is an
+     * Stack of the namespace URIs this prefix has been mapped to --
+     * the top Stack element is the most current one.  (This architecture
+     * is required because documents can declare nested uses of the same
+     * prefix for different Namespace URIs).
+     */
+    private final HashMap<String, Stack<String>> namespaces = new HashMap<String,
Stack<String>>();
+
+    /**
+     * The object stack being constructed.
+     */
+    private final Stack<Object> stack = new Stack<Object>();
+
+    /**
+     * The parameters stack being utilized by CallMethodRule and
+     * CallParamRule rules.
+     */
+    private final Stack<Object> params = new Stack<Object>();
+
+    /**
+     * Stack whose elements are List objects, each containing a list of
+     * Rule objects as returned from Rules.getMatch(). As each xml element
+     * in the input is entered, the matching rules are pushed onto this
+     * stack. After the end tag is reached, the matches are popped again.
+     * The depth of is stack is therefore exactly the same as the current
+     * "nesting" level of the input xml.
+     */
+    private final Stack<List<Rule>> matches = new Stack<List<Rule>>();
+
+    /**
+     * The stack of body text string buffers for surrounding elements.
+     */
+    private final Stack<StringBuilder> bodyTexts = new Stack<StringBuilder>();
+
+    /**
+     * Stacks used for interrule communication, indexed by name String
+     */
+    private final HashMap<String, Stack<Object>> stacksByName = new HashMap<String,
Stack<Object>>();
+
+    /**
+     * <p><code>List</code> of <code>InputSource</code> instances
+     * created by a <code>createInputSourceFromURL()</code> method
+     * call.  These represent open input streams that need to be
+     * closed to avoid resource leaks, as well as potentially locked
+     * JAR files on Windows.</p>
+     */
+    private final List<InputSource> inputSources = new ArrayList<InputSource>();
+
+    /**
+     * The class loader to use for instantiating application objects.
+     */
+    private final ClassLoader classLoader;
+
+    /**
+     * An optional class that substitutes values in attributes and body text.
+     * This may be null and so a null check is always required before use.
+     */
+    private final Substitutor substitutor;
+
+    /**
+     * The URLs of entityValidator that have been registered, keyed by the public
+     * identifier that corresponds.
+     */
+    private final HashMap<String, URL> entityValidator;
+
+    private final XMLReader reader;
+
+    /**
+     * The <code>Rules</code> containing our collection of
+     * <code>Rule</code> instances and associated matching policy.
+     */
+    private Rules rules;
+
+    /**
+     * The Locator associated with our parser.
+     */
+    private Locator locator;
+
+    // ---- internals
+
+    /**
+     * The body text of the current element.
+     */
+    private StringBuilder bodyText = new StringBuilder();
+
+    /**
+     * The current match pattern for nested element processing.
+     */
+    private String match = "";
+
+    /**
+     * The "root" element of the stack (in other words, the last object
+     * that was popped.
+     */
+    private Object root = null;
+
+    public DigesterImpl(XMLReader reader,
+            Rules rules,
+            ClassLoader classLoader,
+            Substitutor substitutor,
+            HashMap<String, URL> entityValidator) {
+        this.reader = reader;
+        this.reader.setDTDHandler(this);
+        this.reader.setContentHandler(this);
+        this.reader.setEntityResolver(this);
+        this.reader.setErrorHandler(this);
+
+        this.rules = rules;
+        this.classLoader = classLoader;
+        this.substitutor = substitutor;
+        this.entityValidator = entityValidator;
+
+        this.rules.setDigester(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Rules getRules() {
+        return this.rules;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setRules(Rules rules) {
+        this.rules = rules;
+        this.rules.setDigester(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ClassLoader getClassLoader() {
+        return this.classLoader;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Log getLog() {
+        return this.log;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Log getSAXLog() {
+        return this.saxLog;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getMatch() {
+        return this.match;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() {
+        this.match = "";
+        this.bodyTexts.clear();
+        this.params.clear();
+        // publicId = null;
+        this.stack.clear();
+        this.stacksByName.clear();
+    }
+
+    // ---- Stack methods
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getCount() {
+        return this.stack.size();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void push(Object object) {
+        if (this.stack.size() == 0) {
+            this.root = object;
+        }
+        this.stack.push(object);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void push(String stackName, Object value) {
+        Stack<Object> namedStack = this.stacksByName.get(stackName);
+        if (namedStack == null) {
+            namedStack = new Stack<Object>();
+            this.stacksByName.put(stackName, namedStack);
+        }
+        namedStack.push(value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object pop() {
+        try {
+            return this.stack.pop();
+        } catch (EmptyStackException e) {
+            this.log.warn("Empty stack (returning null)");
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object pop(String stackName) {
+        Object result = null;
+
+        Stack<Object> namedStack = stacksByName.get(stackName);
+        if (namedStack == null) {
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Stack '" + stackName + "' is empty");
+            }
+            throw new EmptyStackException();
+        }
+
+        result = namedStack.pop();
+
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object peek() {
+        try {
+            return this.stack.peek();
+        } catch (EmptyStackException e) {
+            this.log.warn("Empty stack (returning null)");
+            return (null);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object peek(String stackName) {
+        return this.peek(stackName, 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object peek(int n) {
+        int index = (this.stack.size() - 1) - n;
+        if (index < 0) {
+            this.log.warn("Empty stack (returning null)");
+            return null;
+        }
+        try {
+            return (this.stack.get(index));
+        } catch (EmptyStackException e) {
+            this.log.warn("Empty stack (returning null)");
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object peek(String stackName, int n) {
+        Object result = null;
+        Stack<Object> namedStack = this.stacksByName.get(stackName);
+        if (namedStack == null ) {
+            if (log.isDebugEnabled()) {
+                log.debug("Stack '"
+                        + stackName
+                        + "' is empty");
+            }
+            throw new EmptyStackException();
+        } else {
+            int index = (namedStack.size() - 1) - n;
+            if (index < 0) {
+                throw new EmptyStackException();
+            }
+            result = namedStack.get(index);
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEmpty(String stackName) {
+        boolean result = true;
+        Stack<Object> namedStack = this.stacksByName.get(stackName);
+        if (namedStack != null ) {
+            result = namedStack.isEmpty();
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getRoot() {
+        return this.root;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void resetRoot() {
+        this.root = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object peekParams() {
+        try {
+            return this.params.peek();
+        } catch (EmptyStackException e) {
+            this.log.warn("Empty stack (returning null)");
+            return (null);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object peekParams(int n) {
+        int index = (this.params.size() - 1) - n;
+        if (index < 0) {
+            this.log.warn("Empty stack (returning null)");
+            return (null);
+        }
+        try {
+            return this.params.get(index);
+        } catch (EmptyStackException e) {
+            this.log.warn("Empty stack (returning null)");
+            return (null);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void pushParams(Object object) {
+        if (this.log.isTraceEnabled()) {
+            this.log.trace("Pushing params");
+        }
+        this.params.push(object);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object popParams() {
+        try {
+            if (this.log.isTraceEnabled()) {
+                this.log.trace("Popping params");
+            }
+            return this.params.pop();
+        } catch (EmptyStackException e) {
+            this.log.warn("Empty stack (returning null)");
+            return null;
+        }
+    }
+
+    // ------ ContentHandler Methods
+
+    /**
+     * Process notification of character data received from the body of
+     * an XML element.
+     *
+     * @param buffer The characters from the XML document
+     * @param start Starting offset into the buffer
+     * @param length Number of characters from the buffer
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void characters(char buffer[], int start, int length) throws SAXException {
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("characters(" + new String(buffer, start, length) + ")");
+        }
+
+        this.bodyText.append(buffer, start, length);
+    }
+
+    /**
+     * Process notification of the end of the document being reached.
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void endDocument() throws SAXException {
+        if (this.saxLog.isDebugEnabled()) {
+            if (this.stack.size() > 1) {
+                this.saxLog.debug("endDocument():  "
+                        + this.stack.size()
+                        + " elements left");
+            } else {
+                this.saxLog.debug("endDocument()");
+            }
+        }
+
+        // Fire "finish" events for all defined rules
+        for (Rule rule : this.rules.rules()) {
+            try {
+                rule.finish();
+            } catch (Exception e) {
+                this.log.error("Finish event threw exception", e);
+                throw this.createSAXException(e);
+            } catch (Error e) {
+                this.log.error("Finish event threw error", e);
+                throw e;
+            }
+        }
+
+        // Perform final cleanup
+        clear();
+    }
+
+    /**
+     * Process notification of the end of an XML element being reached.
+     *
+     * @param namespaceURI - The Namespace URI, or the empty string if the
+     *   element has no Namespace URI or if Namespace processing is not
+     *   being performed.
+     * @param localName - The local name (without prefix), or the empty
+     *   string if Namespace processing is not being performed.
+     * @param qName - The qualified XML 1.0 name (with prefix), or the
+     *   empty string if qualified names are not available.
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void endElement(String namespaceURI, String localName, String qName) throws SAXException
{
+        boolean debug = this.log.isDebugEnabled();
+
+        if (debug) {
+            if (this.saxLog.isDebugEnabled()) {
+                this.saxLog.debug("endElement("
+                        + namespaceURI
+                        + ","
+                        + localName
+                        + ","
+                        + qName
+                        + ")");
+            }
+            this.log.debug("  match='"
+                    + this.match
+                    + "'");
+            this.log.debug("  bodyText='"
+                    + this.bodyText
+                    + "'");
+        }
+
+        // the actual element name is either in localName or qName, depending 
+        // on whether the parser is namespace aware
+        String name = localName;
+        if ((name == null) || (name.length() < 1)) {
+            name = qName;
+        }
+
+        // Fire "body" events for all relevant rules
+        List<Rule> rules = this.matches.pop();
+        if ((rules != null) && (rules.size() > 0)) {
+            String bodyText = this.bodyText.toString();
+            Substitutor substitutor = this.substitutor;
+            if (substitutor!= null) {
+                bodyText = substitutor.substitute(bodyText);
+            }
+            for (int i = 0; i < rules.size(); i++) {
+                try {
+                    Rule rule = rules.get(i);
+                    if (debug) {
+                        this.log.debug("  Fire body() for " + rule);
+                    }
+                    rule.body(namespaceURI, name, bodyText);
+                } catch (Exception e) {
+                    this.log.error("Body event threw exception", e);
+                    throw createSAXException(e);
+                } catch (Error e) {
+                    this.log.error("Body event threw error", e);
+                    throw e;
+                }
+            }
+        } else {
+            if (debug) {
+                this.log.debug("  No rules found matching '"
+                        + this.match
+                        + "'.");
+            }
+        }
+
+        // Recover the body text from the surrounding element
+        this.bodyText = this.bodyTexts.pop();
+        if (debug) {
+            this.log.debug("  Popping body text '"
+                    + this.bodyText.toString()
+                    + "'");
+        }
+
+        // Fire "end" events for all relevant rules in reverse order
+        if (rules != null) {
+            for (int i = 0; i < rules.size(); i++) {
+                int j = (rules.size() - i) - 1;
+                try {
+                    Rule rule = rules.get(j);
+                    if (debug) {
+                        this.log.debug("  Fire end() for "
+                                + rule);
+                    }
+                    rule.end(namespaceURI, name);
+                } catch (Exception e) {
+                    this.log.error("End event threw exception", e);
+                    throw this.createSAXException(e);
+                } catch (Error e) {
+                    this.log.error("End event threw error", e);
+                    throw e;
+                }
+            }
+        }
+
+        // Recover the previous match expression
+        int slash = this.match.lastIndexOf('/');
+        if (slash >= 0) {
+            this.match = this.match.substring(0, slash);
+        } else {
+            this.match = "";
+        }
+    }
+
+    /**
+     * Process notification that a namespace prefix is going out of scope.
+     *
+     * @param prefix Prefix that is going out of scope
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void endPrefixMapping(String prefix) throws SAXException {
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("endPrefixMapping("
+                    + prefix
+                    + ")");
+        }
+
+        // Deregister this prefix mapping
+        Stack<String> stack = namespaces.get(prefix);
+        if (stack == null) {
+            return;
+        }
+        try {
+            stack.pop();
+            if (stack.empty()) {
+                this.namespaces.remove(prefix);
+            }
+        } catch (EmptyStackException e) {
+            throw this.createSAXException("endPrefixMapping popped too many times");
+        }
+    }
+
+    /**
+     * Process notification of ignorable whitespace received from the body of
+     * an XML element.
+     *
+     * @param buffer The characters from the XML document
+     * @param start Starting offset into the buffer
+     * @param len Number of characters from the buffer
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void ignorableWhitespace(char buffer[], int start, int len) throws SAXException
{
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("ignorableWhitespace("
+                    + new String(buffer, start, len)
+                    + ")");
+        }
+
+        // No processing required
+    }
+
+    /**
+     * Process notification of a processing instruction that was encountered.
+     *
+     * @param target The processing instruction target
+     * @param data The processing instruction data (if any)
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void processingInstruction(String target, String data) throws SAXException {
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("processingInstruction('"
+                    + target
+                    + "','"
+                    + data
+                    + "')");
+        }
+
+        // No processing is required
+    }
+
+    /**
+     * Gets the document locator associated with our parser.
+     *
+     * @return the Locator supplied by the document parser
+     */
+    public Locator getDocumentLocator() {
+        return locator;
+    }
+
+    /**
+     * Sets the document locator associated with our parser.
+     *
+     * @param locator The new locator
+     */
+    public void setDocumentLocator(Locator locator) {
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("setDocumentLocator("
+                    + locator
+                    + ")");
+        }
+
+        this.locator = locator;
+    }
+
+    /**
+     * Process notification of a skipped entity.
+     *
+     * @param name Name of the skipped entity
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void skippedEntity(String name) throws SAXException {
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("skippedEntity("
+                    + name
+                    + ")");
+        }
+
+        // No processing required
+    }
+
+    /**
+     * Process notification of the beginning of the document being reached.
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void startDocument() throws SAXException {
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("startDocument()");
+        }
+
+        // No processing required
+    }
+
+    /**
+     * Process notification of the start of an XML element being reached.
+     *
+     * @param namespaceURI The Namespace URI, or the empty string if the element
+     *   has no Namespace URI or if Namespace processing is not being performed.
+     * @param localName The local name (without prefix), or the empty
+     *   string if Namespace processing is not being performed.
+     * @param qName The qualified name (with prefix), or the empty
+     *   string if qualified names are not available.\
+     * @param list The attributes attached to the element. If there are
+     *   no attributes, it shall be an empty Attributes object. 
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void startElement(String namespaceURI, String localName, String qName, Attributes
list) throws SAXException {
+        boolean debug = this.log.isDebugEnabled();
+
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("startElement("
+                    + namespaceURI
+                    + ","
+                    + localName
+                    + ","
+                    + qName
+                    + ")");
+        }
+
+        // Save the body text accumulated for our surrounding element
+        this.bodyTexts.push(this.bodyText);
+        if (debug) {
+            this.log.debug("  Pushing body text '"
+                    + this.bodyText.toString()
+                    + "'");
+        }
+        this.bodyText = new StringBuilder();
+
+        // the actual element name is either in localName or qName, depending 
+        // on whether the parser is namespace aware
+        String name = localName;
+        if (name == null || name.length() < 1) {
+            name = qName;
+        }
+
+        // Compute the current matching rule
+        StringBuilder sb = new StringBuilder(this.match);
+        if (this.match.length() > 0) {
+            sb.append('/');
+        }
+        sb.append(name);
+        this.match = sb.toString();
+        if (debug) {
+            this.log.debug("  New match='"
+                    + this.match
+                    + "'");
+        }
+
+        // Fire "begin" events for all relevant rules
+        List<Rule> rules = this.rules.match(namespaceURI, this.match);
+        this.matches.push(rules);
+        if (rules != null && !rules.isEmpty()) {
+            Substitutor substitutor = this.substitutor;
+            if (substitutor!= null) {
+                list = substitutor.substitute(list);
+            }
+            for (int i = 0; i < rules.size(); i++) {
+                try {
+                    Rule rule = rules.get(i);
+                    if (debug) {
+                        this.log.debug("  Fire begin() for "
+                                + rule);
+                    }
+                    rule.begin(namespaceURI, name, list);
+                } catch (Exception e) {
+                    this.log.error("Begin event threw exception", e);
+                    throw this.createSAXException(e);
+                } catch (Error e) {
+                    this.log.error("Begin event threw error", e);
+                    throw e;
+                }
+            }
+        } else if (debug) {
+            this.log.debug("  No rules found matching '"
+                    + this.match
+                    + "'.");
+        }
+    }
+
+    /**
+     * Process notification that a namespace prefix is coming in to scope.
+     *
+     * @param prefix Prefix that is being declared
+     * @param namespaceURI Corresponding namespace URI being mapped to
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void startPrefixMapping(String prefix, String namespaceURI) throws SAXException
{
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("startPrefixMapping("
+                    + prefix
+                    + ","
+                    + namespaceURI
+                    + ")");
+        }
+
+        // Register this prefix mapping
+        Stack<String> stack = this.namespaces.get(prefix);
+        if (stack == null) {
+            stack = new Stack<String>();
+            this.namespaces.put(prefix, stack);
+        }
+        stack.push(namespaceURI);
+    }
+
+    // ---- DTDHandler Methods
+
+    /**
+     * Receive notification of a notation declaration event.
+     *
+     * @param name The notation name
+     * @param publicId The public identifier (if any)
+     * @param systemId The system identifier (if any)
+     */
+    public void notationDecl(String name, String publicId, String systemId) {
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("notationDecl("
+                    + name
+                    + ","
+                    + publicId
+                    + ","
+                    + systemId
+                    + ")");
+        }
+    }
+
+    /**
+     * Receive notification of an unparsed entity declaration event.
+     *
+     * @param name The unparsed entity name
+     * @param publicId The public identifier (if any)
+     * @param systemId The system identifier (if any)
+     * @param notation The name of the associated notation
+     */
+    public void unparsedEntityDecl(String name, String publicId, String systemId, String
notation) {
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("unparsedEntityDecl("
+                    + name
+                    + ","
+                    + publicId
+                    + ","
+                    + systemId
+                    + ","
+                    + notation
+                    + ")");
+        }
+    }
+
+    // ---- EntityResolver Methods
+
+    /**
+     * Set the <code>EntityResolver</code> used by SAX when resolving
+     * public id and system id.
+     * This must be called before the first call to <code>parse()</code>.
+     * @param entityResolver a class that implement the <code>EntityResolver</code>
interface.
+     */
+    public void setEntityResolver(EntityResolver entityResolver){
+        this.reader.setEntityResolver(entityResolver);
+    }
+
+    /**
+     * Return the Entity Resolver used by the SAX parser.
+     * @return Return the Entity Resolver used by the SAX parser.
+     */
+    public EntityResolver getEntityResolver(){
+        return this.reader.getEntityResolver();
+    }
+
+    /**
+     * Resolve the requested external entity.
+     *
+     * @param publicId The public identifier of the entity being referenced
+     * @param systemId The system identifier of the entity being referenced
+     *
+     * @exception SAXException if a parsing exception occurs
+     */
+    public InputSource resolveEntity(String publicId, String systemId) throws SAXException
{
+        if (this.saxLog.isDebugEnabled()) {
+            this.saxLog.debug("resolveEntity('"
+                    + publicId
+                    + "', '"
+                    + systemId
+                    + "')");
+        }
+
+        // Has this system identifier been registered?
+        URL entityURL = null;
+        if (publicId != null) {
+            entityURL = this.entityValidator.get(publicId);
+        }
+
+        // Redirect the schema location to a local destination
+        if (entityURL == null && systemId != null){
+            entityURL = this.entityValidator.get(systemId);
+        } 
+
+        if (entityURL == null) { 
+            if (systemId == null) {
+                // cannot resolve
+                if (this.log.isDebugEnabled()) {
+                    this.log.debug(" Cannot resolve null entity, returning null InputSource");
+                }
+                return null;
+            } else {
+                // try to resolve using system ID
+                if (this.log.isDebugEnabled()) {
+                    this.log.debug(" Trying to resolve using system ID '"
+                            + systemId
+                            + "'");
+                }
+                try {
+                    entityURL = new URL(systemId);
+                } catch (MalformedURLException e) {
+                    throw new IllegalArgumentException("Malformed URL '"
+                            + systemId
+                            + "' : "
+                            + e.getMessage());
+                }
+            }
+        }
+
+        // Return an input source to our alternative URL
+        if (this.log.isDebugEnabled()) {
+            this.log.debug(" Resolving to alternate DTD '"
+                    + entityURL
+                    + "'");
+        }  
+
+        try {
+            InputSource source = createInputSourceFromURL(entityURL);
+            this.inputSources.add(source);
+            return source;
+        } catch (Exception e) {
+            throw this.createSAXException(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setErrorHandler(ErrorHandler errorHandler) {
+        this.reader.setErrorHandler(errorHandler);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ErrorHandler getErrorHandler() {
+        return this.reader.getErrorHandler();
+    }
+
+    // ---- ErrorHandler Methods
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(SAXParseException e) throws SAXException {
+        this.log.error("Parse Error at line "
+                + e.getLineNumber()
+                + " column "
+                + e.getColumnNumber()
+                + ": "
+                + e.getMessage(), e);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void fatalError(SAXParseException e) throws SAXException {
+        this.log.error("Parse Fatal Error at line "
+                + e.getLineNumber()
+                + " column "
+                + e.getColumnNumber()
+                + ": "
+                + e.getMessage(), e);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warning(SAXParseException e) throws SAXException {
+        this.log.warn("Parse Warning Error at line "
+                + e.getLineNumber()
+                + " column "
+                + e.getColumnNumber()
+                + ": "
+                + e.getMessage(), e);
+    }
+
+    // ---- Parsing & I/O
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object parse(File file) throws IOException, SAXException {
+        if (file == null) {
+            throw new IllegalArgumentException("File to parse must be not null");
+        }
+
+        return this.parse(file.toURI().toURL());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object parse(InputSource input) throws IOException, SAXException {
+        if (input == null) {
+            throw new IllegalArgumentException("InputSource to parse must be not null");
+        }
+
+        this.inputSources.add(input);
+
+        try {
+            this.reader.parse(input);
+            return this.root;
+        } finally {
+            this.cleanup();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object parse(InputStream input) throws IOException, SAXException {
+        if (input == null) {
+            throw new IllegalArgumentException("InputStream to parse must be not null");
+        }
+
+        return this.parse(new InputSource(input));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object parse(Reader reader) throws IOException, SAXException {
+        if (reader == null) {
+            throw new IllegalArgumentException("Reader to parse must be not null");
+        }
+
+        return this.parse(new InputSource(reader));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object parse(String uri) throws IOException, SAXException {
+        if (uri == null) {
+            throw new IllegalArgumentException("String URI to parse must be not null");
+        }
+
+        return this.parse(new URL(uri));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object parse(URL url) throws IOException, SAXException {
+        if (url == null) {
+            throw new IllegalArgumentException("URL to parse is null");
+        }
+
+        InputSource inputSource = createInputSourceFromURL(url);
+        inputSource.setSystemId(url.toString());
+        return this.parse(inputSource);
+    }
+
+    /**
+     * Given a URL, return an InputSource that reads from that URL.
+     * <p>
+     * Ideally this function would not be needed and code could just use
+     * <code>new InputSource(entityURL)</code>. Unfortunately it appears
+     * that when the entityURL points to a file within a jar archive a
+     * caching mechanism inside the InputSource implementation causes a
+     * file-handle to the jar file to remain open. On Windows systems
+     * this then causes the jar archive file to be locked on disk
+     * ("in use") which makes it impossible to delete the jar file -
+     * and that really stuffs up "undeploy" in webapps in particular.
+     * <p>
+     * In JDK1.4 and later, Apache XercesJ is used as the xml parser.
+     * The InputSource object provided is converted into an XMLInputSource,
+     * and eventually passed to an instance of XMLDocumentScannerImpl to
+     * specify the source data to be converted into tokens for the rest
+     * of the XMLReader code to handle. XMLDocumentScannerImpl calls
+     * fEntityManager.startDocumentEntity(source), where fEntityManager
+     * is declared in ancestor class XMLScanner to be an XMLEntityManager. In
+     * that class, if the input source stream is null, then:
+     * <pre>
+     *  URL location = new URL(expandedSystemId);
+     *  URLConnection connect = location.openConnection();
+     *  if (connect instanceof HttpURLConnection) {
+     *    setHttpProperties(connect,xmlInputSource);
+     *  }
+     *  stream = connect.getInputStream();
+     * </pre>
+     * This method pretty much duplicates the standard behaviour, except
+     * that it calls URLConnection.setUseCaches(false) before opening
+     * the connection.
+     */
+    private static InputSource createInputSourceFromURL(URL url) throws MalformedURLException,
IOException {
+        URLConnection connection = url.openConnection();
+        connection.setUseCaches(false);
+        InputStream stream = connection.getInputStream();
+        InputSource source = new InputSource(stream);
+        source.setSystemId(url.toExternalForm());
+        return source;
+    }
+
+    /**
+     * Clean up allocated resources after parsing is complete.
+     *
+     * The default method closes input streams that have been created by
+     * Digester itself.
+     */
+    private void cleanup() {
+        // If we created any InputSource objects in this instance,
+        // they each have an input stream that should be closed
+        for (InputSource source : this.inputSources) {
+            InputStream stream = source.getByteStream();
+
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (IOException e) {
+                    // Fall through so we get them all
+                }
+            }
+        }
+        this.inputSources.clear();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Map<String, String> getCurrentNamespaces() {
+        Map<String, String> currentNamespaces = new HashMap<String, String>();
+        for (Map.Entry<String, Stack<String>> nsEntry : this.namespaces.entrySet())
{
+             try {
+                currentNamespaces.put(nsEntry.getKey(), nsEntry.getValue().peek());
+            } catch (RuntimeException e) {
+                // rethrow, after logging
+                this.log.error(e.getMessage(), e);
+                throw e;
+            }
+        }
+        return currentNamespaces;
+    }
+
+    // ---- SAX exception
+
+    /**
+     * {@inheritDoc}
+     */
+    public SAXException createSAXException(String message, Exception e) {
+        if ((e != null) &&
+            (e instanceof InvocationTargetException)) {
+            Throwable t = ((InvocationTargetException) e).getTargetException();
+            if ((t != null) && (t instanceof Exception)) {
+                e = (Exception) t;
+            }
+        }
+        if (this.locator != null) {
+            String error = "Error at line "
+                + this.locator.getLineNumber()
+                + " char "
+                + this.locator.getColumnNumber()
+                + ": "
+                + message;
+            if (e != null) {
+                return new SAXParseException(error, this.locator, e);
+            } else {
+                return new SAXParseException(error, this.locator);
+            }
+        }
+        this.log.error("No Locator!");
+        if (e != null) {
+            return new SAXException(message, e);
+        } else {
+            return new SAXException(message);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public SAXException createSAXException(Exception e) {
+        if (e instanceof InvocationTargetException) {
+            Throwable t = ((InvocationTargetException) e).getTargetException();
+            if ((t != null) && (t instanceof Exception)) {
+                e = (Exception) t;
+            }
+        }
+        return createSAXException(e.getMessage(), e);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public SAXException createSAXException(String message) {
+        return createSAXException(message, null);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public <T> TypeConverter<T> lookupConverter(Class<T> type) {
+        // TODO empty for now
+        return null;
+    }
+
+}

Propchange: commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/digester3/DigesterImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/digester3/DigesterImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/sandbox/digester3/trunk/src/main/java/org/apache/commons/digester3/DigesterImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message