package org.apache.commons.digester3.binder;

/*
 * 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 org.apache.commons.digester3.binder.BinderClassLoader.createBinderClassLoader;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
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;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.validation.Schema;

import org.apache.commons.digester3.Digester;
import org.apache.commons.digester3.RuleSet;
import org.apache.commons.digester3.Rules;
import org.apache.commons.digester3.RulesBase;
import org.apache.commons.digester3.StackAction;
import org.apache.commons.digester3.Substitutor;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

This class manages the creation of Digester instances from digester rules modules.
/** * This class manages the creation of Digester instances from digester rules modules. */
public final class DigesterLoader {
The default head when reporting an errors list.
/** * The default head when reporting an errors list. */
private static final String HEADING = "Digester creation errors:%n%n";
Creates a new DigesterLoader instance given one or more RulesModule instance.
Params:
  • rulesModules – The modules containing the Rule binding
Returns:A new DigesterLoader instance
/** * Creates a new {@link DigesterLoader} instance given one or more {@link RulesModule} instance. * * @param rulesModules The modules containing the {@code Rule} binding * @return A new {@link DigesterLoader} instance */
public static DigesterLoader newLoader( RulesModule... rulesModules ) { if ( rulesModules == null || rulesModules.length == 0 ) { throw new DigesterLoadingException( "At least one RulesModule has to be specified" ); } return newLoader( Arrays.asList( rulesModules ) ); }
Creates a new DigesterLoader instance given a collection of RulesModule instance.
Params:
  • rulesModules – The modules containing the Rule binding
Returns:A new DigesterLoader instance
/** * Creates a new {@link DigesterLoader} instance given a collection of {@link RulesModule} instance. * * @param rulesModules The modules containing the {@code Rule} binding * @return A new {@link DigesterLoader} instance */
public static DigesterLoader newLoader( Iterable<RulesModule> rulesModules ) { if ( rulesModules == null ) { throw new DigesterLoadingException( "RulesModule has to be specified" ); } return new DigesterLoader( rulesModules ); }
The concrete RulesBinder implementation.
/** * The concrete {@link RulesBinder} implementation. */
private final DefaultRulesBinder rulesBinder = new DefaultRulesBinder();
The URLs of entityValidator that have been registered, keyed by the public identifier that corresponds.
/** * The URLs of entityValidator that have been registered, keyed by the public * identifier that corresponds. */
private final Map<String, URL> entityValidator = new HashMap<String, URL>();
The SAXParserFactory to create new default Digester instances.
/** * The SAXParserFactory to create new default {@link Digester} instances. */
private final SAXParserFactory factory = SAXParserFactory.newInstance(); private final Iterable<RulesModule> rulesModules;
The class loader to use for instantiating application objects. If not specified, the context class loader, or the class loader used to load Digester itself, is used, based on the value of the useContextClassLoader variable.
/** * The class loader to use for instantiating application objects. * If not specified, the context class loader, or the class loader * used to load Digester itself, is used, based on the value of the * <code>useContextClassLoader</code> variable. */
private BinderClassLoader 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.
/** * 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 Substitutor substitutor;
The EntityResolver used by the SAX parser. By default it use this class
/** * The EntityResolver used by the SAX parser. By default it use this class */
private EntityResolver entityResolver;
Object which will receive callbacks for every pop/push action on the default stack or named stacks.
/** * Object which will receive callbacks for every pop/push action on the default stack or named stacks. */
private StackAction stackAction;
The executor service to run asynchronous parse method.
Since:3.1
/** * The executor service to run asynchronous parse method. * @since 3.1 */
private ExecutorService executorService;
The application-supplied error handler that is notified when parsing warnings, errors, or fatal errors occur.
Since:3.2
/** * The application-supplied error handler that is notified when parsing warnings, errors, or fatal errors occur. * @since 3.2 */
private ErrorHandler errorHandler = null;
The Locator associated with our parser.
Since:3.2
/** * The Locator associated with our parser. * @since 3.2 */
private Locator locator = null;
Creates a new DigesterLoader instance given a collection of RulesModule instance.
Params:
  • rulesModules – The modules containing the Rule binding
/** * Creates a new {@link DigesterLoader} instance given a collection of {@link RulesModule} instance. * * @param rulesModules The modules containing the {@code Rule} binding */
private DigesterLoader( Iterable<RulesModule> rulesModules ) { this.rulesModules = rulesModules; setUseContextClassLoader( true ); }
Determine whether to use the Context ClassLoader (the one found by calling Thread.currentThread().getContextClassLoader()) 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.
Params:
  • useContextClassLoader – determines whether to use Context ClassLoader.
Returns:This loader instance, useful to chain methods.
/** * 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 useContextClassLoader determines whether to use Context ClassLoader. * @return This loader instance, useful to chain methods. */
public DigesterLoader setUseContextClassLoader( boolean useContextClassLoader ) { if ( useContextClassLoader ) { setClassLoader( Thread.currentThread().getContextClassLoader() ); } else { setClassLoader( getClass().getClassLoader() ); } return this; }
Set the class loader to be used for instantiating application objects when required.
Params:
  • classLoader – the class loader to be used for instantiating application objects when required.
Returns:This loader instance, useful to chain methods.
/** * Set the class loader to be used for instantiating application objects when required. * * @param classLoader the class loader to be used for instantiating application objects when required. * @return This loader instance, useful to chain methods. */
public DigesterLoader setClassLoader( ClassLoader classLoader ) { if ( classLoader == null ) { throw new IllegalArgumentException( "Parameter 'classLoader' cannot be null" ); } this.classLoader = createBinderClassLoader( classLoader ); return this; }
Sets the Substitutor to be used to convert attributes and body text.
Params:
  • substitutor – the Substitutor to be used to convert attributes and body text or null if not substitution of these values is to be performed.
Returns:This loader instance, useful to chain methods.
/** * 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. * @return This loader instance, useful to chain methods. */
public DigesterLoader setSubstitutor( Substitutor substitutor ) { this.substitutor = substitutor; return this; }
Set the "namespace aware" flag for parsers we create.
Params:
  • namespaceAware – The new "namespace aware" flag
Returns:This loader instance, useful to chain methods.
/** * Set the "namespace aware" flag for parsers we create. * * @param namespaceAware The new "namespace aware" flag * @return This loader instance, useful to chain methods. */
public DigesterLoader setNamespaceAware( boolean namespaceAware ) { factory.setNamespaceAware( namespaceAware ); return this; }
Return the "namespace aware" flag for parsers we create.
Returns:true, if the "namespace aware" flag for parsers we create, false otherwise.
/** * Return the "namespace aware" flag for parsers we create. * * @return true, if the "namespace aware" flag for parsers we create, false otherwise. */
public boolean isNamespaceAware() { return factory.isNamespaceAware(); }
Set the XInclude-aware flag for parsers we create. This additionally requires namespace-awareness.
Params:
  • xIncludeAware – The new XInclude-aware flag
See Also:
Returns:This loader instance, useful to chain methods.
/** * Set the XInclude-aware flag for parsers we create. This additionally * requires namespace-awareness. * * @param xIncludeAware The new XInclude-aware flag * @return This loader instance, useful to chain methods. * @see #setNamespaceAware(boolean) */
public DigesterLoader setXIncludeAware( boolean xIncludeAware ) { factory.setXIncludeAware( xIncludeAware ); return this; }
Return the XInclude-aware flag for parsers we create;
Returns:true, if the XInclude-aware flag for parsers we create is set, false otherwise
/** * Return the XInclude-aware flag for parsers we create; * * @return true, if the XInclude-aware flag for parsers we create is set, * false otherwise */
public boolean isXIncludeAware() { return factory.isXIncludeAware(); }
Set the validating parser flag.
Params:
  • validating – The new validating parser flag.
Returns:This loader instance, useful to chain methods.
/** * Set the validating parser flag. * * @param validating The new validating parser flag. * @return This loader instance, useful to chain methods. */
public DigesterLoader setValidating( boolean validating ) { factory.setValidating( validating ); return this; }
Return the validating parser flag.
Returns:true, if the validating parser flag is set, false otherwise
/** * Return the validating parser flag. * * @return true, if the validating parser flag is set, false otherwise */
public boolean isValidating() { return this.factory.isValidating(); }
Set the XML Schema to be used when parsing.
Params:
  • schema – The Schema instance to use.
Returns:This loader instance, useful to chain methods.
/** * Set the XML Schema to be used when parsing. * * @param schema The {@link Schema} instance to use. * @return This loader instance, useful to chain methods. */
public DigesterLoader setSchema( Schema schema ) { factory.setSchema( schema ); return this; }

Register the specified DTD URL for the specified public identifier. This must be called before the first call to parse().

Digester contains an internal EntityResolver implementation. This maps PUBLICID'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 classloader) for DTDs. This allows the performance advantage of using a local version without having to ensure every SYSTEM URI on every processed xml document is local. This implementation provides only basic functionality. If more sophisticated features are required, using setEntityResolver(EntityResolver) to set a custom resolver is recommended.

Note: This method will have no effect when a custom EntityResolver has been set. (Setting a custom EntityResolver overrides the internal implementation.)

Params:
  • publicId – Public identifier of the DTD to be resolved
  • entityURL – The URL to use for reading this DTD
Returns:This loader instance, useful to chain methods.
/** * <p>Register the specified DTD URL for the specified public identifier. * 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 * (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 * 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.) * </p> * @param publicId Public identifier of the DTD to be resolved * @param entityURL The URL to use for reading this DTD * @return This loader instance, useful to chain methods. */
public DigesterLoader register( String publicId, URL entityURL ) { entityValidator.put( publicId, entityURL ); return this; }

Convenience method that registers the string version of an entity URL instead of a URL version.

Params:
  • publicId – Public identifier of the entity to be resolved
  • entityURL – The URL to use for reading this entity
Returns:This loader instance, useful to chain methods.
/** * <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 * @return This loader instance, useful to chain methods. */
public DigesterLoader register( String publicId, String entityURL ) { try { return register( publicId, new URL( entityURL ) ); } catch ( MalformedURLException e ) { throw new IllegalArgumentException( "Malformed URL '" + entityURL + "' : " + e.getMessage() ); } }
Return the set of DTD URL registrations, keyed by public identifier.
Returns:the set of DTD URL registrations.
/** * Return the set of DTD URL registrations, keyed by public identifier. * * @return the set of DTD URL registrations. */
public Map<String, URL> getRegistrations() { return Collections.unmodifiableMap( this.entityValidator ); }
Set the EntityResolver used by SAX when resolving public id and system id. This must be called before the first call to parse().
Params:
  • entityResolver – a class that implement the EntityResolver interface.
Returns:This loader instance, useful to chain 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. * @return This loader instance, useful to chain methods. */
public DigesterLoader setEntityResolver( EntityResolver entityResolver ) { this.entityResolver = entityResolver; return this; }
Sets the Object which will receive callbacks for every pop/push action on the default stack or named stacks.
Params:
  • stackAction – the Object which will receive callbacks for every pop/push action on the default stack or named stacks.
Returns:This loader instance, useful to chain methods.
/** * Sets the Object which will receive callbacks for every pop/push action on the default stack or named stacks. * * @param stackAction the Object which will receive callbacks for every pop/push action on the default stack * or named stacks. * @return This loader instance, useful to chain methods. */
public DigesterLoader setStackAction( StackAction stackAction ) { this.stackAction = stackAction; return this; }
Returns the executor service used to run asynchronous parse method.
Returns:the executor service used to run asynchronous parse method
Since:3.1
/** * 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.
Params:
  • executorService – the executor service to run asynchronous parse method
Returns:This loader instance, useful to chain methods.
Since:3.1
/** * 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; }
Return the error handler for this Digester.
Returns:the error handler for this Digester.
Since:3.2
/** * Return the error handler for this Digester. * * @return the error handler for this Digester. * @since 3.2 */
public ErrorHandler getErrorHandler() { return ( this.errorHandler ); }
Set the error handler for this Digester.
Params:
  • errorHandler – The new error handler
Returns:This loader instance, useful to chain methods.
Since:3.2
/** * Set the error handler for this Digester. * * @param errorHandler The new error handler * @return This loader instance, useful to chain methods. * @since 3.2 */
public DigesterLoader setErrorHandler( ErrorHandler errorHandler ) { this.errorHandler = errorHandler; return this; }
Gets the document locator associated with our parser.
Returns:the Locator supplied by the document parser
Since:3.2
/** * Gets the document locator associated with our parser. * * @return the Locator supplied by the document parser * @since 3.2 */
public Locator getDocumentLocator() { return locator; }
Sets the document locator associated with our parser.
Params:
  • locator – the document locator associated with our parser.
Returns:This loader instance, useful to chain methods.
Since:3.2
/** * Sets the document locator associated with our parser. * * @param locator the document locator associated with our parser. * @return This loader instance, useful to chain methods. * @since 3.2 */
public DigesterLoader setDocumentLocator( Locator locator ) { this.locator = locator; return this; }
Creates a new Digester instance that relies on the default Rules implementation.
Returns:a new Digester instance
/** * Creates a new {@link Digester} instance that relies on the default {@link Rules} implementation. * * @return a new {@link Digester} instance */
public Digester newDigester() { return this.newDigester( new RulesBase() ); }
Creates a new Digester instance that relies on the custom user define Rules implementation
Params:
  • rules – The custom user define Rules implementation
Returns:a new Digester instance
/** * Creates a new {@link Digester} instance that relies on the custom user define {@link Rules} implementation * * @param rules The custom user define {@link Rules} implementation * @return a new {@link Digester} instance */
public Digester newDigester( Rules rules ) { try { return this.newDigester( this.factory.newSAXParser(), rules ); } catch ( ParserConfigurationException e ) { throw new DigesterLoadingException( "SAX Parser misconfigured", e ); } catch ( SAXException e ) { throw new DigesterLoadingException( "An error occurred while initializing the SAX Parser", e ); } }
Creates a new Digester instance that relies on the given SAXParser and the default Rules implementation.
Params:
  • parser – the user defined SAXParser
Returns:a new Digester instance
/** * Creates a new {@link Digester} instance that relies on the given {@code SAXParser} * and the default {@link Rules} implementation. * * @param parser the user defined {@code SAXParser} * @return a new {@link Digester} instance */
public Digester newDigester( SAXParser parser ) { return newDigester( parser, new RulesBase() ); }
Creates a new Digester instance that relies on the given SAXParser and custom user define Rules implementation.
Params:
  • parser – The user defined SAXParser
  • rules – The custom user define Rules implementation
Returns:a new Digester instance
/** * Creates a new {@link Digester} instance that relies on the given {@code SAXParser} * and custom user define {@link Rules} implementation. * * @param parser The user defined {@code SAXParser} * @param rules The custom user define {@link Rules} implementation * @return a new {@link Digester} instance */
public Digester newDigester( SAXParser parser, Rules rules ) { if ( parser == null ) { throw new DigesterLoadingException( "SAXParser must be not null" ); } try { return this.newDigester( parser.getXMLReader(), rules ); } catch ( SAXException e ) { throw new DigesterLoadingException( "An error occurred while creating the XML Reader", e ); } }
Creates a new XMLReader instance that relies on the given XMLReader and the default Rules implementation.
Params:
  • reader – The user defined XMLReader
Returns:a new Digester instance
/** * Creates a new {@link XMLReader} instance that relies on the given {@code XMLReader} * and the default {@link Rules} implementation. * * @param reader The user defined {@code XMLReader} * @return a new {@link Digester} instance */
public Digester newDigester( XMLReader reader ) { return this.newDigester( reader, new RulesBase() ); }
Creates a new XMLReader instance that relies on the given XMLReader and custom user define Rules implementation.
Params:
  • reader – The user defined XMLReader
  • rules – The custom user define Rules implementation
Returns:a new Digester instance
/** * Creates a new {@link XMLReader} instance that relies on the given {@code XMLReader} * and custom user define {@link Rules} implementation. * * @param reader The user defined {@code XMLReader} * @param rules The custom user define {@link Rules} implementation * @return a new {@link Digester} instance */
public Digester newDigester( XMLReader reader, Rules rules ) { if ( reader == null ) { throw new DigesterLoadingException( "XMLReader must be not null" ); } if ( rules == null ) { throw new DigesterLoadingException( "Impossible to create a new Digester with null Rules" ); } Digester digester = new Digester( reader ); // the ClassLoader adapter is no needed anymore digester.setClassLoader( classLoader.getAdaptedClassLoader() ); digester.setRules( rules ); digester.setSubstitutor( substitutor ); digester.registerAll( entityValidator ); digester.setEntityResolver( entityResolver ); digester.setStackAction( stackAction ); digester.setNamespaceAware( isNamespaceAware() ); digester.setExecutorService( executorService ); digester.setErrorHandler( errorHandler ); digester.setDocumentLocator( locator ); addRules( digester ); return digester; }
Add rules to an already created Digester instance, analyzing the digester annotations in the target class.
Params:
  • digester – the Digester instance reference.
/** * Add rules to an already created Digester instance, analyzing the digester annotations in the target class. * * @param digester the Digester instance reference. */
public void addRules( final Digester digester ) { RuleSet ruleSet = createRuleSet(); ruleSet.addRuleInstances( digester ); }
Creates a new RuleSet instance based on the current configuration.
Returns:A new RuleSet instance based on the current configuration.
/** * Creates a new {@link RuleSet} instance based on the current configuration. * * @return A new {@link RuleSet} instance based on the current configuration. */
public RuleSet createRuleSet() { if ( classLoader != rulesBinder.getContextClassLoader() ) { rulesBinder.initialize( classLoader ); for ( RulesModule rulesModule : rulesModules ) { rulesModule.configure( rulesBinder ); } } if ( rulesBinder.hasError() ) { Formatter fmt = new Formatter().format( HEADING ); int index = 1; for ( ErrorMessage errorMessage : rulesBinder.getErrors() ) { fmt.format( "%s) %s%n", index++, errorMessage.getMessage() ); Throwable cause = errorMessage.getCause(); if ( cause != null ) { StringWriter writer = new StringWriter(); cause.printStackTrace( new PrintWriter( writer ) ); fmt.format( "Caused by: %s", writer.getBuffer() ); } fmt.format( "%n" ); } if ( rulesBinder.errorsSize() == 1 ) { fmt.format( "1 error" ); } else { fmt.format( "%s errors", rulesBinder.errorsSize() ); } throw new DigesterLoadingException( fmt.toString() ); } return rulesBinder.getFromBinderRuleSet(); } }