Author: simonetripodi
Date: Sun Sep 25 18:34:22 2011
New Revision: 1175523

URL: http://svn.apache.org/viewvc?rev=1175523&view=rev
Log:
[DIGESTER-150] Use Java5 Concurrent APIs to asynchronous parse()

Added:
    
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/AsyncReaderTestCase.java
   (with props)
Modified:
    commons/proper/digester/trunk/src/changes/changes.xml
    
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/Digester.java
    
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/DigesterLoader.java

Modified: commons/proper/digester/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/changes/changes.xml?rev=1175523&r1=1175522&r2=1175523&view=diff
==============================================================================
--- commons/proper/digester/trunk/src/changes/changes.xml (original)
+++ commons/proper/digester/trunk/src/changes/changes.xml Sun Sep 25 18:34:22 
2011
@@ -22,6 +22,11 @@
     <title>Apache Commons Digester Changes</title>
   </properties>
   <body>
+  <release version="3.1" date="2011-??-??" description="New features release.">
+    <action dev="simonetripodi" type="add" issue="DIGESTER-150">
+      Use Java5 Concurrent APIs to asynchronous parse()
+    </action>
+  </release>
   <release version="3.0" date="2011-07-06" description="New major release.">
     <action dev="simonetripodi" type="fix" issue="DIGESTER-28">
       Default ClassLoader policy unusable in EAR archive

Modified: 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/Digester.java
URL: 
http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/Digester.java?rev=1175523&r1=1175522&r2=1175523&view=diff
==============================================================================
--- 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/Digester.java
 (original)
+++ 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/Digester.java
 Sun Sep 25 18:34:22 2011
@@ -37,6 +37,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Stack;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
@@ -146,7 +149,7 @@ public class Digester
      * 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.
-     * 
+     *
      * @since 1.6
      */
     private final Stack<List<Rule>> matches = new Stack<List<Rule>>();
@@ -199,6 +202,12 @@ public class Digester
     private boolean namespaceAware = false;
 
     /**
+     * The executor service to run asynchronous parse method.
+     * @since 3.1
+     */
+    private ExecutorService executorService;
+
+    /**
      * 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
@@ -213,7 +222,7 @@ public class Digester
 
     /**
      * The parameters stack being utilized by CallMethodRule and CallParamRule 
rules.
-     * 
+     *
      * @since 2.0
      */
     private final Stack<Object[]> params = new Stack<Object[]>();
@@ -246,7 +255,7 @@ public class Digester
 
     /**
      * The XML schema to use for validating an XML instance.
-     * 
+     *
      * @since 2.0
      */
     private Schema schema = null;
@@ -310,7 +319,7 @@ public class Digester
     /**
      * Return the currently mapped namespace URI for the specified prefix, if 
any; otherwise return <code>null</code>.
      * These mappings come and go dynamically as the document is parsed.
-     * 
+     *
      * @param prefix Prefix to look up
      * @return the currently mapped namespace URI for the specified prefix
      */
@@ -362,7 +371,7 @@ public class Digester
 
     /**
      * Set the class loader to be used for instantiating application objects 
when required.
-     * 
+     *
      * @param classLoader The new class loader to use, or <code>null</code> to 
revert to the standard rules
      */
     public void setClassLoader( ClassLoader classLoader )
@@ -408,7 +417,7 @@ public class Digester
 
     /**
      * Set the error handler for this Digester.
-     * 
+     *
      * @param errorHandler The new error handler
      */
     public void setErrorHandler( ErrorHandler errorHandler )
@@ -438,7 +447,7 @@ public class Digester
      * Returns a flag indicating whether the requested feature is supported by 
the underlying implementation of
      * <code>org.xml.sax.XMLReader</code>. See <a 
href="http://www.saxproject.org";>the saxproject website</a> for
      * information about the standard SAX2 feature flags.
-     * 
+     *
      * @param feature Name of the feature to inquire about
      * @return true, if the requested feature is supported by the underlying 
implementation of
      *         <code>org.xml.sax.XMLReader</code>, false otherwise
@@ -458,7 +467,7 @@ public class Digester
      * information about the standard SAX2 feature flags. In order to be 
effective, this method must be called
      * <strong>before</strong> the <code>getParser()</code> method is called 
for the first time, either directly or
      * indirectly.
-     * 
+     *
      * @param feature Name of the feature to set the status for
      * @param value The new value for this feature
      * @exception ParserConfigurationException if a parser configuration error 
occurs
@@ -504,7 +513,7 @@ public class Digester
 
     /**
      * Sets the logger used for logging SAX-related information. 
<strong>Note</strong> the output is finely grained.
-     * 
+     *
      * @param saxLog the logger used for logging SAX-related information, not 
null
      * @since 1.6
      */
@@ -548,7 +557,7 @@ public class Digester
 
     /**
      * Set the "namespace aware" flag for parsers we create.
-     * 
+     *
      * @param namespaceAware The new "namespace aware" flag
      */
     public void setNamespaceAware( boolean namespaceAware )
@@ -559,7 +568,7 @@ public class Digester
     /**
      * Return the XInclude-aware flag for parsers we create. XInclude 
functionality additionally requires
      * namespace-awareness.
-     * 
+     *
      * @return The XInclude-aware flag
      * @see #getNamespaceAware()
      * @since 2.0
@@ -571,7 +580,7 @@ public class Digester
 
     /**
      * Set the XInclude-aware flag for parsers we create. This additionally 
requires namespace-awareness.
-     * 
+     *
      * @param xincludeAware The new XInclude-aware flag
      * @see #setNamespaceAware(boolean)
      * @since 2.0
@@ -583,7 +592,7 @@ public class Digester
 
     /**
      * Set the public id of the current file being parse.
-     * 
+     *
      * @param publicId the DTD/Schema public's id.
      */
     public void setPublicId( String publicId )
@@ -613,7 +622,7 @@ public class Digester
 
     /**
      * Set the namespace URI that will be applied to all subsequently added 
<code>Rule</code> objects.
-     * 
+     *
      * @param ruleNamespaceURI Namespace URI that must match on all 
subsequently added rules, or <code>null</code> for
      *            matching regardless of the current namespace URI
      */
@@ -656,7 +665,7 @@ public class Digester
      *
      * See <a href="http://www.saxproject.org";>the saxproject website</a> for 
information about the standard SAX2
      * properties.
-     * 
+     *
      * @param property Property name to be retrieved
      * @return the current value of the specified property for the underlying 
<code>XMLReader</code> implementation.
      * @exception SAXNotRecognizedException if the property name is not 
recognized
@@ -671,7 +680,7 @@ public class Digester
     /**
      * Set the current value of the specified property for the underlying 
<code>XMLReader</code> implementation. See <a
      * href="http://www.saxproject.org";>the saxproject website</a> for 
information about the standard SAX2 properties.
-     * 
+     *
      * @param property Property name to be set
      * @param value Property value to be set
      * @exception SAXNotRecognizedException if the property name is not 
recognized
@@ -701,7 +710,7 @@ public class Digester
 
     /**
      * Set the <code>Rules</code> implementation object containing our rules 
collection and associated matching policy.
-     * 
+     *
      * @param rules New Rules implementation
      */
     public void setRules( Rules rules )
@@ -712,7 +721,7 @@ public class Digester
 
     /**
      * Return the XML Schema used when parsing.
-     * 
+     *
      * @return The {@link Schema} instance in use.
      * @since 2.0
      */
@@ -723,7 +732,7 @@ public class Digester
 
     /**
      * Set the XML Schema to be used when parsing.
-     * 
+     *
      * @param schema The {@link Schema} instance to use.
      * @since 2.0
      */
@@ -746,7 +755,7 @@ public class Digester
      * Determine whether to use the Context ClassLoader (the one found by 
calling
      * <code>Thread.currentThread().getContextClassLoader()</code>) to 
resolve/load classes that are defined in various
      * rules. If not using Context ClassLoader, then the class-loading 
defaults to using the calling-class' ClassLoader.
-     * 
+     *
      * @param use determines whether to use Context ClassLoader.
      */
     public void setUseContextClassLoader( boolean use )
@@ -766,7 +775,7 @@ public class Digester
 
     /**
      * Set the validating parser flag. This must be called before 
<code>parse()</code> is called the first time.
-     * 
+     *
      * @param validating The new validating parser flag.
      */
     public void setValidating( boolean validating )
@@ -776,7 +785,7 @@ public class Digester
 
     /**
      * Return the XMLReader to be used for parsing the input document.
-     * 
+     *
      * FIXME: there is a bug in JAXP/XERCES that prevent the use of a parser 
that contains a schema with a DTD.
      *
      * @return the XMLReader to be used for parsing the input document.
@@ -808,8 +817,8 @@ public class Digester
 
     /**
      * Gets the <code>Substitutor</code> used to convert attributes and body 
text.
-     * 
-     * @return the <code>Substitutor</code> used to convert attributes and 
body text, 
+     *
+     * @return the <code>Substitutor</code> used to convert attributes and 
body text,
      *         null if not substitutions are to be performed.
      */
     public Substitutor getSubstitutor()
@@ -819,7 +828,7 @@ public class Digester
 
     /**
      * Sets the <code>Substitutor</code> to be used to convert attributes and 
body text.
-     * 
+     *
      * @param substitutor the Substitutor to be used to convert attributes and 
body text or null if not substitution of
      *            these values is to be performed.
      */
@@ -855,11 +864,11 @@ public class Digester
      * properly save/restore the value and maybe some day this will come in 
useful.
      * <p>
      * Note also that this is not quite equivalent to
-     * 
+     *
      * <pre>
      * digester.getXMLReader().setContentHandler( handler )
      * </pre>
-     * 
+     *
      * for these reasons:
      * <ul>
      * <li>Some xml parsers don't like having setContentHandler called after 
parsing has started. The Aelfred parser is
@@ -905,7 +914,7 @@ public class Digester
 
     /**
      * Get the most current namespaces for all prefixes.
-     * 
+     *
      * @return Map A map with namespace prefixes as keys and most current 
namespace URIs for the corresponding prefixes
      *         as values
      * @since 1.8
@@ -933,6 +942,28 @@ public class Digester
         return currentNamespaces;
     }
 
+    /**
+     * Returns the executor service used to run asynchronous parse method.
+     *
+     * @return the executor service used to run asynchronous parse method
+     * @since 3.1
+     */
+    public ExecutorService getExecutorService()
+    {
+        return executorService;
+    }
+
+    /**
+     * Sets the executor service to run asynchronous parse method.
+     *
+     * @param executorService the executor service to run asynchronous parse 
method
+     * @since 3.1
+     */
+    public void setExecutorService( ExecutorService executorService )
+    {
+        this.executorService = executorService;
+    }
+
     // ------------------------------------------------- ContentHandler Methods
 
     /**
@@ -1192,7 +1223,7 @@ public class Digester
 
     /**
      * Gets the document locator associated with our parser.
-     * 
+     *
      * @return the Locator supplied by the document parser
      */
     public Locator getDocumentLocator()
@@ -1392,7 +1423,7 @@ public class Digester
     /**
      * 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 )
@@ -1402,7 +1433,7 @@ public class Digester
 
     /**
      * Return the Entity Resolver used by the SAX parser.
-     * 
+     *
      * @return the Entity Resolver used by the SAX parser.
      */
     public EntityResolver getEntityResolver()
@@ -1536,7 +1567,7 @@ public class Digester
     /**
      * Parse the content of the specified file using this Digester. Returns 
the root element from the object stack (if
      * any).
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param file File containing the XML data to be parsed
      * @return the root element from the object stack (if any)
@@ -1558,9 +1589,32 @@ public class Digester
     }
 
     /**
+     * Creates a Callable instance that parse the content of the specified 
reader using this Digester.
+     *
+     * @param <T> The result type returned by the returned Future's {@code 
get} method
+     * @param file File containing the XML data to be parsed
+     * @return a Future that can be used to track when the parse has been 
fully processed.
+     * @see Digester#parse(File)
+     * @since 3.1
+     */
+    public <T> Future<T> asyncParse( final File file )
+    {
+        return asyncParse( new Callable<T>()
+        {
+
+            public T call()
+                throws Exception
+            {
+                return Digester.this.<T> parse( file );
+            }
+
+        } );
+    }
+
+    /**
      * Parse the content of the specified input source using this Digester. 
Returns the root element from the object
      * stack (if any).
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param input Input source containing the XML data to be parsed
      * @return the root element from the object stack (if any)
@@ -1604,9 +1658,32 @@ public class Digester
     }
 
     /**
+     * Creates a Callable instance that parse the content of the specified 
reader using this Digester.
+     *
+     * @param <T> The result type returned by the returned Future's {@code 
get} method
+     * @param input Input source containing the XML data to be parsed
+     * @return a Future that can be used to track when the parse has been 
fully processed.
+     * @see Digester#parse(InputSource)
+     * @since 3.1
+     */
+    public <T> Future<T> asyncParse( final InputSource input )
+    {
+        return asyncParse( new Callable<T>()
+        {
+
+            public T call()
+                throws Exception
+            {
+                return Digester.this.<T> parse( input );
+            }
+
+        } );
+    }
+
+    /**
      * Parse the content of the specified input stream using this Digester. 
Returns the root element from the object
      * stack (if any).
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param input Input stream containing the XML data to be parsed
      * @return the root element from the object stack (if any)
@@ -1625,9 +1702,32 @@ public class Digester
     }
 
     /**
+     * Creates a Callable instance that parse the content of the specified 
reader using this Digester.
+     *
+     * @param <T> The result type returned by the returned Future's {@code 
get} method
+     * @param input Input stream containing the XML data to be parsed
+     * @return a Future that can be used to track when the parse has been 
fully processed.
+     * @see Digester#parse(InputStream)
+     * @since 3.1
+     */
+    public <T> Future<T> asyncParse( final InputStream input )
+    {
+        return asyncParse( new Callable<T>()
+        {
+
+            public T call()
+                throws Exception
+            {
+                return Digester.this.<T> parse( input );
+            }
+
+        } );
+    }
+
+    /**
      * Parse the content of the specified reader using this Digester. Returns 
the root element from the object stack (if
      * any).
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param reader Reader containing the XML data to be parsed
      * @return the root element from the object stack (if any)
@@ -1646,9 +1746,32 @@ public class Digester
     }
 
     /**
+     * Creates a Callable instance that parse the content of the specified 
reader using this Digester.
+     *
+     * @param <T> The result type returned by the returned Future's {@code 
get} method
+     * @param reader Reader containing the XML data to be parsed
+     * @return a Future that can be used to track when the parse has been 
fully processed.
+     * @see Digester#parse(Reader)
+     * @since 3.1
+     */
+    public <T> Future<T> asyncParse( final Reader reader )
+    {
+        return asyncParse( new Callable<T>()
+        {
+
+            public T call()
+                throws Exception
+            {
+                return Digester.this.<T> parse( reader );
+            }
+
+        } );
+    }
+
+    /**
      * Parse the content of the specified URI using this Digester. Returns the 
root element from the object stack (if
      * any).
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param uri URI containing the XML data to be parsed
      * @return the root element from the object stack (if any)
@@ -1667,9 +1790,32 @@ public class Digester
     }
 
     /**
+     * Creates a Callable instance that parse the content of the specified 
reader using this Digester.
+     *
+     * @param <T> The result type returned by the returned Future's {@code 
get} method
+     * @param uri URI containing the XML data to be parsed
+     * @return a Future that can be used to track when the parse has been 
fully processed.
+     * @see Digester#parse(String)
+     * @since 3.1
+     */
+    public <T> Future<T> asyncParse( final String uri )
+    {
+        return asyncParse( new Callable<T>()
+        {
+
+            public T call()
+                throws Exception
+            {
+                return Digester.this.<T> parse( uri );
+            }
+
+        } );
+    }
+
+    /**
      * Parse the content of the specified URL using this Digester. Returns the 
root element from the object stack (if
      * any).
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param url URL containing the XML data to be parsed
      * @return the root element from the object stack (if any)
@@ -1689,6 +1835,47 @@ public class Digester
     }
 
     /**
+     * Creates a Callable instance that parse the content of the specified 
reader using this Digester.
+     *
+     * @param <T> The result type returned by the returned Future's {@code 
get} method
+     * @param url URL containing the XML data to be parsed
+     * @return a Future that can be used to track when the parse has been 
fully processed.
+     * @see Digester#parse(URL)
+     * @since 3.1
+     */
+    public <T> Future<T> asyncParse( final URL url )
+    {
+        return asyncParse( new Callable<T>()
+        {
+
+            public T call()
+                throws Exception
+            {
+                return Digester.this.<T> parse( url );
+            }
+
+        } );
+    }
+
+    /**
+     * Execute the parse in async mode.
+     *
+     * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
+     * @param callable
+     * @return a Future that can be used to track when the parse has been 
fully processed.
+     * @since 3.1
+     */
+    private <T> Future<T> asyncParse( Callable<T> callable )
+    {
+        if ( executorService == null )
+        {
+            throw new IllegalStateException( "ExecutorService not set" );
+        }
+
+        return executorService.submit( callable );
+    }
+
+    /**
      * <p>
      * Register the specified DTD URL for the specified public identifier. 
This must be called before the first call to
      * <code>parse()</code>.
@@ -1705,7 +1892,7 @@ public class Digester
      * <strong>Note:</strong> This method will have no effect when a custom 
<code>EntityResolver</code> has been set.
      * (Setting a custom <code>EntityResolver</code> overrides the internal 
implementation.)
      * </p>
-     * 
+     *
      * @param publicId Public identifier of the DTD to be resolved
      * @param entityURL The URL to use for reading this DTD
      * @since 1.8
@@ -1723,7 +1910,7 @@ public class Digester
      * <p>
      * Convenience method that registers the string version of an entity URL 
instead of a URL version.
      * </p>
-     * 
+     *
      * @param publicId Public identifier of the entity to be resolved
      * @param entityURL The URL to use for reading this entity
      */
@@ -1778,7 +1965,7 @@ public class Digester
      * 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();
@@ -1788,7 +1975,7 @@ public class Digester
      * }
      * stream = connect.getInputStream();
      * </pre>
-     * 
+     *
      * This method pretty much duplicates the standard behaviour, except that 
it calls URLConnection.setUseCaches(false)
      * before opening the connection.
      *
@@ -1813,7 +2000,7 @@ public class Digester
      * <p>
      * Convenience method that creates an <code>InputSource</code> from the 
string version of a URL.
      * </p>
-     * 
+     *
      * @param url URL for which to create an <code>InputSource</code>
      * @return The InputSource that reads from the input URL
      * @throws IOException if any error occurs while reading the input URL
@@ -1832,7 +2019,7 @@ public class Digester
      * Register a new Rule matching the specified pattern. This method sets 
the <code>Digester</code> property on the
      * rule.
      * </p>
-     * 
+     *
      * @param pattern Element matching pattern
      * @param rule Rule to be registered
      */
@@ -1844,7 +2031,7 @@ public class Digester
 
     /**
      * Register a set of Rule instances defined in a RuleSet.
-     * 
+     *
      * @param ruleSet The RuleSet instance to configure from
      */
     public void addRuleSet( RuleSet ruleSet )
@@ -1869,7 +2056,7 @@ public class Digester
 
     /**
      * Add a "bean property setter" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @see BeanPropertySetterRule
      */
@@ -1880,7 +2067,7 @@ public class Digester
 
     /**
      * Add a "bean property setter" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param propertyName Name of property to set
      * @see BeanPropertySetterRule
@@ -1892,7 +2079,7 @@ public class Digester
 
     /**
      * Add an "call method" rule for a method which accepts no arguments.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to be called
      * @see CallMethodRule
@@ -1904,7 +2091,7 @@ public class Digester
 
     /**
      * Add an "call method" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to be called
      * @param paramCount Number of expected parameters (or zero for a single 
parameter from the body of this element)
@@ -1919,7 +2106,7 @@ public class Digester
      * Add an "call method" rule for the specified parameters. If 
<code>paramCount</code> is set to zero the rule will
      * use the body of the matched element as the single argument of the 
method, unless <code>paramTypes</code> is null
      * or empty, in this case the rule will call the specified method with no 
arguments.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to be called
      * @param paramCount Number of expected parameters (or zero for a single 
parameter from the body of this element)
@@ -1937,7 +2124,7 @@ public class Digester
      * Add an "call method" rule for the specified parameters. If 
<code>paramCount</code> is set to zero the rule will
      * use the body of the matched element as the single argument of the 
method, unless <code>paramTypes</code> is null
      * or empty, in this case the rule will call the specified method with no 
arguments.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to be called
      * @param paramCount Number of expected parameters (or zero for a single 
parameter from the body of this element)
@@ -1953,7 +2140,7 @@ public class Digester
 
     /**
      * Add a "call parameter" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param paramIndex Zero-relative parameter index to set (from the body 
of this element)
      * @see CallParamRule
@@ -1965,7 +2152,7 @@ public class Digester
 
     /**
      * Add a "call parameter" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param paramIndex Zero-relative parameter index to set (from the 
specified attribute)
      * @param attributeName Attribute whose value is used as the parameter 
value
@@ -1979,7 +2166,7 @@ public class Digester
     /**
      * Add a "call parameter" rule. This will either take a parameter from the 
stack or from the current element body
      * text.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param paramIndex The zero-relative parameter number
      * @param fromStack Should the call parameter be taken from the top of the 
stack?
@@ -1993,7 +2180,7 @@ public class Digester
     /**
      * Add a "call parameter" rule that sets a parameter from the stack. This 
takes a parameter from the given position
      * on the stack.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param paramIndex The zero-relative parameter number
      * @param stackIndex set the call parameter to the stackIndex'th object 
down the stack, where 0 is the top of the
@@ -2008,7 +2195,7 @@ public class Digester
     /**
      * Add a "call parameter" rule that sets a parameter from the current 
<code>Digester</code> matching path. This is
      * sometimes useful when using rules that support wildcards.
-     * 
+     *
      * @param pattern the pattern that this rule should match
      * @param paramIndex The zero-relative parameter number
      * @see CallMethodRule
@@ -2026,7 +2213,7 @@ public class Digester
      * Note that when attempting to locate a matching method to invoke, the 
true type of the paramObj is used, so that
      * despite the paramObj being passed in here as type Object, the target 
method can declare its parameters as being
      * the true type of the object (or some ancestor type, according to the 
usual type-conversion rules).
-     * 
+     *
      * @param pattern Element matching pattern
      * @param paramIndex The zero-relative parameter number
      * @param paramObj Any arbitrary object to be passed to the target method.
@@ -2041,7 +2228,7 @@ public class Digester
     /**
      * Add a "factory create" rule for the specified parameters. Exceptions 
thrown during the object creation process
      * will be propagated.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param className Java class name of the object creation factory class
      * @see FactoryCreateRule
@@ -2054,7 +2241,7 @@ public class Digester
     /**
      * Add a "factory create" rule for the specified parameters. Exceptions 
thrown during the object creation process
      * will be propagated.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param clazz Java class of the object creation factory class
      * @see FactoryCreateRule
@@ -2067,7 +2254,7 @@ public class Digester
     /**
      * Add a "factory create" rule for the specified parameters. Exceptions 
thrown during the object creation process
      * will be propagated.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param className Java class name of the object creation factory class
      * @param attributeName Attribute name which, if present, overrides the 
value specified by <code>className</code>
@@ -2081,7 +2268,7 @@ public class Digester
     /**
      * Add a "factory create" rule for the specified parameters. Exceptions 
thrown during the object creation process
      * will be propagated.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param clazz Java class of the object creation factory class
      * @param attributeName Attribute name which, if present, overrides the 
value specified by <code>className</code>
@@ -2096,7 +2283,7 @@ public class Digester
     /**
      * Add a "factory create" rule for the specified parameters. Exceptions 
thrown during the object creation process
      * will be propagated.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param creationFactory Previously instantiated ObjectCreationFactory to 
be utilized
      * @see FactoryCreateRule
@@ -2108,7 +2295,7 @@ public class Digester
 
     /**
      * Add a "factory create" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param className Java class name of the object creation factory class
      * @param ignoreCreateExceptions when <code>true</code> any exceptions 
thrown during object creation will be
@@ -2122,7 +2309,7 @@ public class Digester
 
     /**
      * Add a "factory create" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param clazz Java class of the object creation factory class
      * @param ignoreCreateExceptions when <code>true</code> any exceptions 
thrown during object creation will be
@@ -2137,7 +2324,7 @@ public class Digester
 
     /**
      * Add a "factory create" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param className Java class name of the object creation factory class
      * @param attributeName Attribute name which, if present, overrides the 
value specified by <code>className</code>
@@ -2153,7 +2340,7 @@ public class Digester
 
     /**
      * Add a "factory create" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param clazz Java class of the object creation factory class
      * @param attributeName Attribute name which, if present, overrides the 
value specified by <code>className</code>
@@ -2169,7 +2356,7 @@ public class Digester
 
     /**
      * Add a "factory create" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param creationFactory Previously instantiated ObjectCreationFactory to 
be utilized
      * @param ignoreCreateExceptions when <code>true</code> any exceptions 
thrown during object creation will be
@@ -2185,7 +2372,7 @@ public class Digester
 
     /**
      * Add an "object create" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param className Java class name to be created
      * @see ObjectCreateRule
@@ -2197,7 +2384,7 @@ public class Digester
 
     /**
      * Add an "object create" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param clazz Java class to be created
      * @see ObjectCreateRule
@@ -2209,7 +2396,7 @@ public class Digester
 
     /**
      * Add an "object create" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param className Default Java class name to be created
      * @param attributeName Attribute name that optionally overrides the 
default Java class name to be created
@@ -2222,7 +2409,7 @@ public class Digester
 
     /**
      * Add an "object create" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param attributeName Attribute name that optionally overrides
      * @param clazz Default Java class to be created the default Java class 
name to be created
@@ -2235,7 +2422,7 @@ public class Digester
 
     /**
      * Adds an {@link SetNestedPropertiesRule}.
-     * 
+     *
      * @param pattern register the rule with this pattern
      * @since 1.6
      */
@@ -2246,7 +2433,7 @@ public class Digester
 
     /**
      * Adds an {@link SetNestedPropertiesRule}.
-     * 
+     *
      * @param pattern register the rule with this pattern
      * @param elementName elment name that a property maps to
      * @param propertyName property name of the element mapped from
@@ -2259,7 +2446,7 @@ public class Digester
 
     /**
      * Adds an {@link SetNestedPropertiesRule}.
-     * 
+     *
      * @param pattern register the rule with this pattern
      * @param elementNames elment names that (in order) map to properties
      * @param propertyNames property names that (in order) elements are mapped 
to
@@ -2272,7 +2459,7 @@ public class Digester
 
     /**
      * Add a "set next" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to call on the parent element
      * @see SetNextRule
@@ -2284,7 +2471,7 @@ public class Digester
 
     /**
      * Add a "set next" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to call on the parent element
      * @param paramType Java class name of the expected parameter type (if you 
wish to use a primitive type, specify the
@@ -2299,7 +2486,7 @@ public class Digester
 
     /**
      * Add {@link SetRootRule} with the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to call on the root object
      * @see SetRootRule
@@ -2311,7 +2498,7 @@ public class Digester
 
     /**
      * Add {@link SetRootRule} with the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to call on the root object
      * @param paramType Java class name of the expected parameter type
@@ -2324,7 +2511,7 @@ public class Digester
 
     /**
      * Add a "set properties" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @see SetPropertiesRule
      */
@@ -2336,7 +2523,7 @@ public class Digester
     /**
      * Add a "set properties" rule with a single overridden parameter. See
      * {@link SetPropertiesRule#SetPropertiesRule(String attributeName, String 
propertyName)}
-     * 
+     *
      * @param pattern Element matching pattern
      * @param attributeName map this attribute
      * @param propertyName to this property
@@ -2350,7 +2537,7 @@ public class Digester
     /**
      * Add a "set properties" rule with overridden parameters. See
      * {@link SetPropertiesRule#SetPropertiesRule(String [] attributeNames, 
String [] propertyNames)}
-     * 
+     *
      * @param pattern Element matching pattern
      * @param attributeNames names of attributes with custom mappings
      * @param propertyNames property names these attributes map to
@@ -2363,7 +2550,7 @@ public class Digester
 
     /**
      * Add a "set property" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param name Attribute name containing the property name to be set
      * @param value Attribute name containing the property value to set
@@ -2376,7 +2563,7 @@ public class Digester
 
     /**
      * Add a "set top" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to call on the parent element
      * @see SetTopRule
@@ -2388,7 +2575,7 @@ public class Digester
 
     /**
      * Add a "set top" rule for the specified parameters.
-     * 
+     *
      * @param pattern Element matching pattern
      * @param methodName Method name to call on the parent element
      * @param paramType Java class name of the expected parameter type (if you 
wish to use a primitive type, specify the
@@ -2450,7 +2637,7 @@ public class Digester
     /**
      * Return the n'th object down the stack, where 0 is the top element and 
[getCount()-1] is the bottom element. If
      * the specified index is out of range, return <code>null</code>.
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param n Index of the desired element, where 0 is the top of the stack, 
1 is the next element down, and so on.
      * @return the n'th object down the stack
@@ -2477,7 +2664,7 @@ public class Digester
     /**
      * Pop the top object off of the stack, and return it. If there are no 
objects on the stack, return
      * <code>null</code>.
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @return the top object popped off of the stack
      */
@@ -2501,7 +2688,7 @@ public class Digester
 
     /**
      * Push a new object onto the top of the object stack.
-     * 
+     *
      * @param <T> any type of the pushed object
      * @param object The new object
      */
@@ -2522,7 +2709,7 @@ public class Digester
     /**
      * Pushes the given object onto the stack with the given name. If no stack 
already exists with the given name then
      * one will be created.
-     * 
+     *
      * @param <T> any type of the pushed object
      * @param stackName the name of the stack onto which the object should be 
pushed
      * @param value the Object to be pushed onto the named stack.
@@ -2551,7 +2738,7 @@ public class Digester
      * <p>
      * <strong>Note:</strong> a stack is considered empty if no objects have 
been pushed onto it yet.
      * </p>
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param stackName the name of the stack from which the top value is to 
be popped.
      * @return the top <code>Object</code> on the stack or or null if the 
stack is either empty or has not been created
@@ -2588,7 +2775,7 @@ public class Digester
      * <p>
      * <strong>Note:</strong> a stack is considered empty if no objects have 
been pushed onto it yet.
      * </p>
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param stackName the name of the stack to be peeked
      * @return the top <code>Object</code> on the stack or null if the stack 
is either empty or has not been created yet
@@ -2606,7 +2793,7 @@ public class Digester
      * <p>
      * <strong>Note:</strong> a stack is considered empty if no objects have 
been pushed onto it yet.
      * </p>
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @param stackName the name of the stack to be peeked
      * @param n Index of the desired element, where 0 is the top of the stack, 
1 is the next element down, and so on.
@@ -2643,7 +2830,7 @@ public class Digester
      * <p>
      * <strong>Note:</strong> a stack is considered empty if no objects have 
been pushed onto it yet.
      * </p>
-     * 
+     *
      * @param stackName the name of the stack whose emptiness should be 
evaluated
      * @return true if the given stack if empty
      * @since 1.6
@@ -2676,7 +2863,7 @@ public class Digester
      * same as the return value from this method. However when the Digester is 
being used as a SAXContentHandler, no
      * such return value is available; in this case, this method allows you to 
access the root object that has been
      * created after parsing has completed.
-     * 
+     *
      * @param <T> the type used to auto-cast the returned object to the 
assigned variable type
      * @return the root object that has been created after parsing or null if 
the digester has not parsed any XML yet.
      */
@@ -2690,7 +2877,7 @@ public class Digester
      * <p>
      * It is not considered safe for a digester instance to be reused to parse 
multiple xml documents. However if you
      * are determined to do so, then you should call both clear() and 
resetRoot() before each parse.
-     * 
+     *
      * @since 1.7
      */
     public void resetRoot()
@@ -2708,7 +2895,7 @@ public class Digester
      * created by Digester itself. If you override this method in a subclass, 
be sure to call
      * <code>super.cleanup()</code> to invoke this logic.
      * </p>
-     * 
+     *
      * @since 1.8
      */
     protected void cleanup()
@@ -2757,7 +2944,7 @@ public class Digester
 
     /**
      * Checks the Digester instance has been configured.
-     * 
+     *
      * @return true, if the Digester instance has been configured, false 
otherwise
      * @since 3.0
      */
@@ -2776,7 +2963,7 @@ public class Digester
      * false. Subclasses that override <code>configure</code> or who set 
<code>configured</code> may find that this
      * method may be called more than once.
      * </p>
-     * 
+     *
      * @since 1.6
      */
     protected void initialize()
@@ -2829,7 +3016,7 @@ public class Digester
      * <p>
      * The parameters stack is used to store <code>CallMethodRule</code> 
parameters. See {@link #params}.
      * </p>
-     * 
+     *
      * @param n Index of the desired element, where 0 is the top of the stack, 
1 is the next element down, and so on.
      * @return the n'th object down the parameters stack
      */
@@ -2887,7 +3074,7 @@ public class Digester
      * <p>
      * The parameters stack is used to store <code>CallMethodRule</code> 
parameters. See {@link #params}.
      * </p>
-     * 
+     *
      * @param object The new object
      */
     public void pushParams( Object... object )
@@ -2936,7 +3123,7 @@ public class Digester
 
     /**
      * Create a SAX exception which also understands about the location in the 
digester file where the exception occurs
-     * 
+     *
      * @param e the exception cause
      * @return the new SAX exception
      */
@@ -2955,7 +3142,7 @@ public class Digester
 
     /**
      * Create a SAX exception which also understands about the location in the 
digester file where the exception occurs
-     * 
+     *
      * @param message the custom SAX exception message
      * @return the new SAX exception
      */
@@ -2966,7 +3153,7 @@ public class Digester
 
     /**
      * Helps casting the input object to given type, avoiding NPEs.
-     * 
+     *
      * @since 3.0
      * @param <T> the type the input object has to be cast.
      * @param obj the object has to be cast.

Modified: 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/DigesterLoader.java
URL: 
http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/DigesterLoader.java?rev=1175523&r1=1175522&r2=1175523&view=diff
==============================================================================
--- 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/DigesterLoader.java
 (original)
+++ 
commons/proper/digester/trunk/src/main/java/org/apache/commons/digester3/binder/DigesterLoader.java
 Sun Sep 25 18:34:22 2011
@@ -28,6 +28,7 @@ import java.util.Collections;
 import java.util.Formatter;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ExecutorService;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
@@ -127,6 +128,12 @@ public final class DigesterLoader
     private StackAction stackAction;
 
     /**
+     * The executor service to run asynchronous parse method.
+     * @since 3.1
+     */
+    private ExecutorService executorService;
+
+    /**
      * Creates a new {@link DigesterLoader} instance given a collection of 
{@link RulesModule} instance.
      *
      * @param rulesModules The modules containing the {@code Rule} binding
@@ -164,7 +171,7 @@ public final class DigesterLoader
         return this;
     }
 
-    /** 
+    /**
      * Sets the <code>Substitutor</code> to be used to convert attributes and 
body text.
      *
      * @param substitutor the Substitutor to be used to convert attributes and 
body text
@@ -263,18 +270,18 @@ public final class DigesterLoader
      * This must be called before the first call to <code>parse()</code>.
      * </p><p>
      * <code>Digester</code> contains an internal <code>EntityResolver</code>
-     * implementation. This maps <code>PUBLICID</code>'s to URLs 
+     * implementation. This maps <code>PUBLICID</code>'s to URLs
      * (from which the resource will be loaded). A common use case for this
-     * method is to register local URLs (possibly computed at runtime by a 
+     * method is to register local URLs (possibly computed at runtime by a
      * classloader) for DTDs. This allows the performance advantage of using
      * a local version without having to ensure every <code>SYSTEM</code>
      * URI on every processed xml document is local. This implementation 
provides
      * only basic functionality. If more sophisticated features are required,
      * using {@link #setEntityResolver(EntityResolver)} to set a custom 
resolver is recommended.
      * </p><p>
-     * <strong>Note:</strong> This method will have no effect when a custom 
-     * <code>EntityResolver</code> has been set. (Setting a custom 
-     * <code>EntityResolver</code> overrides the internal implementation.) 
+     * <strong>Note:</strong> This method will have no effect when a custom
+     * <code>EntityResolver</code> has been set. (Setting a custom
+     * <code>EntityResolver</code> overrides the internal implementation.)
      * </p>
      * @param publicId Public identifier of the DTD to be resolved
      * @param entityURL The URL to use for reading this DTD
@@ -319,7 +326,7 @@ public final class DigesterLoader
     /**
      * 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.
      * @return This loader instance, useful to chain methods.
      */
@@ -343,6 +350,30 @@ public final class DigesterLoader
     }
 
     /**
+     * Returns the executor service used to run asynchronous parse method.
+     *
+     * @return the executor service used to run asynchronous parse method
+     * @since 3.1
+     */
+    public ExecutorService getExecutorService()
+    {
+        return executorService;
+    }
+
+    /**
+     * Sets the executor service to run asynchronous parse method.
+     *
+     * @param executorService the executor service to run asynchronous parse 
method
+     * @return This loader instance, useful to chain methods.
+     * @since 3.1
+     */
+    public DigesterLoader setExecutorService( ExecutorService executorService )
+    {
+        this.executorService = executorService;
+        return this;
+    }
+
+    /**
      * Creates a new {@link Digester} instance that relies on the default 
{@link Rules} implementation.
      *
      * @return a new {@link Digester} instance
@@ -449,6 +480,7 @@ public final class DigesterLoader
         digester.setEntityResolver( entityResolver );
         digester.setStackAction( stackAction );
         digester.setNamespaceAware( isNamespaceAware() );
+        digester.setExecutorService( executorService );
 
         addRules( digester );
 

Added: 
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/AsyncReaderTestCase.java
URL: 
http://svn.apache.org/viewvc/commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/AsyncReaderTestCase.java?rev=1175523&view=auto
==============================================================================
--- 
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/AsyncReaderTestCase.java
 (added)
+++ 
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/AsyncReaderTestCase.java
 Sun Sep 25 18:34:22 2011
@@ -0,0 +1,124 @@
+package org.apache.commons.digester3;
+
+/*
+ * 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.
+ */
+
+import static java.lang.System.getProperty;
+import static java.util.concurrent.Executors.newFixedThreadPool;
+import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+import java.io.InputStreamReader;
+import java.util.concurrent.Future;
+
+import org.apache.commons.digester3.binder.AbstractRulesModule;
+import org.apache.commons.digester3.binder.DigesterLoader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.xml.sax.InputSource;
+
+public final class AsyncReaderTestCase
+{
+
+    private final DigesterLoader digesterLoader = newLoader( new 
AbstractRulesModule()
+    {
+
+        @Override
+        protected void configure()
+        {
+            forPattern( "employee" ).createObject().ofType( Employee.class );
+        }
+
+    } ).setExecutorService( newFixedThreadPool( 1 ) );
+
+    private Digester digester;
+
+    @Before
+    public void setUp()
+    {
+        digester = digesterLoader.newDigester();
+    }
+
+    @After
+    public void tearDown()
+    {
+        digester = null;
+    }
+
+    @Test
+    public void parseFromFile()
+        throws Exception
+    {
+        Future<Employee> future = digester.asyncParse( new File( getProperty( 
"user.dir" ),
+            "src/test/resources/org/apache/commons/digester3/Test9.xml" ) );
+        verify( future );
+    }
+
+    @Test
+    public void parseFromClasspathURL()
+        throws Exception
+    {
+        Future<Employee> future = digester.asyncParse( getClass().getResource( 
"Test9.xml" ) );
+        verify( future );
+    }
+
+    @Test
+    public void parseFromInputStream()
+        throws Exception
+    {
+        Future<Employee> future = digester.asyncParse( getClass().getResource( 
"Test9.xml" ).openStream() );
+        verify( future );
+    }
+
+    @Test
+    public void parseFromInputSource()
+        throws Exception
+    {
+        Future<Employee> future =
+            digester.asyncParse( new InputSource( getClass().getResource( 
"Test9.xml" ).openStream() ) );
+        verify( future );
+    }
+
+    @Test
+    public void parseFromReader()
+        throws Exception
+    {
+        Future<Employee> future =
+            digester.asyncParse( new InputStreamReader( 
getClass().getResource( "Test9.xml" ).openStream() ) );
+        verify( future );
+    }
+
+    @Test
+    public void parseFromUri()
+        throws Exception
+    {
+        Future<Employee> future = digester.asyncParse( getClass().getResource( 
"Test9.xml" ).toExternalForm() );
+        verify( future );
+    }
+
+    private void verify( Future<Employee> result )
+        throws Exception
+    {
+        Employee employee = result.get();
+        assertNotNull( employee );
+    }
+
+}

Propchange: 
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/AsyncReaderTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/AsyncReaderTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
commons/proper/digester/trunk/src/test/java/org/apache/commons/digester3/AsyncReaderTestCase.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain


Reply via email to