();
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)
*/
@Override
public void notationDecl(String name, String publicId, String systemId) {
if (saxLog.isDebugEnabled()) {
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
*/
@Override
public void unparsedEntityDecl(String name, String publicId,
String systemId, String notation) {
if (saxLog.isDebugEnabled()) {
saxLog.debug("unparsedEntityDecl(" + name + "," + publicId + "," +
systemId + "," + notation + ")");
}
}
// ----------------------------------------------- EntityResolver Methods
/**
* Set the EntityResolver
used by SAX when resolving
* public id and system id.
* This must be called before the first call to parse()
.
* @param entityResolver a class that implement the EntityResolver
interface.
*/
public void setEntityResolver(EntityResolver entityResolver){
this.entityResolver = entityResolver;
}
/**
* Return the Entity Resolver used by the SAX parser.
* @return Return the Entity Resolver used by the SAX parser.
*/
public EntityResolver getEntityResolver(){
return entityResolver;
}
@Override
public InputSource resolveEntity(String name, String publicId,
String baseURI, String systemId) throws SAXException, IOException {
if (saxLog.isDebugEnabled()) {
saxLog.debug("resolveEntity('" + publicId + "', '" + systemId +
"', '" + baseURI + "')");
}
// Has this system identifier been registered?
String entityURL = null;
if (publicId != null) {
entityURL = entityValidator.get(publicId);
}
if (entityURL == null) {
if (systemId == null) {
// cannot resolve
if (log.isDebugEnabled()) {
log.debug(" Cannot resolve entity: '" + publicId + "'");
}
return (null);
} else {
// try to resolve using system ID
if (log.isDebugEnabled()) {
log.debug(" Trying to resolve using system ID '" +
systemId + "'");
}
entityURL = systemId;
// resolve systemId against baseURI if it is not absolute
if (baseURI != null) {
try {
URI uri = new URI(systemId);
if (!uri.isAbsolute()) {
entityURL = new URI(baseURI).resolve(uri).toString();
}
} catch (URISyntaxException e) {
if (log.isDebugEnabled()) {
log.debug("Invalid URI '" + baseURI + "' or '" +
systemId + "'");
}
}
}
}
}
// Return an input source to our alternative URL
if (log.isDebugEnabled()) {
log.debug(" Resolving to alternate DTD '" + entityURL + "'");
}
try {
return (new InputSource(entityURL));
} catch (Exception e) {
throw createSAXException(e);
}
}
// ----------------------------------------------- LexicalHandler Methods
@Override
public void startDTD(String name, String publicId, String systemId)
throws SAXException {
setPublicId(publicId);
}
// ------------------------------------------------- ErrorHandler Methods
/**
* Forward notification of a parsing error to the application supplied
* error handler (if any).
*
* @param exception The error information
*
* @exception SAXException if a parsing exception occurs
*/
@Override
public void error(SAXParseException exception) throws SAXException {
log.error("Parse Error at line " + exception.getLineNumber() +
" column " + exception.getColumnNumber() + ": " +
exception.getMessage(), exception);
if (errorHandler != null) {
errorHandler.error(exception);
}
}
/**
* Forward notification of a fatal parsing error to the application
* supplied error handler (if any).
*
* @param exception The fatal error information
*
* @exception SAXException if a parsing exception occurs
*/
@Override
public void fatalError(SAXParseException exception) throws SAXException {
log.error("Parse Fatal Error at line " + exception.getLineNumber() +
" column " + exception.getColumnNumber() + ": " +
exception.getMessage(), exception);
if (errorHandler != null) {
errorHandler.fatalError(exception);
}
}
/**
* Forward notification of a parse warning to the application supplied
* error handler (if any).
*
* @param exception The warning information
*
* @exception SAXException if a parsing exception occurs
*/
@Override
public void warning(SAXParseException exception) throws SAXException {
if (errorHandler != null) {
log.warn("Parse Warning Error at line " + exception.getLineNumber() +
" column " + exception.getColumnNumber() + ": " +
exception.getMessage(), exception);
errorHandler.warning(exception);
}
}
// ------------------------------------------------------- Public Methods
/**
* Parse the content of the specified file using this Digester. Returns
* the root element from the object stack (if any).
*
* @param file File containing the XML data to be parsed
*
* @exception IOException if an input/output error occurs
* @exception SAXException if a parsing exception occurs
*/
public Object parse(File file) throws IOException, SAXException {
configure();
InputSource input = new InputSource(new FileInputStream(file));
input.setSystemId("file://" + file.getAbsolutePath());
getXMLReader().parse(input);
return (root);
}
/**
* Parse the content of the specified input source using this Digester.
* Returns the root element from the object stack (if any).
*
* @param input Input source containing the XML data to be parsed
*
* @exception IOException if an input/output error occurs
* @exception SAXException if a parsing exception occurs
*/
public Object parse(InputSource input) throws IOException, SAXException {
configure();
getXMLReader().parse(input);
return (root);
}
/**
* Parse the content of the specified input stream using this Digester.
* Returns the root element from the object stack (if any).
*
* @param input Input stream containing the XML data to be parsed
*
* @exception IOException if an input/output error occurs
* @exception SAXException if a parsing exception occurs
*/
public Object parse(InputStream input) throws IOException, SAXException {
configure();
InputSource is = new InputSource(input);
getXMLReader().parse(is);
return (root);
}
/**
* Parse the content of the specified reader using this Digester.
* Returns the root element from the object stack (if any).
*
* @param reader Reader containing the XML data to be parsed
*
* @exception IOException if an input/output error occurs
* @exception SAXException if a parsing exception occurs
*/
public Object parse(Reader reader) throws IOException, SAXException {
configure();
InputSource is = new InputSource(reader);
getXMLReader().parse(is);
return (root);
}
/**
* Parse the content of the specified URI using this Digester.
* Returns the root element from the object stack (if any).
*
* @param uri URI containing the XML data to be parsed
*
* @exception IOException if an input/output error occurs
* @exception SAXException if a parsing exception occurs
*/
public Object parse(String uri) throws IOException, SAXException {
configure();
InputSource is = new InputSource(uri);
getXMLReader().parse(is);
return (root);
}
/**
* 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 {@link #setEntityResolver} 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.)
*
* @param publicId Public identifier of the DTD to be resolved
* @param entityURL The URL to use for reading this DTD
*/
public void register(String publicId, String entityURL) {
if (log.isDebugEnabled()) {
log.debug("register('" + publicId + "', '" + entityURL + "'");
}
entityValidator.put(publicId, entityURL);
}
// --------------------------------------------------------- Rule Methods
/**
* Register a new Rule matching the specified pattern.
* This method sets the Digester
property on the rule.
*
* @param pattern Element matching pattern
* @param rule Rule to be registered
*/
public void addRule(String pattern, Rule rule) {
rule.setDigester(this);
getRules().add(pattern, rule);
}
/**
* Register a set of Rule instances defined in a RuleSet.
*
* @param ruleSet The RuleSet instance to configure from
*/
public void addRuleSet(RuleSet ruleSet) {
String oldNamespaceURI = getRuleNamespaceURI();
String newNamespaceURI = ruleSet.getNamespaceURI();
if (log.isDebugEnabled()) {
if (newNamespaceURI == null) {
log.debug("addRuleSet() with no namespace URI");
} else {
log.debug("addRuleSet() with namespace URI " + newNamespaceURI);
}
}
setRuleNamespaceURI(newNamespaceURI);
ruleSet.addRuleInstances(this);
setRuleNamespaceURI(oldNamespaceURI);
}
/**
* 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
*/
public void addCallMethod(String pattern, String methodName) {
addRule(
pattern,
new CallMethodRule(methodName));
}
/**
* 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)
* @see CallMethodRule
*/
public void addCallMethod(String pattern, String methodName,
int paramCount) {
addRule(pattern,
new CallMethodRule(methodName, paramCount));
}
/**
* Add an "call method" rule for the specified parameters.
* If paramCount
is set to zero the rule will use
* the body of the matched element as the single argument of the
* method, unless paramTypes
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)
* @param paramTypes Set of Java class names for the types
* of the expected parameters
* (if you wish to use a primitive type, specify the corresponding
* Java wrapper class instead, such as java.lang.Boolean
* for a boolean
parameter)
* @see CallMethodRule
*/
public void addCallMethod(String pattern, String methodName,
int paramCount, String paramTypes[]) {
addRule(pattern,
new CallMethodRule(
methodName,
paramCount,
paramTypes));
}
/**
* Add an "call method" rule for the specified parameters.
* If paramCount
is set to zero the rule will use
* the body of the matched element as the single argument of the
* method, unless paramTypes
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)
* @param paramTypes The Java class names of the arguments
* (if you wish to use a primitive type, specify the corresponding
* Java wrapper class instead, such as java.lang.Boolean
* for a boolean
parameter)
* @see CallMethodRule
*/
public void addCallMethod(String pattern, String methodName,
int paramCount, Class> paramTypes[]) {
addRule(pattern,
new CallMethodRule(
methodName,
paramCount,
paramTypes));
}
/**
* 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
*/
public void addCallParam(String pattern, int paramIndex) {
addRule(pattern,
new CallParamRule(paramIndex));
}
/**
* 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
* @see CallParamRule
*/
public void addCallParam(String pattern, int paramIndex,
String attributeName) {
addRule(pattern,
new CallParamRule(paramIndex, attributeName));
}
/**
* Add a "call parameter" rule.
* This will either take a parameter from the stack
* or from the current element body text.
*
* @param paramIndex The zero-relative parameter number
* @param fromStack Should the call parameter be taken from the top of the stack?
* @see CallParamRule
*/
public void addCallParam(String pattern, int paramIndex, boolean fromStack) {
addRule(pattern,
new CallParamRule(paramIndex, fromStack));
}
/**
* Add a "call parameter" rule that sets a parameter from the stack.
* This takes a parameter from the given position on the stack.
*
* @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 stack, 1 the next element down and so on
* @see CallMethodRule
*/
public void addCallParam(String pattern, int paramIndex, int stackIndex) {
addRule(pattern,
new CallParamRule(paramIndex, stackIndex));
}
/**
* Add a "call parameter" rule that sets a parameter from the current
* Digester
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
*/
public void addCallParamPath(String pattern,int paramIndex) {
addRule(pattern, new PathCallParamRule(paramIndex));
}
/**
* Add a "call parameter" rule that sets a parameter from a
* caller-provided object. This can be used to pass constants such as
* strings to methods; it can also be used to pass mutable objects,
* providing ways for objects to do things like "register" themselves
* with some shared object.
*
* 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 paramIndex The zero-relative parameter number
* @param paramObj Any arbitrary object to be passed to the target
* method.
* @see CallMethodRule
*
* @since 1.6
*/
public void addObjectParam(String pattern, int paramIndex,
Object paramObj) {
addRule(pattern,
new ObjectParamRule(paramIndex, paramObj));
}
/**
* 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
*/
public void addFactoryCreate(String pattern, String className) {
addFactoryCreate(pattern, className, false);
}
/**
* 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
*/
public void addFactoryCreate(String pattern, Class> clazz) {
addFactoryCreate(pattern, clazz, false);
}
/**
* 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 className
* @see FactoryCreateRule
*/
public void addFactoryCreate(String pattern, String className,
String attributeName) {
addFactoryCreate(pattern, className, attributeName, false);
}
/**
* 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 className
* @see FactoryCreateRule
*/
public void addFactoryCreate(String pattern, Class> clazz,
String attributeName) {
addFactoryCreate(pattern, clazz, attributeName, false);
}
/**
* 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
*/
public void addFactoryCreate(String pattern,
ObjectCreationFactory creationFactory) {
addFactoryCreate(pattern, creationFactory, false);
}
/**
* 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 true
any exceptions thrown during
* object creation will be ignored.
* @see FactoryCreateRule
*/
public void addFactoryCreate(
String pattern,
String className,
boolean ignoreCreateExceptions) {
addRule(
pattern,
new FactoryCreateRule(className, ignoreCreateExceptions));
}
/**
* 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 true
any exceptions thrown during
* object creation will be ignored.
* @see FactoryCreateRule
*/
public void addFactoryCreate(
String pattern,
Class> clazz,
boolean ignoreCreateExceptions) {
addRule(
pattern,
new FactoryCreateRule(clazz, ignoreCreateExceptions));
}
/**
* 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 className
* @param ignoreCreateExceptions when true
any exceptions thrown during
* object creation will be ignored.
* @see FactoryCreateRule
*/
public void addFactoryCreate(
String pattern,
String className,
String attributeName,
boolean ignoreCreateExceptions) {
addRule(
pattern,
new FactoryCreateRule(className, attributeName, ignoreCreateExceptions));
}
/**
* 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 className
* @param ignoreCreateExceptions when true
any exceptions thrown during
* object creation will be ignored.
* @see FactoryCreateRule
*/
public void addFactoryCreate(
String pattern,
Class> clazz,
String attributeName,
boolean ignoreCreateExceptions) {
addRule(
pattern,
new FactoryCreateRule(clazz, attributeName, ignoreCreateExceptions));
}
/**
* 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 true
any exceptions thrown during
* object creation will be ignored.
* @see FactoryCreateRule
*/
public void addFactoryCreate(String pattern,
ObjectCreationFactory creationFactory,
boolean ignoreCreateExceptions) {
creationFactory.setDigester(this);
addRule(pattern,
new FactoryCreateRule(creationFactory, ignoreCreateExceptions));
}
/**
* Add an "object create" rule for the specified parameters.
*
* @param pattern Element matching pattern
* @param className Java class name to be created
* @see ObjectCreateRule
*/
public void addObjectCreate(String pattern, String className) {
addRule(pattern,
new ObjectCreateRule(className));
}
/**
* Add an "object create" rule for the specified parameters.
*
* @param pattern Element matching pattern
* @param clazz Java class to be created
* @see ObjectCreateRule
*/
public void addObjectCreate(String pattern, Class> clazz) {
addRule(pattern,
new ObjectCreateRule(clazz));
}
/**
* 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
* @see ObjectCreateRule
*/
public void addObjectCreate(String pattern, String className,
String attributeName) {
addRule(pattern,
new ObjectCreateRule(className, attributeName));
}
/**
* 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
* @see ObjectCreateRule
*/
public void addObjectCreate(String pattern,
String attributeName,
Class> clazz) {
addRule(pattern,
new ObjectCreateRule(attributeName, clazz));
}
/**
* 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
*/
public void addSetNext(String pattern, String methodName) {
addRule(pattern,
new SetNextRule(methodName));
}
/**
* 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 corresponding
* Java wrapper class instead, such as java.lang.Boolean
* for a boolean
parameter)
* @see SetNextRule
*/
public void addSetNext(String pattern, String methodName,
String paramType) {
addRule(pattern,
new SetNextRule(methodName, paramType));
}
/**
* Add {@link SetRootRule} with the specified parameters.
*
* @param pattern Element matching pattern
* @param methodName Method name to call on the root object
* @see SetRootRule
*/
public void addSetRoot(String pattern, String methodName) {
addRule(pattern,
new SetRootRule(methodName));
}
/**
* 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
* @see SetRootRule
*/
public void addSetRoot(String pattern, String methodName,
String paramType) {
addRule(pattern,
new SetRootRule(methodName, paramType));
}
/**
* Add a "set properties" rule for the specified parameters.
*
* @param pattern Element matching pattern
* @see SetPropertiesRule
*/
public void addSetProperties(String pattern) {
addRule(pattern,
new SetPropertiesRule());
}
/**
* 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
* @see SetPropertiesRule
*/
public void addSetProperties(
String pattern,
String attributeName,
String propertyName) {
addRule(pattern,
new SetPropertiesRule(attributeName, propertyName));
}
/**
* 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
* @see SetPropertiesRule
*/
public void addSetProperties(
String pattern,
String [] attributeNames,
String [] propertyNames) {
addRule(pattern,
new SetPropertiesRule(attributeNames, propertyNames));
}
/**
* 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
* @see SetPropertyRule
*/
public void addSetProperty(String pattern, String name, String value) {
addRule(pattern,
new SetPropertyRule(name, value));
}
/**
* 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
*/
public void addSetTop(String pattern, String methodName) {
addRule(pattern,
new SetTopRule(methodName));
}
/**
* 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 corresponding
* Java wrapper class instead, such as java.lang.Boolean
* for a boolean
parameter)
* @see SetTopRule
*/
public void addSetTop(String pattern, String methodName,
String paramType) {
addRule(pattern,
new SetTopRule(methodName, paramType));
}
// --------------------------------------------------- Object Stack Methods
/**
* Clear the current contents of the object stack.
*
* Calling this method might allow another document of the same type
* to be correctly parsed. However this method was not intended for this
* purpose. In general, a separate Digester object should be created for
* each document to be parsed.
*/
public void clear() {
match = "";
bodyTexts.clear();
params.clear();
publicId = null;
stack.clear();
log = null;
saxLog = null;
configured = false;
}
public void reset() {
root = null;
setErrorHandler(null);
clear();
}
/**
* Return the top object on the stack without removing it. If there are
* no objects on the stack, return null
.
*/
public Object peek() {
try {
return (stack.peek());
} catch (EmptyStackException e) {
log.warn("Empty stack (returning null)");
return (null);
}
}
/**
* 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 null
.
*
* @param n Index of the desired element, where 0 is the top of the stack,
* 1 is the next element down, and so on.
*/
public Object peek(int n) {
try {
return (stack.peek(n));
} catch (EmptyStackException e) {
log.warn("Empty stack (returning null)");
return (null);
}
}
/**
* Pop the top object off of the stack, and return it. If there are
* no objects on the stack, return null
.
*/
public Object pop() {
try {
return (stack.pop());
} catch (EmptyStackException e) {
log.warn("Empty stack (returning null)");
return (null);
}
}
/**
* Push a new object onto the top of the object stack.
*
* @param object The new object
*/
public void push(Object object) {
if (stack.size() == 0) {
root = object;
}
stack.push(object);
}
/**
* 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 stackName the name of the stack onto which the object should be pushed
* @param value the Object to be pushed onto the named stack.
*
* @since 1.6
*/
public void push(String stackName, Object value) {
ArrayStack namedStack = stacksByName.get(stackName);
if (namedStack == null) {
namedStack = new ArrayStack();
stacksByName.put(stackName, namedStack);
}
namedStack.push(value);
}
/**
* Pops (gets and removes) the top object from the stack with the given name.
*
* Note: a stack is considered empty
* if no objects have been pushed onto it yet.
*
* @param stackName the name of the stack from which the top value is to be popped
* @return the top Object
on the stack or or null if the stack is either
* empty or has not been created yet
* @throws EmptyStackException if the named stack is empty
*
* @since 1.6
*/
public Object pop(String stackName) {
Object result = null;
ArrayStack namedStack = stacksByName.get(stackName);
if (namedStack == null) {
if (log.isDebugEnabled()) {
log.debug("Stack '" + stackName + "' is empty");
}
throw new EmptyStackException();
} else {
result = namedStack.pop();
}
return result;
}
/**
* Gets the top object from the stack with the given name.
* This method does not remove the object from the stack.
*
* Note: a stack is considered empty
* if no objects have been pushed onto it yet.
*
* @param stackName the name of the stack to be peeked
* @return the top Object
on the stack or null if the stack is either
* empty or has not been created yet
* @throws EmptyStackException if the named stack is empty
*
* @since 1.6
*/
public Object peek(String stackName) {
Object result = null;
ArrayStack namedStack = stacksByName.get(stackName);
if (namedStack == null ) {
if (log.isDebugEnabled()) {
log.debug("Stack '" + stackName + "' is empty");
}
throw new EmptyStackException();
} else {
result = namedStack.peek();
}
return result;
}
/**
* Is the stack with the given name empty?
* Note: a stack is considered empty
* if no objects have been pushed onto it yet.
* @param stackName the name of the stack whose emptiness
* should be evaluated
* @return true if the given stack if empty
*
* @since 1.6
*/
public boolean isEmpty(String stackName) {
boolean result = true;
ArrayStack namedStack = stacksByName.get(stackName);
if (namedStack != null ) {
result = namedStack.isEmpty();
}
return result;
}
/**
* When the Digester is being used as a SAXContentHandler,
* this method allows you to access the root object that has been
* created after parsing.
*
* @return the root object that has been created after parsing
* or null if the digester has not parsed any XML yet.
*/
public Object getRoot() {
return root;
}
// ------------------------------------------------ Parameter Stack Methods
// ------------------------------------------------------ Protected Methods
/**
*
* Provide a hook for lazy configuration of this Digester
* instance. The default implementation does nothing, but subclasses
* can override as needed.
*
*
*
* Note This method may be called more than once.
* Once only initialization code should be placed in {@link #initialize}
* or the code should take responsibility by checking and setting the
* {@link #configured} flag.
*
*/
protected void configure() {
// Do not configure more than once
if (configured) {
return;
}
log = LogFactory.getLog("org.apache.tomcat.util.digester.Digester");
saxLog = LogFactory.getLog("org.apache.tomcat.util.digester.Digester.sax");
// Perform lazy configuration as needed
initialize(); // call hook method for subclasses that want to be initialized once only
// Nothing else required by default
// Set the configuration flag to avoid repeating
configured = true;
}
/**
*
* Provides a hook for lazy initialization of this Digester
* instance.
* The default implementation does nothing, but subclasses
* can override as needed.
* Digester (by default) only calls this method once.
*
*
*
* Note This method will be called by {@link #configure}
* only when the {@link #configured} flag is false.
* Subclasses that override configure
or who set configured
* may find that this method may be called more than once.
*
*
* @since 1.6
*/
protected void initialize() {
// Perform lazy initialization as needed
// Nothing required by default
}
// -------------------------------------------------------- Package Methods
/**
* Return the set of DTD URL registrations, keyed by public identifier.
*/
Map getRegistrations() {
return (entityValidator);
}
/**
* Return the top object on the parameters stack without removing it. If there are
* no objects on the stack, return null
.
*
* The parameters stack is used to store CallMethodRule
parameters.
* See {@link #params}.
*/
public Object peekParams() {
try {
return (params.peek());
} catch (EmptyStackException e) {
log.warn("Empty stack (returning null)");
return (null);
}
}
/**
* Return the n'th object down the parameters stack, where 0 is the top element
* and [getCount()-1] is the bottom element. If the specified index
* is out of range, return null
.
*
* The parameters stack is used to store CallMethodRule
parameters.
* See {@link #params}.
*
* @param n Index of the desired element, where 0 is the top of the stack,
* 1 is the next element down, and so on.
*/
public Object peekParams(int n) {
try {
return (params.peek(n));
} catch (EmptyStackException e) {
log.warn("Empty stack (returning null)");
return (null);
}
}
/**
* Pop the top object off of the parameters stack, and return it. If there are
* no objects on the stack, return null
.
*
* The parameters stack is used to store CallMethodRule
parameters.
* See {@link #params}.
*/
public Object popParams() {
try {
if (log.isTraceEnabled()) {
log.trace("Popping params");
}
return (params.pop());
} catch (EmptyStackException e) {
log.warn("Empty stack (returning null)");
return (null);
}
}
/**
* Push a new object onto the top of the parameters stack.
*
* The parameters stack is used to store CallMethodRule
parameters.
* See {@link #params}.
*
* @param object The new object
*/
public void pushParams(Object object) {
if (log.isTraceEnabled()) {
log.trace("Pushing params");
}
params.push(object);
}
/**
* Create a SAX exception which also understands about the location in
* the digester file where the exception occurs
*
* @return the new exception
*/
public SAXException createSAXException(String message, Exception e) {
if ((e != null) &&
(e instanceof InvocationTargetException)) {
Throwable t = e.getCause();
if (t instanceof ThreadDeath) {
throw (ThreadDeath) t;
}
if (t instanceof VirtualMachineError) {
throw (VirtualMachineError) t;
}
if (t instanceof Exception) {
e = (Exception) t;
}
}
if (locator != null) {
String error = "Error at (" + locator.getLineNumber() + ", " +
locator.getColumnNumber() + ") : " + message;
if (e != null) {
return new SAXParseException(error, locator, e);
} else {
return new SAXParseException(error, locator);
}
}
log.error("No Locator!");
if (e != null) {
return new SAXException(message, e);
} else {
return new SAXException(message);
}
}
/**
* Create a SAX exception which also understands about the location in
* the digester file where the exception occurs
*
* @return the new exception
*/
public SAXException createSAXException(Exception e) {
if (e instanceof InvocationTargetException) {
Throwable t = e.getCause();
if (t instanceof ThreadDeath) {
throw (ThreadDeath) t;
}
if (t instanceof VirtualMachineError) {
throw (VirtualMachineError) t;
}
if (t instanceof Exception) {
e = (Exception) t;
}
}
return createSAXException(e.getMessage(), e);
}
/**
* Create a SAX exception which also understands about the location in
* the digester file where the exception occurs
*
* @return the new exception
*/
public SAXException createSAXException(String message) {
return createSAXException(message, null);
}
// ------------------------------------------------------- Private Methods
/**
* Returns an attributes list which contains all the attributes
* passed in, with any text of form "${xxx}" in an attribute value
* replaced by the appropriate value from the system property.
*/
private Attributes updateAttributes(Attributes list) {
if (list.getLength() == 0) {
return list;
}
AttributesImpl newAttrs = new AttributesImpl(list);
int nAttributes = newAttrs.getLength();
for (int i = 0; i < nAttributes; ++i) {
String value = newAttrs.getValue(i);
try {
String newValue =
IntrospectionUtils.replaceProperties(value, null, source);
if (value != newValue) {
newAttrs.setValue(i, newValue);
}
}
catch (Exception e) {
// ignore - let the attribute have its original value
}
}
return newAttrs;
}
/**
* Return a new StringBuilder containing the same contents as the
* input buffer, except that data of form ${varname} have been
* replaced by the value of that var as defined in the system property.
*/
private StringBuilder updateBodyText(StringBuilder bodyText) {
String in = bodyText.toString();
String out;
try {
out = IntrospectionUtils.replaceProperties(in, null, source);
} catch(Exception e) {
return bodyText; // return unchanged data
}
if (out == in) {
// No substitutions required. Don't waste memory creating
// a new buffer
return bodyText;
} else {
return new StringBuilder(out);
}
}
}