Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/AbstractObjectCreationFactory.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/AbstractObjectCreationFactory.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/AbstractObjectCreationFactory.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,79 @@ +/* $Id: AbstractObjectCreationFactory.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester; + + +import org.xml.sax.Attributes; + + +/** + *

Abstract base class for ObjectCreationFactory + * implementations.

+ */ +abstract public class AbstractObjectCreationFactory implements ObjectCreationFactory { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The associated Digester instance that was set up by + * {@link FactoryCreateRule} upon initialization. + */ + protected Digester digester = null; + + + // --------------------------------------------------------- Public Methods + + + /** + *

Factory method called by {@link FactoryCreateRule} to supply an + * object based on the element's attributes. + * + * @param attributes the element's attributes + * + * @throws Exception any exception thrown will be propagated upwards + */ + public abstract Object createObject(Attributes attributes) throws Exception; + + + /** + *

Returns the {@link Digester} that was set by the + * {@link FactoryCreateRule} upon initialization. + */ + public Digester getDigester() { + + return (this.digester); + + } + + + /** + *

Set the {@link Digester} to allow the implementation to do logging, + * classloading based on the digester's classloader, etc. + * + * @param digester parent Digester object + */ + public void setDigester(Digester digester) { + + this.digester = digester; + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/AbstractRulesImpl.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/AbstractRulesImpl.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/AbstractRulesImpl.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,168 @@ +/* $Id: AbstractRulesImpl.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import java.util.List; + + +/** + *

AbstractRuleImpl provides basic services for Rules implementations. + * Extending this class should make it easier to create a Rules implementation.

+ * + *

AbstractRuleImpl manages the Digester + * and namespaceUri properties. + * If the subclass overrides {@link #registerRule} (rather than {@link #add}), + * then the Digester and namespaceURI of the Rule + * will be set correctly before it is passed to registerRule. + * The subclass can then perform whatever it needs to do to register the rule.

+ * + * @since 1.5 + */ + +abstract public class AbstractRulesImpl implements Rules { + + // ------------------------------------------------------------- Fields + + /** Digester using this Rules implementation */ + private Digester digester; + /** Namespace uri to assoicate with subsequent Rule's */ + private String namespaceURI; + + // ------------------------------------------------------------- Properties + + /** + * Return the Digester instance with which this Rules instance is + * associated. + */ + public Digester getDigester() { + return digester; + } + + /** + * Set the Digester instance with which this Rules instance is associated. + * + * @param digester The newly associated Digester instance + */ + public void setDigester(Digester digester) { + this.digester = digester; + } + + /** + * Return the namespace URI that will be applied to all subsequently + * added Rule objects. + */ + public String getNamespaceURI() { + return namespaceURI; + } + + /** + * Set the namespace URI that will be applied to all subsequently + * added Rule objects. + * + * @param namespaceURI Namespace URI that must match on all + * subsequently added rules, or null for matching + * regardless of the current namespace URI + */ + public void setNamespaceURI(String namespaceURI) { + this.namespaceURI = namespaceURI; + } + + // --------------------------------------------------------- Public Methods + + /** + * Registers a new Rule instance matching the specified pattern. + * This implementation sets the Digester and the + * namespaceURI on the Rule before calling {@link #registerRule}. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + public void add(String pattern, Rule rule) { + // set up rule + if (this.digester != null) { + rule.setDigester(this.digester); + } + + if (this.namespaceURI != null) { + rule.setNamespaceURI(this.namespaceURI); + } + + registerRule(pattern, rule); + + } + + /** + * Register rule at given pattern. + * The the Digester and namespaceURI properties of the given Rule + * can be assumed to have been set properly before this method is called. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + abstract protected void registerRule(String pattern, Rule rule); + + /** + * Clear all existing Rule instance registrations. + */ + abstract public void clear(); + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param pattern Nesting pattern to be matched + * + * @deprecated Call match(namespaceURI,pattern) instead. + */ + @Deprecated + public List match(String pattern) { + return match(namespaceURI, pattern); + } + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param namespaceURI Namespace URI for which to select matching rules, + * or null to match regardless of namespace URI + * @param pattern Nesting pattern to be matched + */ + abstract public List match(String namespaceURI, String pattern); + + + /** + * Return a List of all registered Rule instances, or a zero-length List + * if there are no registered Rule instances. If more than one Rule + * instance has been registered, they must be returned + * in the order originally registered through the add() + * method. + */ + abstract public List rules(); + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/BeanPropertySetterRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/BeanPropertySetterRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/BeanPropertySetterRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,232 @@ +/* $Id: BeanPropertySetterRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import java.beans.PropertyDescriptor; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.beanutils.DynaBean; +import org.apache.commons.beanutils.DynaProperty; +import org.apache.commons.beanutils.PropertyUtils; + + +/** + *

Rule implements sets a bean property on the top object + * to the body text.

+ * + *

The property set:

+ *
  • can be specified when the rule is created
  • + *
  • or can match the current element when the rule is called.
+ * + *

Using the second method and the {@link ExtendedBaseRules} child match + * pattern, all the child elements can be automatically mapped to properties + * on the parent object.

+ */ + +public class BeanPropertySetterRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + *

Construct rule that sets the given property from the body text.

+ * + * @param digester associated Digester + * @param propertyName name of property to set + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #BeanPropertySetterRule(String propertyName)} instead. + */ + @Deprecated + public BeanPropertySetterRule(Digester digester, String propertyName) { + + this(propertyName); + + } + + /** + *

Construct rule that automatically sets a property from the body text. + * + *

This construct creates a rule that sets the property + * on the top object named the same as the current element. + * + * @param digester associated Digester + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #BeanPropertySetterRule()} instead. + */ + @Deprecated + public BeanPropertySetterRule(Digester digester) { + + this(); + + } + + /** + *

Construct rule that sets the given property from the body text.

+ * + * @param propertyName name of property to set + */ + public BeanPropertySetterRule(String propertyName) { + + this.propertyName = propertyName; + + } + + /** + *

Construct rule that automatically sets a property from the body text. + * + *

This construct creates a rule that sets the property + * on the top object named the same as the current element. + */ + public BeanPropertySetterRule() { + + this((String)null); + + } + + // ----------------------------------------------------- Instance Variables + + + /** + * Set this property on the top object. + */ + protected String propertyName = null; + + + /** + * The body text used to set the property. + */ + protected String bodyText = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the body text of this element. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @param text The text of the body of this element + */ + @Override + public void body(String namespace, String name, String text) + throws Exception { + + // log some debugging information + if (digester.log.isDebugEnabled()) { + digester.log.debug("[BeanPropertySetterRule]{" + + digester.match + "} Called with text '" + text + "'"); + } + + bodyText = text.trim(); + + } + + + /** + * Process the end of this element. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * + * @exception NoSuchMethodException if the bean does not + * have a writeable property of the specified name + */ + @Override + public void end(String namespace, String name) throws Exception { + + String property = propertyName; + + if (property == null) { + // If we don't have a specific property name, + // use the element name. + property = name; + } + + // Get a reference to the top object + Object top = digester.peek(); + + // log some debugging information + if (digester.log.isDebugEnabled()) { + digester.log.debug("[BeanPropertySetterRule]{" + digester.match + + "} Set " + top.getClass().getName() + " property " + + property + " with text " + bodyText); + } + + // Force an exception if the property does not exist + // (BeanUtils.setProperty() silently returns in this case) + if (top instanceof DynaBean) { + DynaProperty desc = + ((DynaBean) top).getDynaClass().getDynaProperty(property); + if (desc == null) { + throw new NoSuchMethodException + ("Bean has no property named " + property); + } + } else /* this is a standard JavaBean */ { + PropertyDescriptor desc = + PropertyUtils.getPropertyDescriptor(top, property); + if (desc == null) { + throw new NoSuchMethodException + ("Bean has no property named " + property); + } + } + + // Set the property (with conversion as necessary) + BeanUtils.setProperty(top, property, bodyText); + + } + + + /** + * Clean up after parsing is complete. + */ + @Override + public void finish() throws Exception { + + bodyText = null; + + } + + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("BeanPropertySetterRule["); + sb.append("propertyName="); + sb.append(propertyName); + sb.append("]"); + return (sb.toString()); + + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/CallMethodRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/CallMethodRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/CallMethodRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,687 @@ +/* $Id: CallMethodRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import org.apache.commons.beanutils.ConvertUtils; +import org.apache.commons.beanutils.MethodUtils; +import org.xml.sax.Attributes; + + +/** + *

Rule implementation that calls a method on an object on the stack + * (normally the top/parent object), passing arguments collected from + * subsequent CallParamRule rules or from the body of this + * element.

+ * + *

By using {@link #CallMethodRule(String methodName)} + * a method call can be made to a method which accepts no + * arguments.

+ * + *

Incompatible method parameter types are converted + * using org.apache.commons.beanutils.ConvertUtils. + *

+ * + *

This rule now uses {@link MethodUtils#invokeMethod} by default. + * This increases the kinds of methods successfully and allows primitives + * to be matched by passing in wrapper classes. + * There are rare cases when {@link MethodUtils#invokeExactMethod} + * (the old default) is required. + * This method is much stricter in it's reflection. + * Setting the UseExactMatch to true reverts to the use of this + * method.

+ * + *

Note that the target method is invoked when the end of + * the tag the CallMethodRule fired on is encountered, not when the + * last parameter becomes available. This implies that rules which fire on + * tags nested within the one associated with the CallMethodRule will + * fire before the CallMethodRule invokes the target method. This behaviour is + * not configurable.

+ * + *

Note also that if a CallMethodRule is expecting exactly one parameter + * and that parameter is not available (eg CallParamRule is used with an + * attribute name but the attribute does not exist) then the method will + * not be invoked. If a CallMethodRule is expecting more than one parameter, + * then it is always invoked, regardless of whether the parameters were + * available or not; missing parameters are converted to the appropriate target + * type by calling ConvertUtils.convert. Note that the default ConvertUtils + * converters for the String type returns a null when passed a null, meaning + * that CallMethodRule will passed null for all String parameters for which + * there is no parameter info available from the XML. However parameters of + * type Float and Integer will be passed a real object containing a zero value + * as that is the output of the default ConvertUtils converters for those + * types when passed a null. You can register custom converters to change + * this behaviour; see the beautils library documentation for more info.

+ * + *

Note that when a constructor is used with paramCount=0, indicating that + * the body of the element is to be passed to the target method, an empty + * element will cause an empty string to be passed to the target method, + * not null. And if automatic type conversion is being applied (ie if the + * target function takes something other than a string as a parameter) then + * the conversion will fail if the converter class does not accept an empty + * string as valid input.

+ * + *

CallMethodRule has a design flaw which can cause it to fail under + * certain rule configurations. All CallMethodRule instances share a single + * parameter stack, and all CallParamRule instances simply store their data + * into the parameter-info structure that is on the top of the stack. This + * means that two CallMethodRule instances cannot be associated with the + * same pattern without getting scrambled parameter data. This same issue + * also applies when a CallMethodRule matches some element X, a different + * CallMethodRule matches a child element Y and some of the CallParamRules + * associated with the first CallMethodRule match element Y or one of its + * child elements. This issue has been present since the very first release + * of Digester. Note, however, that this configuration of CallMethodRule + * instances is not commonly required.

+ */ + +public class CallMethodRule extends Rule { + + // ----------------------------------------------------------- Constructors + + /** + * Construct a "call method" rule with the specified method name. The + * parameter types (if any) default to java.lang.String. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of this element. + * + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallMethodRule(String methodName,int paramCount)} instead. + */ + @Deprecated + public CallMethodRule(Digester digester, String methodName, + int paramCount) { + + this(methodName, paramCount); + + } + + + /** + * Construct a "call method" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java class names of the arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallMethodRule(String methodName,int paramCount, String [] paramTypes)} instead. + */ + @Deprecated + public CallMethodRule(Digester digester, String methodName, + int paramCount, String paramTypes[]) { + + this(methodName, paramCount, paramTypes); + + } + + + /** + * Construct a "call method" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java classes that represent the + * parameter types of the method arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean.TYPE + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallMethodRule(String methodName,int paramCount, Class [] paramTypes)} instead. + */ + @Deprecated + public CallMethodRule(Digester digester, String methodName, + int paramCount, Class paramTypes[]) { + + this(methodName, paramCount, paramTypes); + } + + + /** + * Construct a "call method" rule with the specified method name. The + * parameter types (if any) default to java.lang.String. + * + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of this element. + */ + public CallMethodRule(String methodName, + int paramCount) { + this(0, methodName, paramCount); + } + + /** + * Construct a "call method" rule with the specified method name. The + * parameter types (if any) default to java.lang.String. + * + * @param targetOffset location of the target object. Positive numbers are + * relative to the top of the digester object stack. Negative numbers + * are relative to the bottom of the stack. Zero implies the top + * object on the stack. + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of this element. + */ + public CallMethodRule(int targetOffset, + String methodName, + int paramCount) { + + this.targetOffset = targetOffset; + this.methodName = methodName; + this.paramCount = paramCount; + if (paramCount == 0) { + this.paramTypes = new Class[] { String.class }; + } else { + this.paramTypes = new Class[paramCount]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypes[i] = String.class; + } + } + + } + + /** + * Construct a "call method" rule with the specified method name. + * The method should accept no parameters. + * + * @param methodName Method name of the parent method to call + */ + public CallMethodRule(String methodName) { + + this(0, methodName, 0, (Class[]) null); + + } + + + /** + * Construct a "call method" rule with the specified method name. + * The method should accept no parameters. + * + * @param targetOffset location of the target object. Positive numbers are + * relative to the top of the digester object stack. Negative numbers + * are relative to the bottom of the stack. Zero implies the top + * object on the stack. + * @param methodName Method name of the parent method to call + */ + public CallMethodRule(int targetOffset, String methodName) { + + this(targetOffset, methodName, 0, (Class[]) null); + + } + + + /** + * Construct a "call method" rule with the specified method name and + * parameter types. If paramCount is set to zero the rule + * will use the body of this 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 methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java class names of the arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public CallMethodRule( + String methodName, + int paramCount, + String paramTypes[]) { + this(0, methodName, paramCount, paramTypes); + } + + /** + * Construct a "call method" rule with the specified method name and + * parameter types. If paramCount is set to zero the rule + * will use the body of this 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 targetOffset location of the target object. Positive numbers are + * relative to the top of the digester object stack. Negative numbers + * are relative to the bottom of the stack. Zero implies the top + * object on the stack. + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java class names of the arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public CallMethodRule( int targetOffset, + String methodName, + int paramCount, + String paramTypes[]) { + + this.targetOffset = targetOffset; + this.methodName = methodName; + this.paramCount = paramCount; + if (paramTypes == null) { + this.paramTypes = new Class[paramCount]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypes[i] = String.class; + } + } else { + // copy the parameter class names into an array + // the classes will be loaded when the digester is set + this.paramClassNames = new String[paramTypes.length]; + for (int i = 0; i < this.paramClassNames.length; i++) { + this.paramClassNames[i] = paramTypes[i]; + } + } + + } + + + /** + * Construct a "call method" rule with the specified method name and + * parameter types. If paramCount is set to zero the rule + * will use the body of this 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 methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java classes that represent the + * parameter types of the method arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean.TYPE + * for a boolean parameter) + */ + public CallMethodRule( + String methodName, + int paramCount, + Class paramTypes[]) { + this(0, methodName, paramCount, paramTypes); + } + + /** + * Construct a "call method" rule with the specified method name and + * parameter types. If paramCount is set to zero the rule + * will use the body of this 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 targetOffset location of the target object. Positive numbers are + * relative to the top of the digester object stack. Negative numbers + * are relative to the bottom of the stack. Zero implies the top + * object on the stack. + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java classes that represent the + * parameter types of the method arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean.TYPE + * for a boolean parameter) + */ + public CallMethodRule( int targetOffset, + String methodName, + int paramCount, + Class paramTypes[]) { + + this.targetOffset = targetOffset; + this.methodName = methodName; + this.paramCount = paramCount; + if (paramTypes == null) { + this.paramTypes = new Class[paramCount]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypes[i] = String.class; + } + } else { + this.paramTypes = new Class[paramTypes.length]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypes[i] = paramTypes[i]; + } + } + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The body text collected from this element. + */ + protected String bodyText = null; + + + /** + * location of the target object for the call, relative to the + * top of the digester object stack. The default value of zero + * means the target object is the one on top of the stack. + */ + protected int targetOffset = 0; + + /** + * The method name to call on the parent object. + */ + protected String methodName = null; + + + /** + * The number of parameters to collect from MethodParam rules. + * If this value is zero, a single parameter will be collected from the + * body of this element. + */ + protected int paramCount = 0; + + + /** + * The parameter types of the parameters to be collected. + */ + protected Class paramTypes[] = null; + + /** + * The names of the classes of the parameters to be collected. + * This attribute allows creation of the classes to be postponed until the digester is set. + */ + private String paramClassNames[] = null; + + /** + * Should MethodUtils.invokeExactMethod be used for reflection. + */ + protected boolean useExactMatch = false; + + // --------------------------------------------------------- Public Methods + + /** + * Should MethodUtils.invokeExactMethod + * be used for the reflection. + */ + public boolean getUseExactMatch() { + return useExactMatch; + } + + /** + * Set whether MethodUtils.invokeExactMethod + * should be used for the reflection. + */ + public void setUseExactMatch(boolean useExactMatch) + { + this.useExactMatch = useExactMatch; + } + + /** + * Set the associated digester. + * If needed, this class loads the parameter classes from their names. + */ + @Override + public void setDigester(Digester digester) + { + // call superclass + super.setDigester(digester); + // if necessary, load parameter classes + if (this.paramClassNames != null) { + this.paramTypes = new Class[paramClassNames.length]; + for (int i = 0; i < this.paramClassNames.length; i++) { + try { + this.paramTypes[i] = + digester.getClassLoader().loadClass(this.paramClassNames[i]); + } catch (ClassNotFoundException e) { + // use the digester log + digester.getLogger().error("(CallMethodRule) Cannot load class " + this.paramClassNames[i], e); + this.paramTypes[i] = null; // Will cause NPE later + } + } + } + } + + /** + * Process the start of this element. + * + * @param attributes The attribute list for this element + */ + @Override + public void begin(Attributes attributes) throws Exception { + + // Push an array to capture the parameter values if necessary + if (paramCount > 0) { + Object parameters[] = new Object[paramCount]; + for (int i = 0; i < parameters.length; i++) { + parameters[i] = null; + } + digester.pushParams(parameters); + } + + } + + + /** + * Process the body text of this element. + * + * @param bodyText The body text of this element + */ + @Override + public void body(String bodyText) throws Exception { + + if (paramCount == 0) { + this.bodyText = bodyText.trim(); + } + + } + + + /** + * Process the end of this element. + */ + @Override + public void end() throws Exception { + + // Retrieve or construct the parameter values array + Object parameters[] = null; + if (paramCount > 0) { + + parameters = (Object[]) digester.popParams(); + + if (digester.log.isTraceEnabled()) { + for (int i=0,size=parameters.length;i= 0) { + target = digester.peek(targetOffset); + } else { + target = digester.peek( digester.getCount() + targetOffset ); + } + + if (target == null) { + StringBuffer sb = new StringBuffer(); + sb.append("[CallMethodRule]{"); + sb.append(digester.match); + sb.append("} Call target is null ("); + sb.append("targetOffset="); + sb.append(targetOffset); + sb.append(",stackdepth="); + sb.append(digester.getCount()); + sb.append(")"); + throw new org.xml.sax.SAXException(sb.toString()); + } + + // Invoke the required method on the top object + if (digester.log.isDebugEnabled()) { + StringBuffer sb = new StringBuffer("[CallMethodRule]{"); + sb.append(digester.match); + sb.append("} Call "); + sb.append(target.getClass().getName()); + sb.append("."); + sb.append(methodName); + sb.append("("); + for (int i = 0; i < paramValues.length; i++) { + if (i > 0) { + sb.append(","); + } + if (paramValues[i] == null) { + sb.append("null"); + } else { + sb.append(paramValues[i].toString()); + } + sb.append("/"); + if (paramTypes[i] == null) { + sb.append("null"); + } else { + sb.append(paramTypes[i].getName()); + } + } + sb.append(")"); + digester.log.debug(sb.toString()); + } + + Object result = null; + if (useExactMatch) { + // invoke using exact match + result = MethodUtils.invokeExactMethod(target, methodName, + paramValues, paramTypes); + + } else { + // invoke using fuzzier match + result = MethodUtils.invokeMethod(target, methodName, + paramValues, paramTypes); + } + + processMethodCallResult(result); + } + + + /** + * Clean up after parsing is complete. + */ + @Override + public void finish() throws Exception { + + bodyText = null; + + } + + /** + * Subclasses may override this method to perform additional processing of the + * invoked method's result. + * + * @param result the Object returned by the method invoked, possibly null + */ + protected void processMethodCallResult(Object result) { + // do nothing + } + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("CallMethodRule["); + sb.append("methodName="); + sb.append(methodName); + sb.append(", paramCount="); + sb.append(paramCount); + sb.append(", paramTypes={"); + if (paramTypes != null) { + for (int i = 0; i < paramTypes.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(paramTypes[i].getName()); + } + } + sb.append("}"); + sb.append("]"); + return (sb.toString()); + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/CallParamRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/CallParamRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/CallParamRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,283 @@ +/* $Id: CallParamRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import java.util.Stack; + +import org.xml.sax.Attributes; + + +/** + *

Rule implementation that saves a parameter for use by a surrounding + * CallMethodRule.

+ * + *

This parameter may be: + *

    + *
  • from an attribute of the current element + * See {@link #CallParamRule(int paramIndex, String attributeName)} + *
  • from current the element body + * See {@link #CallParamRule(int paramIndex)} + *
  • from the top object on the stack. + * See {@link #CallParamRule(int paramIndex, boolean fromStack)} + *
  • the current path being processed (separate Rule). + * See {@link PathCallParamRule} + *
+ *

+ */ + +public class CallParamRule extends Rule { + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "call parameter" rule that will save the body text of this + * element as the parameter value. + * + *

Note that if the element is empty the an empty string is + * passed to the target method, not null. And if automatic type conversion + * is being applied (ie if the target function takes something other than + * a string as a parameter) then the conversion will fail if the converter + * class does not accept an empty string as valid input.

+ * + * @param digester The associated Digester + * @param paramIndex The zero-relative parameter number + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallParamRule(int paramIndex)} instead. + */ + @Deprecated + public CallParamRule(Digester digester, int paramIndex) { + + this(paramIndex); + + } + + + /** + * Construct a "call parameter" rule that will save the value of the + * specified attribute as the parameter value. + * + * @param digester The associated Digester + * @param paramIndex The zero-relative parameter number + * @param attributeName The name of the attribute to save + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallParamRule(int paramIndex, String attributeName)} instead. + */ + @Deprecated + public CallParamRule(Digester digester, int paramIndex, + String attributeName) { + + this(paramIndex, attributeName); + + } + + /** + * Construct a "call parameter" rule that will save the body text of this + * element as the parameter value. + * + *

Note that if the element is empty the an empty string is + * passed to the target method, not null. And if automatic type conversion + * is being applied (ie if the target function takes something other than + * a string as a parameter) then the conversion will fail if the converter + * class does not accept an empty string as valid input.

+ * + * @param paramIndex The zero-relative parameter number + */ + public CallParamRule(int paramIndex) { + + this(paramIndex, null); + + } + + + /** + * Construct a "call parameter" rule that will save the value of the + * specified attribute as the parameter value. + * + * @param paramIndex The zero-relative parameter number + * @param attributeName The name of the attribute to save + */ + public CallParamRule(int paramIndex, + String attributeName) { + + this.paramIndex = paramIndex; + this.attributeName = attributeName; + + } + + + /** + * Construct a "call parameter" rule. + * + * @param paramIndex The zero-relative parameter number + * @param fromStack should this parameter be taken from the top of the stack? + */ + public CallParamRule(int paramIndex, boolean fromStack) { + + this.paramIndex = paramIndex; + this.fromStack = fromStack; + + } + + /** + * Constructs a "call parameter" rule which sets a parameter from the stack. + * If the stack contains too few objects, then the parameter will be set to null. + * + * @param paramIndex The zero-relative parameter number + * @param stackIndex the index of the object which will be passed as a parameter. + * The zeroth object is the top of the stack, 1 is the next object down and so on. + */ + public CallParamRule(int paramIndex, int stackIndex) { + + this.paramIndex = paramIndex; + this.fromStack = true; + this.stackIndex = stackIndex; + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The attribute from which to save the parameter value + */ + protected String attributeName = null; + + + /** + * The zero-relative index of the parameter we are saving. + */ + protected int paramIndex = 0; + + + /** + * Is the parameter to be set from the stack? + */ + protected boolean fromStack = false; + + /** + * The position of the object from the top of the stack + */ + protected int stackIndex = 0; + + /** + * Stack is used to allow nested body text to be processed. + * Lazy creation. + */ + protected Stack bodyTextStack; + + // --------------------------------------------------------- Public Methods + + + /** + * Process the start of this element. + * + * @param attributes The attribute list for this element + */ + @Override + public void begin(Attributes attributes) throws Exception { + + Object param = null; + + if (attributeName != null) { + + param = attributes.getValue(attributeName); + + } else if(fromStack) { + + param = digester.peek(stackIndex); + + if (digester.log.isDebugEnabled()) { + + StringBuffer sb = new StringBuffer("[CallParamRule]{"); + sb.append(digester.match); + sb.append("} Save from stack; from stack?").append(fromStack); + sb.append("; object=").append(param); + digester.log.debug(sb.toString()); + } + } + + // Have to save the param object to the param stack frame here. + // Can't wait until end(). Otherwise, the object will be lost. + // We can't save the object as instance variables, as + // the instance variables will be overwritten + // if this CallParamRule is reused in subsequent nesting. + + if(param != null) { + Object parameters[] = (Object[]) digester.peekParams(); + parameters[paramIndex] = param; + } + } + + + /** + * Process the body text of this element. + * + * @param bodyText The body text of this element + */ + @Override + public void body(String bodyText) throws Exception { + + if (attributeName == null && !fromStack) { + // We must wait to set the parameter until end + // so that we can make sure that the right set of parameters + // is at the top of the stack + if (bodyTextStack == null) { + bodyTextStack = new Stack(); + } + bodyTextStack.push(bodyText.trim()); + } + + } + + /** + * Process any body texts now. + */ + @Override + public void end(String namespace, String name) { + if (bodyTextStack != null && !bodyTextStack.empty()) { + // what we do now is push one parameter onto the top set of parameters + Object parameters[] = (Object[]) digester.peekParams(); + parameters[paramIndex] = bodyTextStack.pop(); + } + } + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("CallParamRule["); + sb.append("paramIndex="); + sb.append(paramIndex); + sb.append(", attributeName="); + sb.append(attributeName); + sb.append(", from stack="); + sb.append(fromStack); + sb.append("]"); + return (sb.toString()); + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/Digester.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/Digester.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/Digester.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,3402 @@ +/* $Id: Digester.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.EmptyStackException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Stack; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.validation.Schema; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + + + + +/** + *

A Digester processes an XML input stream by matching a + * series of element nesting patterns to execute Rules that have been added + * prior to the start of parsing.

+ * + *

See the Digester + * Developer Guide for more information.

+ * + *

IMPLEMENTATION NOTE - A single Digester instance may + * only be used within the context of a single thread at a time, and a call + * to parse() must be completed before another can be initiated + * even from the same thread.

+ * + *

A Digester instance should not be used for parsing more than one input + * document. The problem is that the Digester class has quite a few member + * variables whose values "evolve" as SAX events are received during a parse. + * When reusing the Digester instance, all these members must be reset back + * to their initial states before the second parse begins. The "clear()" + * method makes a stab at resetting these, but it is actually rather a + * difficult problem. If you are determined to reuse Digester instances, then + * at the least you should call the clear() method before each parse, and must + * call it if the Digester parse terminates due to an exception during a parse. + *

+ * + *

LEGACY IMPLEMENTATION NOTE - When using the legacy XML + * schema support (instead of using the {@link Schema} class), a bug in + * Xerces 2.0.2 prevents the support of XML schema. You need Xerces 2.1/2.3 + * and up to make this class work with the legacy XML schema support.

+ * + *

This package was inspired by the XmlMapper class that was + * part of Tomcat 3.0 and 3.1, but is organized somewhat differently.

+ */ + +public class Digester extends DefaultHandler { + + + // --------------------------------------------------------- Constructors + + + /** + * Construct a new Digester with default properties. + */ + public Digester() { + + super(); + + } + + + /** + * Construct a new Digester, allowing a SAXParser to be passed in. This + * allows Digester to be used in environments which are unfriendly to + * JAXP1.1 (such as WebLogic 6.0). This may help in places where + * you are able to load JAXP 1.1 classes yourself. + */ + public Digester(SAXParser parser) { + + super(); + + this.parser = parser; + + } + + + /** + * Construct a new Digester, allowing an XMLReader to be passed in. This + * allows Digester to be used in environments which are unfriendly to + * JAXP1.1 (such as WebLogic 6.0). Note that if you use this option you + * have to configure namespace and validation support yourself, as these + * properties only affect the SAXParser and emtpy constructor. + */ + public Digester(XMLReader reader) { + + super(); + + this.reader = reader; + + } + + + // --------------------------------------------------- Instance Variables + + + /** + * The body text of the current element. + */ + protected StringBuffer bodyText = new StringBuffer(); + + + /** + * The stack of body text string buffers for surrounding elements. + */ + protected Stack bodyTexts = new Stack(); + + + /** + * Stack whose elements are List objects, each containing a list of + * Rule objects as returned from Rules.getMatch(). As each xml element + * in the input is entered, the matching rules are pushed onto this + * stack. After the end tag is reached, the matches are popped again. + * The depth of is stack is therefore exactly the same as the current + * "nesting" level of the input xml. + * + * @since 1.6 + */ + protected Stack> matches = new Stack>(); + + /** + * 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. + */ + protected ClassLoader classLoader = null; + + + /** + * Has this Digester been configured yet. + */ + protected boolean configured = false; + + + /** + * The EntityResolver used by the SAX parser. By default it use this class + */ + protected EntityResolver entityResolver; + + /** + * The URLs of entityValidator that have been registered, keyed by the public + * identifier that corresponds. + */ + protected HashMap entityValidator = new HashMap(); + + + /** + * The application-supplied error handler that is notified when parsing + * warnings, errors, or fatal errors occur. + */ + protected ErrorHandler errorHandler = null; + + + /** + * The SAXParserFactory that is created the first time we need it. + */ + protected SAXParserFactory factory = null; + + /** + * @deprecated This is now managed by {@link ParserFeatureSetterFactory} + */ + @Deprecated + protected String JAXP_SCHEMA_LANGUAGE = + "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + + + /** + * The Locator associated with our parser. + */ + protected Locator locator = null; + + + /** + * The current match pattern for nested element processing. + */ + protected String match = ""; + + + /** + * Do we want a "namespace aware" parser. + */ + protected boolean namespaceAware = false; + + + /** + * Registered namespaces we are currently processing. The key is the + * namespace prefix that was declared in the document. The value is an + * Stack of the namespace URIs this prefix has been mapped to -- + * the top Stack element is the most current one. (This architecture + * is required because documents can declare nested uses of the same + * prefix for different Namespace URIs). + */ + protected HashMap> namespaces = new HashMap>(); + + + /** + * Do we want a "XInclude aware" parser. + */ + protected boolean xincludeAware = false; + + + /** + * The parameters stack being utilized by CallMethodRule and + * CallParamRule rules. + * + * @since 2.0 + */ + protected Stack params = new Stack(); + + + /** + * The SAXParser we will use to parse the input stream. + */ + protected SAXParser parser = null; + + + /** + * The public identifier of the DTD we are currently parsing under + * (if any). + */ + protected String publicId = null; + + + /** + * The XMLReader used to parse digester rules. + */ + protected XMLReader reader = null; + + + /** + * The "root" element of the stack (in other words, the last object + * that was popped. + */ + protected Object root = null; + + + /** + * The Rules implementation containing our collection of + * Rule instances and associated matching policy. If not + * established before the first rule is added, a default implementation + * will be provided. + */ + protected Rules rules = null; + + /** + * The XML schema language to use for validating an XML instance. By + * default this value is set to W3C_XML_SCHEMA + * + * @deprecated Use {@link Schema} support instead. + */ + @Deprecated + protected String schemaLanguage = W3C_XML_SCHEMA; + + + /** + * The XML schema to use for validating an XML instance. + * + * @deprecated Use {@link Schema} support instead. + */ + @Deprecated + protected String schemaLocation = null; + + + /** + * The XML schema to use for validating an XML instance. + * + * @since 2.0 + */ + protected Schema schema = null; + + + /** + * The object stack being constructed. + */ + protected Stack stack = new Stack(); + + + /** + * Do we want to use the Context ClassLoader when loading classes + * for instantiating new objects. Default is false. + */ + protected boolean useContextClassLoader = false; + + + /** + * Do we want to use a validating parser. + */ + protected boolean validating = false; + + + /** + * The Log to which most logging calls will be made. + */ + protected Log log = + LogFactory.getLog("org.apache.commons.digester.Digester"); + + + /** + * The Log to which all SAX event related logging calls will be made. + */ + protected Log saxLog = + LogFactory.getLog("org.apache.commons.digester.Digester.sax"); + + + /** + * The schema language supported. By default, we use this one. + */ + protected static final String W3C_XML_SCHEMA = + "http://www.w3.org/2001/XMLSchema"; + + /** + * 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. + */ + protected Substitutor substitutor; + + /** Stacks used for interrule communication, indexed by name String */ + private HashMap> stacksByName = new HashMap>(); + + /** + * If not null, then calls by the parser to this object's characters, + * startElement, endElement and processingInstruction methods are + * forwarded to the specified object. This is intended to allow rules + * to temporarily "take control" of the sax events. In particular, + * this is used by NodeCreateRule. + *

+ * See setCustomContentHandler. + */ + private ContentHandler customContentHandler = null; + + /** + * Object which will receive callbacks for every pop/push action + * on the default stack or named stacks. + */ + private StackAction stackAction = null; + + // ------------------------------------------------------------- Properties + + /** + * Return the currently mapped namespace URI for the specified prefix, + * if any; otherwise return null. These mappings come and + * go dynamically as the document is parsed. + * + * @param prefix Prefix to look up + */ + public String findNamespaceURI(String prefix) { + + Stack nsStack = namespaces.get(prefix); + if (nsStack == null) { + return null; + } + try { + return (nsStack.peek()); + } catch (EmptyStackException e) { + return null; + } + + } + + + /** + * Return the class loader to be used for instantiating application objects + * when required. This is determined based upon the following rules: + *

    + *
  • The class loader set by setClassLoader(), if any
  • + *
  • The thread context class loader, if it exists and the + * useContextClassLoader property is set to true
  • + *
  • The class loader used to load the Digester class itself. + *
+ */ + public ClassLoader getClassLoader() { + + if (this.classLoader != null) { + return (this.classLoader); + } + if (this.useContextClassLoader) { + ClassLoader classLoader = + Thread.currentThread().getContextClassLoader(); + if (classLoader != null) { + return (classLoader); + } + } + return (this.getClass().getClassLoader()); + + } + + + /** + * Set the class loader to be used for instantiating application objects + * when required. + * + * @param classLoader The new class loader to use, or null + * to revert to the standard rules + */ + public void setClassLoader(ClassLoader classLoader) { + + this.classLoader = classLoader; + + } + + + /** + * Return the current depth of the element stack. + */ + public int getCount() { + + return (stack.size()); + + } + + + /** + * Return the name of the XML element that is currently being processed. + */ + public String getCurrentElementName() { + + String elementName = match; + int lastSlash = elementName.lastIndexOf('/'); + if (lastSlash >= 0) { + elementName = elementName.substring(lastSlash + 1); + } + return (elementName); + + } + + + /** + * Return the debugging detail level of our currently enabled logger. + * + * @deprecated This method now always returns 0. Digester uses the apache + * jakarta commons-logging library; see the documentation for that library + * for more information. + */ + @Deprecated + public int getDebug() { + + return (0); + + } + + + /** + * Set the debugging detail level of our currently enabled logger. + * + * @param debug New debugging detail level (0=off, increasing integers + * for more detail) + * + * @deprecated This method now has no effect at all. Digester uses + * the apache jakarta comons-logging library; see the documentation + * for that library for more information. + */ + @Deprecated + public void setDebug(int debug) { + + // No action is taken + + } + + + /** + * Return the error handler for this Digester. + */ + public ErrorHandler getErrorHandler() { + + return (this.errorHandler); + + } + + + /** + * Set the error handler for this Digester. + * + * @param errorHandler The new error handler + */ + public void setErrorHandler(ErrorHandler errorHandler) { + + this.errorHandler = errorHandler; + + } + + + /** + * Return the SAXParserFactory we will use, creating one if necessary. + */ + public SAXParserFactory getFactory() { + + if (factory == null) { + factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(namespaceAware); + factory.setXIncludeAware(xincludeAware); + factory.setValidating(validating); + factory.setSchema(schema); + } + return (factory); + + } + + + /** + * Returns a flag indicating whether the requested feature is supported + * by the underlying implementation of org.xml.sax.XMLReader. + * See the saxproject website + * for information about the standard SAX2 feature flags. + * + * @param feature Name of the feature to inquire about + * + * @exception ParserConfigurationException if a parser configuration error + * occurs + * @exception SAXNotRecognizedException if the property name is + * not recognized + * @exception SAXNotSupportedException if the property name is + * recognized but not supported + */ + public boolean getFeature(String feature) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException { + + return (getFactory().getFeature(feature)); + + } + + + /** + * Sets a flag indicating whether the requested feature is supported + * by the underlying implementation of org.xml.sax.XMLReader. + * See the saxproject website + * for information about the standard SAX2 feature flags. In order to be + * effective, this method must be called before the + * getParser() 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 + * @exception SAXNotRecognizedException if the property name is + * not recognized + * @exception SAXNotSupportedException if the property name is + * recognized but not supported + */ + public void setFeature(String feature, boolean value) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException { + + getFactory().setFeature(feature, value); + + } + + + /** + * Return the current Logger associated with this instance of the Digester + */ + public Log getLogger() { + + return log; + + } + + + /** + * Set the current logger for this Digester. + */ + public void setLogger(Log log) { + + this.log = log; + + } + + /** + * Gets the logger used for logging SAX-related information. + * Note the output is finely grained. + * + * @since 1.6 + */ + public Log getSAXLogger() { + + return saxLog; + } + + + /** + * Sets the logger used for logging SAX-related information. + * Note the output is finely grained. + * @param saxLog Log, not null + * + * @since 1.6 + */ + public void setSAXLogger(Log saxLog) { + + this.saxLog = saxLog; + } + + /** + * Return the current rule match path + */ + public String getMatch() { + + return match; + + } + + + /** + * Return the "namespace aware" flag for parsers we create. + */ + public boolean getNamespaceAware() { + + return (this.namespaceAware); + + } + + + /** + * Set the "namespace aware" flag for parsers we create. + * + * @param namespaceAware The new "namespace aware" flag + */ + public void setNamespaceAware(boolean namespaceAware) { + + this.namespaceAware = namespaceAware; + + } + + + /** + * 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 + */ + public boolean getXIncludeAware() { + + return (this.xincludeAware); + + } + + + /** + * 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 + */ + public void setXIncludeAware(boolean xincludeAware) { + + this.xincludeAware = xincludeAware; + + } + + + /** + * Set the publid id of the current file being parse. + * @param publicId the DTD/Schema public's id. + */ + public void setPublicId(String publicId){ + this.publicId = publicId; + } + + + /** + * Return the public identifier of the DTD we are currently + * parsing under, if any. + */ + public String getPublicId() { + + return (this.publicId); + + } + + + /** + * Return the namespace URI that will be applied to all subsequently + * added Rule objects. + */ + public String getRuleNamespaceURI() { + + return (getRules().getNamespaceURI()); + + } + + + /** + * Set the namespace URI that will be applied to all subsequently + * added Rule objects. + * + * @param ruleNamespaceURI Namespace URI that must match on all + * subsequently added rules, or null for matching + * regardless of the current namespace URI + */ + public void setRuleNamespaceURI(String ruleNamespaceURI) { + + getRules().setNamespaceURI(ruleNamespaceURI); + + } + + + /** + * Return the SAXParser we will use to parse the input stream. If there + * is a problem creating the parser, return null. + */ + public SAXParser getParser() { + + // Return the parser we already created (if any) + if (parser != null) { + return (parser); + } + + // Create a new parser + try { + if (validating && (schemaLocation != null)) { + // There is no portable way to specify the location of + // an xml schema to be applied to the input document, so + // we have to use parser-specific code for this. That code + // is hidden behind the ParserFeatureSetterFactory class. + + // The above has changed in JDK 1.5 and no longer true. The + // functionality used in this block has now been deprecated. + // We now use javax.xml.validation.Schema instead. + + Properties properties = new Properties(); + properties.put("SAXParserFactory", getFactory()); + if (schemaLocation != null) { + properties.put("schemaLocation", schemaLocation); + properties.put("schemaLanguage", schemaLanguage); + } + parser = ParserFeatureSetterFactory.newSAXParser(properties); + } else { + // The user doesn't want to use any non-portable parsing features, + // so we can just use the portable API here. Note that method + // getFactory returns a factory already configured with the + // appropriate namespaceAware and validating properties. + + parser = getFactory().newSAXParser(); + } + } catch (Exception e) { + log.error("Digester.getParser: ", e); + return (null); + } + + return (parser); + + } + + + /** + * Return the current value of the specified property for the underlying + * XMLReader implementation. + * See the saxproject website + * for information about the standard SAX2 properties. + * + * @param property Property name to be retrieved + * + * @exception SAXNotRecognizedException if the property name is + * not recognized + * @exception SAXNotSupportedException if the property name is + * recognized but not supported + */ + public Object getProperty(String property) + throws SAXNotRecognizedException, SAXNotSupportedException { + + return (getParser().getProperty(property)); + + } + + + /** + * Set the current value of the specified property for the underlying + * XMLReader implementation. + * See the saxproject website + * 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 + * @exception SAXNotSupportedException if the property name is + * recognized but not supported + */ + public void setProperty(String property, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException { + + getParser().setProperty(property, value); + + } + + + /** + * By setting the reader in the constructor, you can bypass JAXP and + * be able to use digester in Weblogic 6.0. + * + * @deprecated Use getXMLReader() instead, which can throw a + * SAXException if the reader cannot be instantiated + */ + @Deprecated + public XMLReader getReader() { + + try { + return (getXMLReader()); + } catch (SAXException e) { + log.error("Cannot get XMLReader", e); + return (null); + } + + } + + + /** + * Return the Rules implementation object containing our + * rules collection and associated matching policy. If none has been + * established, a default implementation will be created and returned. + */ + public Rules getRules() { + + if (this.rules == null) { + this.rules = new RulesBase(); + this.rules.setDigester(this); + } + return (this.rules); + + } + + + /** + * Set the Rules implementation object containing our + * rules collection and associated matching policy. + * + * @param rules New Rules implementation + */ + public void setRules(Rules rules) { + + this.rules = rules; + this.rules.setDigester(this); + + } + + + /** + * Return the XML Schema URI used for validating an XML instance. + * + * @deprecated Use {@link Schema} for validation instead. + * @see #getXMLSchema() + * @see #setXMLSchema(Schema) + */ + @Deprecated + public String getSchema() { + + return (this.schemaLocation); + + } + + + /** + * Set the XML Schema URI used for validating the input XML. + *

+ * It is often desirable to force the input document to be + * validated against a particular schema regardless of what type + * the input document declares itself to be. This method allows that + * to be done. + *

+ * Note, however, that there is no standard API for enabling this + * feature on the underlying SAX parser; this method therefore only works + * for those parsers explicitly supported by Digester's + * ParserFeatureSetterFactory class. If the underlying parser does not + * support the feature, or is not one of the supported parsers, then + * an exception will be thrown when getParser is called (explicitly, + * or implicitly via the parse method). + *

+ * See also method setSchemaLanguage which allows the type of the schema + * specified here to be defined. By default, the schema is expected to + * be a W3C xml schema definition. + *

+ * IMPORTANT NOTE: This functionality was never very reliable, and has + * been horribly broken since the 1.6 release of Digester. There are + * currently no plans to fix it, so you are strongly recommended to + * avoid using this method. Instead, create an XMLParser instance + * yourself, configure validation appropriately, and pass it as a + * parameter to the Digester constructor. + * + * @param schemaLocation a URI to the schema. + * @deprecated Use {@link Schema} for validation instead. + * @see #getXMLSchema() + * @see #setXMLSchema(Schema) + */ + @Deprecated + public void setSchema(String schemaLocation){ + + this.schemaLocation = schemaLocation; + + } + + + /** + * Return the XML Schema language used when parsing. + * + * @deprecated Use {@link Schema} for validation instead. + * @see #getXMLSchema() + * @see #setXMLSchema(Schema) + */ + @Deprecated + public String getSchemaLanguage() { + + return (this.schemaLanguage); + + } + + + /** + * Set the XML Schema language used when parsing. By default, we use W3C. + * + * @param schemaLanguage a URI to the schema language. + * @deprecated Use {@link Schema} for validation instead. + * @see #getXMLSchema() + * @see #setXMLSchema(Schema) + */ + @Deprecated + public void setSchemaLanguage(String schemaLanguage){ + + this.schemaLanguage = schemaLanguage; + + } + + + /** + * Return the XML Schema used when parsing. + * + * @return The {@link Schema} instance in use. + * + * @since 2.0 + */ + public Schema getXMLSchema() { + + return (this.schema); + + } + + + /** + * Set the XML Schema to be used when parsing. + * + * @param schema The {@link Schema} instance to use. + * + * @since 2.0 + */ + public void setXMLSchema(Schema schema){ + + this.schema = schema; + + } + + + /** + * Return the boolean as to whether the context classloader should be used. + */ + public boolean getUseContextClassLoader() { + + return useContextClassLoader; + + } + + + /** + * 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. + * + * @param use determines whether to use Context ClassLoader. + */ + public void setUseContextClassLoader(boolean use) { + + useContextClassLoader = use; + + } + + + /** + * Return the validating parser flag. + */ + public boolean getValidating() { + + return (this.validating); + + } + + + /** + * Set the validating parser flag. This must be called before + * parse() is called the first time. + * + * @param validating The new validating parser flag. + */ + public void setValidating(boolean validating) { + + this.validating = validating; + + } + + + /** + * Return the XMLReader to be used for parsing the input document. + * + * FIX ME: there is a bug in JAXP/XERCES that prevent the use of a + * parser that contains a schema with a DTD. + * @exception SAXException if no XMLReader can be instantiated + */ + public XMLReader getXMLReader() throws SAXException { + if (reader == null){ + reader = getParser().getXMLReader(); + } + + reader.setDTDHandler(this); + reader.setContentHandler(this); + + if (entityResolver == null){ + reader.setEntityResolver(this); + } else { + reader.setEntityResolver(entityResolver); + } + + reader.setErrorHandler(this); + return reader; + } + + /** + * Gets the Substitutor used to convert attributes and body text. + * @return Substitutor, null if not substitutions are to be performed. + */ + public Substitutor getSubstitutor() { + return substitutor; + } + + /** + * Sets the Substitutor 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. + */ + public void setSubstitutor(Substitutor substitutor) { + this.substitutor = substitutor; + } + + /* + * See setCustomContentHandler. + * + * @since 1.7 + */ + public ContentHandler getCustomContentHandler() { + return customContentHandler; + } + + /** + * Redirects (or cancels redirecting) of SAX ContentHandler events to an + * external object. + *

+ * When this object's customContentHandler is non-null, any SAX events + * received from the parser will simply be passed on to the specified + * object instead of this object handling them. This allows Rule classes + * to take control of the SAX event stream for a while in order to do + * custom processing. Such a rule should save the old value before setting + * a new one, and restore the old value in order to resume normal digester + * processing. + *

+ * An example of a Rule which needs this feature is NodeCreateRule. + *

+ * Note that saving the old value is probably not needed as it should always + * be null; a custom rule that wants to take control could only have been + * called when there was no custom content handler. But it seems cleaner + * to properly save/restore the value and maybe some day this will come in + * useful. + *

+ * Note also that this is not quite equivalent to + *

+     * digester.getXMLReader().setContentHandler(handler)
+     * 
+ * for these reasons: + *
    + *
  • Some xml parsers don't like having setContentHandler called after + * parsing has started. The Aelfred parser is one example.
  • + *
  • Directing the events via the Digester object potentially allows + * us to log information about those SAX events at the digester level.
  • + *
+ * + * @since 1.7 + */ + public void setCustomContentHandler(ContentHandler handler) { + customContentHandler = handler; + } + + /** + * Define a callback object which is invoked whever an object is pushed onto + * a digester object stack, or popped off one. + * + * @since 1.8 + */ + public void setStackAction(StackAction stackAction) { + this.stackAction = stackAction; + } + + /** + * See setStackAction. + * + * @since 1.8 + */ + public StackAction getStackAction() { + return stackAction; + } + + /** + * 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 + */ + public Map getCurrentNamespaces() { + if (!namespaceAware) { + log.warn("Digester is not namespace aware"); + } + Map currentNamespaces = new HashMap(); + for (Map.Entry> nsEntry : namespaces.entrySet()) { + try { + currentNamespaces.put(nsEntry.getKey(), + nsEntry.getValue().peek()); + } catch (RuntimeException e) { + // rethrow, after logging + log.error(e.getMessage(), e); + throw e; + } + } + return currentNamespaces; + } + + // ------------------------------------------------- ContentHandler Methods + + + /** + * Process notification of character data received from the body of + * an XML element. + * + * @param buffer The characters from the XML document + * @param start Starting offset into the buffer + * @param length Number of characters from the buffer + * + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void characters(char buffer[], int start, int length) + throws SAXException { + + if (customContentHandler != null) { + // forward calls instead of handling them here + customContentHandler.characters(buffer, start, length); + return; + } + + if (saxLog.isDebugEnabled()) { + saxLog.debug("characters(" + new String(buffer, start, length) + ")"); + } + + bodyText.append(buffer, start, length); + + } + + + /** + * Process notification of the end of the document being reached. + * + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void endDocument() throws SAXException { + + if (saxLog.isDebugEnabled()) { + if (getCount() > 1) { + saxLog.debug("endDocument(): " + getCount() + + " elements left"); + } else { + saxLog.debug("endDocument()"); + } + } + + // Fire "finish" events for all defined rules + for (Rule rule : getRules().rules()) { + try { + rule.finish(); + } catch (Exception e) { + log.error("Finish event threw exception", e); + throw createSAXException(e); + } catch (Error e) { + log.error("Finish event threw error", e); + throw e; + } + } + + // Perform final cleanup + clear(); + + } + + + /** + * Process notification of the end of an XML element being reached. + * + * @param namespaceURI - The Namespace URI, or the empty string if the + * element has no Namespace URI or if Namespace processing is not + * being performed. + * @param localName - The local name (without prefix), or the empty + * string if Namespace processing is not being performed. + * @param qName - The qualified XML 1.0 name (with prefix), or the + * empty string if qualified names are not available. + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void endElement(String namespaceURI, String localName, + String qName) throws SAXException { + + if (customContentHandler != null) { + // forward calls instead of handling them here + customContentHandler.endElement(namespaceURI, localName, qName); + return; + } + + boolean debug = log.isDebugEnabled(); + + if (debug) { + if (saxLog.isDebugEnabled()) { + saxLog.debug("endElement(" + namespaceURI + "," + localName + + "," + qName + ")"); + } + log.debug(" match='" + match + "'"); + log.debug(" bodyText='" + bodyText + "'"); + } + + // the actual element name is either in localName or qName, depending + // on whether the parser is namespace aware + String name = localName; + if ((name == null) || (name.length() < 1)) { + name = qName; + } + + // Fire "body" events for all relevant rules + List rules = matches.pop(); + if ((rules != null) && (rules.size() > 0)) { + String bodyText = this.bodyText.toString(); + Substitutor substitutor = getSubstitutor(); + if (substitutor!= null) { + bodyText = substitutor.substitute(bodyText); + } + for (int i = 0; i < rules.size(); i++) { + try { + Rule rule = rules.get(i); + if (debug) { + log.debug(" Fire body() for " + rule); + } + rule.body(namespaceURI, name, bodyText); + } catch (Exception e) { + log.error("Body event threw exception", e); + throw createSAXException(e); + } catch (Error e) { + log.error("Body event threw error", e); + throw e; + } + } + } else { + if (debug) { + log.debug(" No rules found matching '" + match + "'."); + } + } + + // Recover the body text from the surrounding element + bodyText = bodyTexts.pop(); + if (debug) { + log.debug(" Popping body text '" + bodyText.toString() + "'"); + } + + // Fire "end" events for all relevant rules in reverse order + if (rules != null) { + for (int i = 0; i < rules.size(); i++) { + int j = (rules.size() - i) - 1; + try { + Rule rule = rules.get(j); + if (debug) { + log.debug(" Fire end() for " + rule); + } + rule.end(namespaceURI, name); + } catch (Exception e) { + log.error("End event threw exception", e); + throw createSAXException(e); + } catch (Error e) { + log.error("End event threw error", e); + throw e; + } + } + } + + // Recover the previous match expression + int slash = match.lastIndexOf('/'); + if (slash >= 0) { + match = match.substring(0, slash); + } else { + match = ""; + } + + } + + + /** + * Process notification that a namespace prefix is going out of scope. + * + * @param prefix Prefix that is going out of scope + * + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void endPrefixMapping(String prefix) throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("endPrefixMapping(" + prefix + ")"); + } + + // Deregister this prefix mapping + Stack stack = namespaces.get(prefix); + if (stack == null) { + return; + } + try { + stack.pop(); + if (stack.empty()) + namespaces.remove(prefix); + } catch (EmptyStackException e) { + throw createSAXException("endPrefixMapping popped too many times"); + } + + } + + + /** + * Process notification of ignorable whitespace received from the body of + * an XML element. + * + * @param buffer The characters from the XML document + * @param start Starting offset into the buffer + * @param len Number of characters from the buffer + * + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void ignorableWhitespace(char buffer[], int start, int len) + throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("ignorableWhitespace(" + + new String(buffer, start, len) + ")"); + } + + // No processing required + + } + + + /** + * Process notification of a processing instruction that was encountered. + * + * @param target The processing instruction target + * @param data The processing instruction data (if any) + * + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void processingInstruction(String target, String data) + throws SAXException { + + if (customContentHandler != null) { + // forward calls instead of handling them here + customContentHandler.processingInstruction(target, data); + return; + } + + if (saxLog.isDebugEnabled()) { + saxLog.debug("processingInstruction('" + target + "','" + data + "')"); + } + + // No processing is required + + } + + + /** + * Gets the document locator associated with our parser. + * + * @return the Locator supplied by the document parser + */ + public Locator getDocumentLocator() { + + return locator; + + } + + /** + * Sets the document locator associated with our parser. + * + * @param locator The new locator + */ + @Override + public void setDocumentLocator(Locator locator) { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("setDocumentLocator(" + locator + ")"); + } + + this.locator = locator; + + } + + + /** + * Process notification of a skipped entity. + * + * @param name Name of the skipped entity + * + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void skippedEntity(String name) throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("skippedEntity(" + name + ")"); + } + + // No processing required + + } + + + /** + * Process notification of the beginning of the document being reached. + * + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void startDocument() throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("startDocument()"); + } + + // ensure that the digester is properly configured, as + // the digester could be used as a SAX ContentHandler + // rather than via the parse() methods. + configure(); + } + + + /** + * Process notification of the start of an XML element being reached. + * + * @param namespaceURI The Namespace URI, or the empty string if the element + * has no Namespace URI or if Namespace processing is not being performed. + * @param localName The local name (without prefix), or the empty + * string if Namespace processing is not being performed. + * @param qName The qualified name (with prefix), or the empty + * string if qualified names are not available.\ + * @param list The attributes attached to the element. If there are + * no attributes, it shall be an empty Attributes object. + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void startElement(String namespaceURI, String localName, + String qName, Attributes list) + throws SAXException { + boolean debug = log.isDebugEnabled(); + + if (customContentHandler != null) { + // forward calls instead of handling them here + customContentHandler.startElement(namespaceURI, localName, qName, list); + return; + } + + if (saxLog.isDebugEnabled()) { + saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + + qName + ")"); + } + + // Save the body text accumulated for our surrounding element + bodyTexts.push(bodyText); + if (debug) { + log.debug(" Pushing body text '" + bodyText.toString() + "'"); + } + bodyText = new StringBuffer(); + + // the actual element name is either in localName or qName, depending + // on whether the parser is namespace aware + String name = localName; + if ((name == null) || (name.length() < 1)) { + name = qName; + } + + // Compute the current matching rule + StringBuffer sb = new StringBuffer(match); + if (match.length() > 0) { + sb.append('/'); + } + sb.append(name); + match = sb.toString(); + if (debug) { + log.debug(" New match='" + match + "'"); + } + + // Fire "begin" events for all relevant rules + List rules = getRules().match(namespaceURI, match); + matches.push(rules); + if ((rules != null) && (rules.size() > 0)) { + Substitutor substitutor = getSubstitutor(); + if (substitutor!= null) { + list = substitutor.substitute(list); + } + for (int i = 0; i < rules.size(); i++) { + try { + Rule rule = rules.get(i); + if (debug) { + log.debug(" Fire begin() for " + rule); + } + rule.begin(namespaceURI, name, list); + } catch (Exception e) { + log.error("Begin event threw exception", e); + throw createSAXException(e); + } catch (Error e) { + log.error("Begin event threw error", e); + throw e; + } + } + } else { + if (debug) { + log.debug(" No rules found matching '" + match + "'."); + } + } + + } + + + /** + * Process notification that a namespace prefix is coming in to scope. + * + * @param prefix Prefix that is being declared + * @param namespaceURI Corresponding namespace URI being mapped to + * + * @exception SAXException if a parsing error is to be reported + */ + @Override + public void startPrefixMapping(String prefix, String namespaceURI) + throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("startPrefixMapping(" + prefix + "," + namespaceURI + ")"); + } + + // Register this prefix mapping + Stack stack = namespaces.get(prefix); + if (stack == null) { + stack = new Stack(); + 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; + } + + /** + * Resolve the requested external entity. + * + * @param publicId The public identifier of the entity being referenced + * @param systemId The system identifier of the entity being referenced + * + * @exception SAXException if a parsing exception occurs + * + */ + @Override + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("resolveEntity('" + publicId + "', '" + systemId + "')"); + } + + if (publicId != null) + this.publicId = publicId; + + // Has this system identifier been registered? + URL entityURL = null; + if (publicId != null) { + entityURL = entityValidator.get(publicId); + } + + // Redirect the schema location to a local destination + if (schemaLocation != null && entityURL == null && systemId != null){ + entityURL = entityValidator.get(systemId); + } + + if (entityURL == null) { + if (systemId == null) { + // cannot resolve + if (log.isDebugEnabled()) { + log.debug(" Cannot resolve null entity, returning null InputSource"); + } + return (null); + + } else { + // try to resolve using system ID + if (log.isDebugEnabled()) { + log.debug(" Trying to resolve using system ID '" + systemId + "'"); + } + try { + entityURL = new URL(systemId); + } catch (MalformedURLException e) { + throw new IllegalArgumentException("Malformed URL '" + systemId + + "' : " + e.getMessage()); + } + } + } + + // Return an input source to our alternative URL + if (log.isDebugEnabled()) { + log.debug(" Resolving to alternate DTD '" + entityURL + "'"); + } + + try { + return createInputSourceFromURL(entityURL); + } catch (Exception e) { + throw createSAXException(e); + } + } + + + // ------------------------------------------------- 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 + + + /** + * Log a message to our associated logger. + * + * @param message The message to be logged + * @deprecated Call getLogger() and use it's logging methods + */ + @Deprecated + public void log(String message) { + + log.info(message); + + } + + + /** + * Log a message and exception to our associated logger. + * + * @param message The message to be logged + * @deprecated Call getLogger() and use it's logging methods + */ + @Deprecated + public void log(String message, Throwable exception) { + + log.error(message, exception); + + } + + + /** + * 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 { + + if (file == null) { + throw new IllegalArgumentException("File to parse is null"); + } + + configure(); + InputSource input = new InputSource(new FileInputStream(file)); + input.setSystemId(file.toURI().toURL().toString()); + getXMLReader().parse(input); + cleanup(); + 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 { + + if (input == null) { + throw new IllegalArgumentException("InputSource to parse is null"); + } + + configure(); + getXMLReader().parse(input); + cleanup(); + 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 { + + if (input == null) { + throw new IllegalArgumentException("InputStream to parse is null"); + } + + configure(); + InputSource is = new InputSource(input); + getXMLReader().parse(is); + cleanup(); + 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 { + + if (reader == null) { + throw new IllegalArgumentException("Reader to parse is null"); + } + + configure(); + InputSource is = new InputSource(reader); + getXMLReader().parse(is); + cleanup(); + 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 { + + if (uri == null) { + throw new IllegalArgumentException("String URI to parse is null"); + } + + configure(); + InputSource is = createInputSourceFromURL(uri); + getXMLReader().parse(is); + cleanup(); + return (root); + + } + + + /** + * Parse the content of the specified URL using this Digester. + * Returns the root element from the object stack (if any). + * + * @param url URL containing the XML data to be parsed + * + * @exception IOException if an input/output error occurs + * @exception SAXException if a parsing exception occurs + * + * @since 1.8 + */ + public Object parse(URL url) throws IOException, SAXException { + + if (url == null) { + throw new IllegalArgumentException("URL to parse is null"); + } + + configure(); + InputSource is = createInputSourceFromURL(url); + getXMLReader().parse(is); + cleanup(); + 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 + * + * @since 1.8 + */ + public void register(String publicId, URL entityURL) { + + if (log.isDebugEnabled()) { + log.debug("register('" + publicId + "', '" + entityURL + "'"); + } + entityValidator.put(publicId, entityURL); + + } + + + /** + *

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

+ * + * @param publicId Public identifier of the entity to be resolved + * @param entityURL The URL to use for reading this entity + */ + public void register(String publicId, String entityURL) { + + if (log.isDebugEnabled()) { + log.debug("register('" + publicId + "', '" + entityURL + "'"); + } + try { + entityValidator.put(publicId, new URL(entityURL)); + } catch (MalformedURLException e) { + throw new IllegalArgumentException("Malformed URL '" + entityURL + + "' : " + e.getMessage()); + } + + } + + + /** + *

List of InputSource instances + * created by a createInputSourceFromURL() method + * call. These represent open input streams that need to be + * closed to avoid resource leaks, as well as potentially locked + * JAR files on Windows.

+ */ + protected List inputSources = new ArrayList(5); + + + /** + * Given a URL, return an InputSource that reads from that URL. + *

+ * Ideally this function would not be needed and code could just use + * new InputSource(entityURL). Unfortunately it appears + * that when the entityURL points to a file within a jar archive a + * caching mechanism inside the InputSource implementation causes a + * file-handle to the jar file to remain open. On Windows systems + * this then causes the jar archive file to be locked on disk + * ("in use") which makes it impossible to delete the jar file - + * and that really stuffs up "undeploy" in webapps in particular. + *

+ * In JDK1.4 and later, Apache XercesJ is used as the xml parser. + * The InputSource object provided is converted into an XMLInputSource, + * and eventually passed to an instance of XMLDocumentScannerImpl to + * specify the source data to be converted into tokens for the rest + * of the XMLReader code to handle. XMLDocumentScannerImpl calls + * fEntityManager.startDocumentEntity(source), where fEntityManager + * is declared in ancestor class XMLScanner to be an XMLEntityManager. In + * that class, if the input source stream is null, then: + *

+     *  URL location = new URL(expandedSystemId);
+     *  URLConnection connect = location.openConnection();
+     *  if (connect instanceof HttpURLConnection) {
+     *    setHttpProperties(connect,xmlInputSource);
+     *  }
+     *  stream = connect.getInputStream();
+     * 
+ * This method pretty much duplicates the standard behaviour, except + * that it calls URLConnection.setUseCaches(false) before opening + * the connection. + * + * @since 1.8 + */ + public InputSource createInputSourceFromURL(URL url) + throws MalformedURLException, IOException { + + URLConnection connection = url.openConnection(); + connection.setUseCaches(false); + InputStream stream = connection.getInputStream(); + InputSource source = new InputSource(stream); + source.setSystemId(url.toExternalForm()); + inputSources.add(source); + return source; + + } + + + /** + *

Convenience method that creates an InputSource + * from the string version of a URL.

+ * + * @param url URL for which to create an InputSource + * + * @since 1.8 + */ + public InputSource createInputSourceFromURL(String url) + throws MalformedURLException, IOException { + + return createInputSourceFromURL(new URL(url)); + + } + + + // --------------------------------------------------------- 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 a "bean property setter" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @see BeanPropertySetterRule + */ + public void addBeanPropertySetter(String pattern) { + + addRule(pattern, + new BeanPropertySetterRule()); + + } + + + /** + * Add a "bean property setter" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param propertyName Name of property to set + * @see BeanPropertySetterRule + */ + public void addBeanPropertySetter(String pattern, + String propertyName) { + + addRule(pattern, + new BeanPropertySetterRule(propertyName)); + + } + + /** + * 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 corresonding + * 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 corresonding + * 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)); + + } + + /** + * Adds an {@link SetNestedPropertiesRule}. + * + * @param pattern register the rule with this pattern + * + * @since 1.6 + */ + public void addSetNestedProperties(String pattern) { + + addRule(pattern, new SetNestedPropertiesRule()); + } + + /** + * 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 + * + * @since 1.6 + */ + public void addSetNestedProperties(String pattern, String elementName, String propertyName) { + + addRule(pattern, new SetNestedPropertiesRule(elementName, propertyName)); + } + + /** + * 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 + * + * @since 1.6 + */ + public void addSetNestedProperties(String pattern, String[] elementNames, String[] propertyNames) { + + addRule(pattern, new SetNestedPropertiesRule(elementNames, propertyNames)); + } + + + /** + * 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 corresonding + * 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 corresonding + * 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 default object stack, the param stack, + * all named stacks, and other internal variables. + *

+ * Calling this method might allow another document of the same type + * to be correctly parsed. However this method was not intended for this + * purpose (just to tidy up memory usage). In general, a separate Digester + * object should be created for each document to be parsed. + *

+ * Note that this method is called automatically after a document has been + * successfully parsed by a Digester instance. However it is not invoked + * automatically when a parse fails, so when reusing a Digester instance + * (which is not recommended) this method must be called manually + * after a parse failure. + */ + public void clear() { + + match = ""; + bodyTexts.clear(); + params.clear(); + publicId = null; + stack.clear(); + stacksByName.clear(); + customContentHandler = null; + } + + + /** + * 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) { + + int index = (stack.size() - 1) - n; + if (index < 0) { + log.warn("Empty stack (returning null)"); + return (null); + } + try { + return (stack.get(index)); + } 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 { + Object popped = stack.pop(); + if (stackAction != null) { + popped = stackAction.onPop(this, null, popped); + } + return popped; + } 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 (stackAction != null) { + object = stackAction.onPush(this, null, 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) { + if (stackAction != null) { + value = stackAction.onPush(this, stackName, value); + } + + Stack namedStack = stacksByName.get(stackName); + if (namedStack == null) { + namedStack = new Stack(); + 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; + Stack namedStack = stacksByName.get(stackName); + if (namedStack == null) { + if (log.isDebugEnabled()) { + log.debug("Stack '" + stackName + "' is empty"); + } + throw new EmptyStackException(); + } + + result = namedStack.pop(); + + if (stackAction != null) { + result = stackAction.onPop(this, stackName, result); + } + + 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) { + return peek(stackName, 0); + } + + /** + *

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 + * @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 specified Object on the stack. + * @throws EmptyStackException if the named stack is empty + * + * @since 1.6 + */ + public Object peek(String stackName, int n) { + Object result = null; + Stack namedStack = stacksByName.get(stackName); + if (namedStack == null ) { + if (log.isDebugEnabled()) { + log.debug("Stack '" + stackName + "' is empty"); + } + throw new EmptyStackException(); + + } else { + int index = (namedStack.size() - 1) - n; + if (index < 0) { + throw new EmptyStackException(); + } + result = namedStack.get(index); + } + return result; + } + + /** + *

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; + Stack namedStack = stacksByName.get(stackName); + if (namedStack != null ) { + result = namedStack.isEmpty(); + } + return result; + } + + /** + * Returns the root element of the tree of objects created as a result + * of applying the rule objects to the input XML. + *

+ * If the digester stack was "primed" by explicitly pushing a root + * object onto the stack before parsing started, then that root object + * is returned here. + *

+ * Alternatively, if a Rule which creates an object (eg ObjectCreateRule) + * matched the root element of the xml, then the object created will be + * returned here. + *

+ * In other cases, the object most recently pushed onto an empty digester + * stack is returned. This would be a most unusual use of digester, however; + * one of the previous configurations is much more likely. + *

+ * Note that when using one of the Digester.parse methods, the return + * value from the parse method is exactly the 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. + * + * @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; + } + + /** + * This method allows the "root" variable to be reset to null. + *

+ * 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() { + root = null; + } + + // ------------------------------------------------ Parameter Stack Methods + + + // ------------------------------------------------------ Protected Methods + + + /** + *

Clean up allocated resources after parsing is complete. The + * default method closes input streams that have been created by + * Digester itself. If you override this method in a subclass, be + * sure to call super.cleanup() to invoke this logic.

+ * + * @since 1.8 + */ + protected void cleanup() { + + // If we created any InputSource objects in this instance, + // they each have an input stream that should be closed + for (InputSource source : inputSources) { + try { + source.getByteStream().close(); + } catch (IOException e) { + // Fall through so we get them all + } + } + inputSources.clear(); + + } + + + /** + *

+ * 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; + } + + // 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 set of rules that apply to the specified match position. + * The selected rules are those that match exactly, or those rules + * that specify a suffix match and the tail of the rule matches the + * current match position. Exact matches have precedence over + * suffix matches, then (among suffix matches) the longest match + * is preferred. + * + * @param match The current match position + * + * @deprecated Call match() on the Rules + * implementation returned by getRules() + */ + @Deprecated + List getRules(String match) { + + return (getRules().match(match)); + + } + + + /** + *

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) { + + int index = (params.size() - 1) - n; + if (index < 0) { + log.warn("Empty stack (returning null)"); + return (null); + } + try { + return (params.get(index)); + } 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 = ((InvocationTargetException) e).getTargetException(); + if ((t != null) && (t instanceof Exception)) { + e = (Exception) t; + } + } + if (locator != null) { + String error = "Error at line " + locator.getLineNumber() + " char " + + 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 = ((InvocationTargetException) e).getTargetException(); + if ((t != null) && (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); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/ExtendedBaseRules.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/ExtendedBaseRules.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/ExtendedBaseRules.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,484 @@ +/* $Id: ExtendedBaseRules.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + + +/** + *

Extension of {@link RulesBase} for complex schema.

+ * + *

This is an extension of the basic pattern matching scheme + * intended to improve support for mapping complex xml-schema. + * It is intended to be a minimal extension of the standard rules + * big enough to support complex schema but without the full generality + * offered by more exotic matching pattern rules.

+ * + *

When should you use this rather than the original?

+ * + *

+ * This pattern-matching engine is complex and slower than the basic + * default RulesBase class, but offers more functionality: + *

    + *
  • Universal patterns allow patterns to be specified which will match + * regardless of whether there are "better matching" patterns available.
  • + *
  • Parent-match patterns (eg "a/b/?") allow matching for all direct + * children of a specified element.
  • + *
  • Ancestor-match patterns (eg "a/b/*") allow matching all elements + * nested within a specified element to any nesting depth.
  • + *
  • Completely-wild patterns ("*" or "!*") allow matching all elements.
  • + *
+ *

+ * + *

Universal Match Patterns

+ * + *

The default RulesBase pattern-matching engine always attempts to find + * the "best matching pattern", and will ignore rules associated with other + * patterns that match but are not "as good". As an example, if the pattern + * "a/b/c" is associated with rules 1 and 2, and "*/c" is associated with + * rules 3 and 4 then element "a/b/c" will cause only rules 1 and 2 to execute. + * Rules 3 and 4 do have matching patterns, but because the patterns are shorter + * and include wildcard characters they are regarded as being "not as good" as + * a direct match. In general, exact patterns are better than wildcard patterns, + * and among multiple patterns with wildcards, the longest is preferred. + * See the RulesBase class for more information.

+ * + *

This feature of preferring "better" patterns can be a powerful tool. + * However it also means that patterns can interact in unexpected ways.

+ * + *

When using the ExtendedBaseRules, any pattern prefixed with '!' bypasses + * the "best match" feature. Even if there is an exact match or a longer + * wildcard match, patterns prefixed by '!' will still be tested to see if + * they match, and if so their associated Rule objects will be included in + * the set of rules to be executed in the normal manner.

+ * + *
    + *
  • Pattern "!*/a/b" matches whenever an 'b' element + * is inside an 'a'.
  • + *
  • Pattern "!a/b/?" matches any child of a parent + * matching "a/b" (see "Parent Match Patterns").
  • + *
  • Pattern "!*/a/b/?" matches any child of a parent + * matching "!*/a/b" (see "Parent Match Patterns").
  • + *
  • Pattern "!a/b/*" matches any element whose path + * starts with "a" then "b" (see "Ancestor Match Patterns").
  • + *
  • Pattern "!*/a/b/*" matches any elements whose path + * contains 'a/b' (see "Ancestor Match Patterns").
  • + *
+ * + *

Parent Match Patterns

+ * + *

+ * These will match direct child elements of a particular parent element. + *

    + *
  • + * "a/b/c/?" matches any child whose parent matches + * "a/b/c". Exact parent rules take precedence over Ancestor + * Match patterns. + *
  • + *
  • + * "*/a/b/c/?" matches any child whose parent matches + * "*/a/b/c". The longest matching still applies to parent + * matches but the length excludes the '?', which effectively means + * that standard wildcard matches with the same level of depth are + * chosen in preference. + *
  • + *
+ *

+ * + *

Ancestor Match Patterns

+ * + *

+ * These will match elements whose parentage includes a particular sequence + * of elements. + *

    + *
  • + * "a/b/*" matches any element whose path starts with + * 'a' then 'b'. Exact parent and parent match rules take precedence. + * The longest ancestor match will take precedence. + *
  • + *
  • + * "*/a/b/*" matches any elements whose path contains + * an element 'a' followed by an element 'b'. The longest matching still + * applies but the length excludes the '*' at the end. + *
  • + *
+ *

+ * + *

Completely Wild Patterns

+ * + *

Pattern "*" matches every pattern that isn't matched by + * any other basic rule.

+ * + *

Pattern "!*" matches every pattern.

+ * + *

Using The Extended Rules

+ * + *

By default, a Digester instance uses a {@link RulesBase} instance as + * its pattern matching engine. To use an ExtendedBaseRules instance, call + * the Digester.setRules method before adding any Rule objects to the digester + * instance: + *

+ *     Digester digester = new Digester();
+ *     digester.setRules( new ExtendedBaseRules() );
+ * 

+ * + *

The most important thing to remember when using the extended rules is + * that universal and non-universal patterns are completely independent. + * Universal patterns are never affected by the addition of new patterns + * or the removal of existing ones. Non-universal patterns are never affected + * by the addition of new universal patterns or the removal of + * existing universal patterns. As in the basic matching rules, + * non-universal (basic) patterns can be affected by the + * addition of new non-universal patterns or the removal of existing + * non-universal patterns, because only rules associated with the + * "best matching" pattern for each xml element are executed. + * + *

This means that you can use universal patterns to build up the simple + * parts of your structure - for example defining universal creation and + * property setting rules. More sophisticated and complex mapping will require + * non-universal patterns and this might mean that some of the universal rules + * will need to be replaced by a series of special cases using non-universal + * rules. But by using universal rules as your backbone, these additions + * should not break your existing rules.

+ */ + + +public class ExtendedBaseRules extends RulesBase { + + + // ----------------------------------------------------- Instance Variables + + /** + * Counts the entry number for the rules. + */ + private int counter = 0; + + + /** + * The decision algorithm used (unfortunately) doesn't preserve the entry + * order. + * This map is used by a comparator which orders the list of matches + * before it's returned. + * This map stores the entry number keyed by the rule. + */ + private Map order = new HashMap(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Register a new Rule instance matching the specified pattern. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + @Override + public void add(String pattern, Rule rule) { + super.add(pattern, rule); + counter++; + order.put(rule, counter); + } + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param pattern Nesting pattern to be matched + */ + @Override + public List match(String namespace, String pattern) { + // calculate the pattern of the parent + // (if the element has one) + String parentPattern = ""; + int lastIndex = pattern.lastIndexOf('/'); + + boolean hasParent = true; + if (lastIndex == -1) { + // element has no parent + hasParent = false; + + } else { + // calculate the pattern of the parent + parentPattern = pattern.substring(0, lastIndex); + + } + + + // we keep the list of universal matches separate + List universalList = new ArrayList(counter); + + // Universal all wildards ('!*') + // These are always matched so always add them + List tempList = this.cache.get("!*"); + if (tempList != null) { + universalList.addAll(tempList); + } + + // Universal exact parent match + // need to get this now since only wildcards are considered later + tempList = this.cache.get("!" + parentPattern + "/?"); + if (tempList != null) { + universalList.addAll(tempList); + } + + + // base behaviour means that if we certain matches, we don't continue + // but we just have a single combined loop and so we have to set + // a variable + boolean ignoreBasicMatches = false; + + + // see if we have an exact basic pattern match + List rulesList = this.cache.get(pattern); + if (rulesList != null) { + // we have a match! + // so ignore all basic matches from now on + ignoreBasicMatches = true; + + } else { + + // see if we have an exact child match + if (hasParent) { + // matching children takes preference + rulesList = this.cache.get(parentPattern + "/?"); + if (rulesList != null) { + // we have a match! + // so ignore all basic matches from now on + ignoreBasicMatches = true; + + } else { + // we don't have a match yet - so try exact ancester + // + rulesList = findExactAncesterMatch(pattern); + if (rulesList != null) { + // we have a match! + // so ignore all basic matches from now on + ignoreBasicMatches = true; + } + } + } + } + + + // OK - we're ready for the big loop! + // Unlike the basic rules case, + // we have to go through for all those universal rules in all cases. + + // Find the longest key, ie more discriminant + String longKey = ""; + int longKeyLength = 0; + + for (String key : this.cache.keySet()) { + + // find out if it's a univeral pattern + // set a flag + boolean isUniversal = key.startsWith("!"); + if (isUniversal) { + // and find the underlying key + key = key.substring(1, key.length()); + } + + + // don't need to check exact matches + boolean wildcardMatchStart = key.startsWith("*/"); + boolean wildcardMatchEnd = key.endsWith("/*"); + if (wildcardMatchStart || (isUniversal && wildcardMatchEnd)) { + + boolean parentMatched = false; + boolean basicMatched = false; + boolean ancesterMatched = false; + + boolean parentMatchEnd = key.endsWith("/?"); + if (parentMatchEnd) { + // try for a parent match + parentMatched = parentMatch(key, pattern, parentPattern); + + } else if (wildcardMatchEnd) { + // check for ancester match + if (wildcardMatchStart) { + String patternBody = key.substring(2, key.length() - 2); + if (pattern.endsWith(patternBody)) { + ancesterMatched = true; + } else { + ancesterMatched = (pattern.indexOf(patternBody + "/") > -1); + } + } else { + String bodyPattern = key.substring(0, key.length() - 2); + if (pattern.startsWith(bodyPattern)) + { + if (pattern.length() == bodyPattern.length()) { + // exact match + ancesterMatched = true; + } else { + ancesterMatched = ( pattern.charAt(bodyPattern.length()) == '/' ); + } + } else { + ancesterMatched = false; + } + } + } else { + // try for a base match + basicMatched = basicMatch(key, pattern); + } + + if (parentMatched || basicMatched || ancesterMatched) { + if (isUniversal) { + // universal rules go straight in + // (no longest matching rule) + tempList = this.cache.get("!" + key); + if (tempList != null) { + universalList.addAll(tempList); + } + + } else { + if (!ignoreBasicMatches) { + // ensure that all parent matches are SHORTER + // than rules with same level of matching. + // + // the calculations below don't work for universal + // matching, but we don't care because in that case + // this if-stmt is not entered. + int keyLength = key.length(); + if (wildcardMatchStart) { + --keyLength; + } + if (wildcardMatchEnd) { + --keyLength; + } else if (parentMatchEnd) { + --keyLength; + } + + if (keyLength > longKeyLength) { + rulesList = this.cache.get(key); + longKey = key; + longKeyLength = keyLength; + } + } + } + } + } + } + + + // '*' works in practice as a default matching + // (this is because anything is a deeper match!) + if (rulesList == null) { + rulesList = this.cache.get("*"); + } + + // if we've matched a basic pattern, then add to the universal list + if (rulesList != null) { + universalList.addAll(rulesList); + } + + + // don't filter if namespace is null + if (namespace != null) { + // remove invalid namespaces + Iterator it = universalList.iterator(); + while (it.hasNext()) { + Rule rule = it.next(); + String ns_uri = rule.getNamespaceURI(); + if (ns_uri != null && !ns_uri.equals(namespace)) { + it.remove(); + } + } + } + + + // need to make sure that the collection is sort in the order + // of addition. We use a custom comparator for this + Collections.sort( + universalList, + new Comparator() { + + public int compare(Rule r1, Rule r2) throws ClassCastException { + // Get the entry order from the map + Integer i1 = order.get(r1); + Integer i2 = order.get(r2); + + // and use that to perform the comparison + if (i1 == null) { + if (i2 == null) { + + return 0; + + } else { + + return -1; + + } + } else if (i2 == null) { + return 1; + } + + return (i1.intValue() - i2.intValue()); + } + }); + + return universalList; + } + + /** + * Matching parent. + */ + private boolean parentMatch(String key, String pattern, String parentPattern) { + return parentPattern.endsWith(key.substring(1, key.length() - 2)); + } + + /** + * Standard match. + * Matches the end of the pattern to the key. + */ + private boolean basicMatch(String key, String pattern) { + return (pattern.equals(key.substring(2)) || + pattern.endsWith(key.substring(1))); + } + + /** + * Finds an exact ancester match for given pattern + */ + private List findExactAncesterMatch(String parentPattern) { + List matchingRules = null; + int lastIndex = parentPattern.length(); + while (lastIndex-- > 0) { + lastIndex = parentPattern.lastIndexOf('/', lastIndex); + if (lastIndex > 0) { + matchingRules = this.cache.get(parentPattern.substring(0, lastIndex) + "/*"); + if (matchingRules != null) { + return matchingRules; + } + } + } + return null; + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/FactoryCreateRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/FactoryCreateRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/FactoryCreateRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,509 @@ +/* $Id: FactoryCreateRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + +import java.util.Stack; + +import org.xml.sax.Attributes; + + +/** + *

Rule implementation that uses an {@link ObjectCreationFactory} to create + * a new object which it pushes onto the object stack. When the element is + * complete, the object will be popped.

+ * + *

This rule is intended in situations where the element's attributes are + * needed before the object can be created. A common senario is for the + * ObjectCreationFactory implementation to use the attributes as parameters + * in a call to either a factory method or to a non-empty constructor. + */ + +public class FactoryCreateRule extends Rule { + + // ----------------------------------------------------------- Fields + + /** Should exceptions thrown by the factory be ignored? */ + private boolean ignoreCreateExceptions; + /** Stock to manage */ + private Stack exceptionIgnoredStack; + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a factory create rule that will use the specified + * class name to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack. + * + * @param digester The associated Digester + * @param className Java class name of the object creation factory class + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(String className)} instead. + */ + @Deprecated + public FactoryCreateRule(Digester digester, String className) { + + this(className); + + } + + + /** + * Construct a factory create rule that will use the specified + * class to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack. + * + * @param digester The associated Digester + * @param clazz Java class name of the object creation factory class + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(Class clazz)} instead. + */ + @Deprecated + public FactoryCreateRule(Digester digester, Class clazz) { + + this(clazz); + + } + + + /** + * Construct a factory create rule that will use the specified + * class name (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack. + * + * @param digester The associated Digester + * @param className Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(String className, String attributeName)} instead. + */ + @Deprecated + public FactoryCreateRule(Digester digester, + String className, String attributeName) { + + this(className, attributeName); + + } + + + /** + * Construct a factory create rule that will use the specified + * class (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack. + * + * @param digester The associated Digester + * @param clazz Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(Class clazz, String attributeName)} instead. + */ + @Deprecated + public FactoryCreateRule(Digester digester, + Class clazz, String attributeName) { + + this(clazz, attributeName); + + } + + + /** + * Construct a factory create rule using the given, already instantiated, + * {@link ObjectCreationFactory}. + * + * @param digester The associated Digester + * @param creationFactory called on to create the object. + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(ObjectCreationFactory creationFactory)} instead. + */ + @Deprecated + public FactoryCreateRule(Digester digester, + ObjectCreationFactory creationFactory) { + + this(creationFactory); + + } + + /** + *

Construct a factory create rule that will use the specified + * class name to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack.

+ * + *

Exceptions thrown during the object creation process will be propagated.

+ * + * @param className Java class name of the object creation factory class + */ + public FactoryCreateRule(String className) { + + this(className, false); + + } + + + /** + *

Construct a factory create rule that will use the specified + * class to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack.

+ * + *

Exceptions thrown during the object creation process will be propagated.

+ * + * @param clazz Java class name of the object creation factory class + */ + public FactoryCreateRule(Class clazz) { + + this(clazz, false); + + } + + + /** + *

Construct a factory create rule that will use the specified + * class name (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack.

+ * + *

Exceptions thrown during the object creation process will be propagated.

+ * + * @param className Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + */ + public FactoryCreateRule(String className, String attributeName) { + + this(className, attributeName, false); + + } + + + /** + *

Construct a factory create rule that will use the specified + * class (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack.

+ * + *

Exceptions thrown during the object creation process will be propagated.

+ * + * @param clazz Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + */ + public FactoryCreateRule(Class clazz, String attributeName) { + + this(clazz, attributeName, false); + + } + + + /** + *

Construct a factory create rule using the given, already instantiated, + * {@link ObjectCreationFactory}.

+ * + *

Exceptions thrown during the object creation process will be propagated.

+ * + * @param creationFactory called on to create the object. + */ + public FactoryCreateRule(ObjectCreationFactory creationFactory) { + + this(creationFactory, false); + + } + + /** + * Construct a factory create rule that will use the specified + * class name to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack. + * + * @param className Java class name of the object creation factory class + * @param ignoreCreateExceptions if true, exceptions thrown by the object + * creation factory + * will be ignored. + */ + public FactoryCreateRule(String className, boolean ignoreCreateExceptions) { + + this(className, null, ignoreCreateExceptions); + + } + + + /** + * Construct a factory create rule that will use the specified + * class to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack. + * + * @param clazz Java class name of the object creation factory class + * @param ignoreCreateExceptions if true, exceptions thrown by the + * object creation factory + * will be ignored. + */ + public FactoryCreateRule(Class clazz, boolean ignoreCreateExceptions) { + + this(clazz, null, ignoreCreateExceptions); + + } + + + /** + * Construct a factory create rule that will use the specified + * class name (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack. + * + * @param className Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + * @param ignoreCreateExceptions if true, exceptions thrown by the object + * creation factory will be ignored. + */ + public FactoryCreateRule( + String className, + String attributeName, + boolean ignoreCreateExceptions) { + + this.className = className; + this.attributeName = attributeName; + this.ignoreCreateExceptions = ignoreCreateExceptions; + + } + + + /** + * Construct a factory create rule that will use the specified + * class (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack. + * + * @param clazz Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + * @param ignoreCreateExceptions if true, exceptions thrown by the object + * creation factory will be ignored. + */ + public FactoryCreateRule( + Class clazz, + String attributeName, + boolean ignoreCreateExceptions) { + + this(clazz.getName(), attributeName, ignoreCreateExceptions); + + } + + + /** + * Construct a factory create rule using the given, already instantiated, + * {@link ObjectCreationFactory}. + * + * @param creationFactory called on to create the object. + * @param ignoreCreateExceptions if true, exceptions thrown by the object + * creation factory will be ignored. + */ + public FactoryCreateRule( + ObjectCreationFactory creationFactory, + boolean ignoreCreateExceptions) { + + this.creationFactory = creationFactory; + this.ignoreCreateExceptions = ignoreCreateExceptions; + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The attribute containing an override class name if it is present. + */ + protected String attributeName = null; + + + /** + * The Java class name of the ObjectCreationFactory to be created. + * This class must have a no-arguments constructor. + */ + protected String className = null; + + + /** + * The object creation factory we will use to instantiate objects + * as required based on the attributes specified in the matched XML + * element. + */ + protected ObjectCreationFactory creationFactory = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the beginning of this element. + * + * @param attributes The attribute list of this element + */ + @Override + public void begin(String namespace, String name, Attributes attributes) throws Exception { + + if (ignoreCreateExceptions) { + + if (exceptionIgnoredStack == null) { + exceptionIgnoredStack = new Stack(); + } + + try { + Object instance = getFactory(attributes).createObject(attributes); + + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule]{" + digester.match + + "} New " + (instance == null ? "null object" : + instance.getClass().getName())); + } + digester.push(instance); + exceptionIgnoredStack.push(Boolean.FALSE); + + } catch (Exception e) { + // log message and error + if (digester.log.isInfoEnabled()) { + digester.log.info("[FactoryCreateRule] Create exception ignored: " + + ((e.getMessage() == null) ? e.getClass().getName() : e.getMessage())); + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule] Ignored exception:", e); + } + } + exceptionIgnoredStack.push(Boolean.TRUE); + } + + } else { + Object instance = getFactory(attributes).createObject(attributes); + + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule]{" + digester.match + + "} New " + (instance == null ? "null object" : + instance.getClass().getName())); + } + digester.push(instance); + } + } + + + /** + * Process the end of this element. + */ + @Override + public void end(String namespace, String name) throws Exception { + + // check if object was created + // this only happens if an exception was thrown and we're ignoring them + if ( + ignoreCreateExceptions && + exceptionIgnoredStack != null && + !(exceptionIgnoredStack.empty())) { + + if (exceptionIgnoredStack.pop().booleanValue()) { + // creation exception was ignored + // nothing was put onto the stack + if (digester.log.isTraceEnabled()) { + digester.log.trace("[FactoryCreateRule] No creation so no push so no pop"); + } + return; + } + } + + Object top = digester.pop(); + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule]{" + digester.match + + "} Pop " + top.getClass().getName()); + } + + } + + + /** + * Clean up after parsing is complete. + */ + @Override + public void finish() throws Exception { + + if (attributeName != null) { + creationFactory = null; + } + + } + + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("FactoryCreateRule["); + sb.append("className="); + sb.append(className); + sb.append(", attributeName="); + sb.append(attributeName); + if (creationFactory != null) { + sb.append(", creationFactory="); + sb.append(creationFactory); + } + sb.append("]"); + return (sb.toString()); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return an instance of our associated object creation factory, + * creating one if necessary. + * + * @param attributes Attributes passed to our factory creation element + * + * @exception Exception if any error occurs + */ + protected ObjectCreationFactory getFactory(Attributes attributes) + throws Exception { + + if (creationFactory == null) { + String realClassName = className; + if (attributeName != null) { + String value = attributes.getValue(attributeName); + if (value != null) { + realClassName = value; + } + } + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule]{" + digester.match + + "} New factory " + realClassName); + } + Class clazz = digester.getClassLoader().loadClass(realClassName); + creationFactory = (ObjectCreationFactory) + clazz.newInstance(); + creationFactory.setDigester(digester); + } + return (creationFactory); + + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/NodeCreateRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/NodeCreateRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/NodeCreateRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,479 @@ +/* $Id: NodeCreateRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + + +/** + * A rule implementation that creates a DOM + * {@link org.w3c.dom.Node Node} containing the XML at the element that matched + * the rule. Two concrete types of nodes can be created by this rule: + *
    + *
  • the default is to create an {@link org.w3c.dom.Element Element} node. + * The created element will correspond to the element that matched the rule, + * containing all XML content underneath that element.
  • + *
  • alternatively, this rule can create nodes of type + * {@link org.w3c.dom.DocumentFragment DocumentFragment}, which will contain + * only the XML content under the element the rule was trigged on.
  • + *
+ * The created node will be normalized, meaning it will not contain text nodes + * that only contain white space characters. + * + + * + *

The created Node will be pushed on Digester's object stack + * when done. To use it in the context of another DOM + * {@link org.w3c.dom.Document Document}, it must be imported first, using the + * Document method + * {@link org.w3c.dom.Document#importNode(org.w3c.dom.Node, boolean) importNode()}. + *

+ * + *

Important Note: This is implemented by replacing the SAX + * {@link org.xml.sax.ContentHandler ContentHandler} in the parser used by + * Digester, and resetting it when the matched element is closed. As a side + * effect, rules that would match XML nodes under the element that matches + * a NodeCreateRule will never be triggered by Digester, which + * usually is the behavior one would expect.

+ * + *

Note that the current implementation does not set the namespace prefixes + * in the exported nodes. The (usually more important) namespace URIs are set, + * of course.

+ * + * @since Digester 1.4 + */ + +public class NodeCreateRule extends Rule { + + + // ---------------------------------------------------------- Inner Classes + + + /** + * The SAX content handler that does all the actual work of assembling the + * DOM node tree from the SAX events. + */ + private class NodeBuilder + extends DefaultHandler { + + + // ------------------------------------------------------- Constructors + + + /** + * Constructor. + * + *

Stores the content handler currently used by Digester so it can + * be reset when done, and initializes the DOM objects needed to + * build the node.

+ * + * @param doc the document to use to create nodes + * @param root the root node + * @throws ParserConfigurationException if the DocumentBuilderFactory + * could not be instantiated + * @throws SAXException if the XMLReader could not be instantiated by + * Digester (should not happen) + */ + public NodeBuilder(Document doc, Node root) + throws ParserConfigurationException, SAXException { + + this.doc = doc; + this.root = root; + this.top = root; + + oldContentHandler = digester.getCustomContentHandler(); + + } + + + // ------------------------------------------------- Instance Variables + + + /** + * The content handler used by Digester before it was set to this + * content handler. + */ + protected ContentHandler oldContentHandler = null; + + + /** + * Depth of the current node, relative to the element where the content + * handler was put into action. + */ + protected int depth = 0; + + + /** + * A DOM Document used to create the various Node instances. + */ + protected Document doc = null; + + + /** + * The DOM node that will be pushed on Digester's stack. + */ + protected Node root = null; + + + /** + * The current top DOM mode. + */ + protected Node top = null; + + /** + * The text content of the current top DOM node. + */ + protected StringBuffer topText = new StringBuffer(); + + + // --------------------------------------------- Helper Methods + + /** + * Appends a {@link org.w3c.dom.Text Text} node to the current node + * if the content reported by the parser is not purely whitespace. + */ + private void addTextIfPresent() throws SAXException { + if (topText.length() > 0) { + String str = topText.toString(); + topText.setLength(0); + + if (str.trim().length() > 0) { + // The contained text is not *pure* whitespace, so create + // a text node to hold it. Note that the "untrimmed" text + // is stored in the node. + try { + top.appendChild(doc.createTextNode(str)); + } catch (DOMException e) { + throw new SAXException(e.getMessage()); + } + } + } + } + + // --------------------------------------------- ContentHandler Methods + + + /** + * Handle notification about text embedded within the current node. + *

+ * An xml parser calls this when text is found. We need to ensure that this + * text gets attached to the new Node we are creating - except in the case + * where the only text in the node is whitespace. + *

+ * There is a catch, however. According to the sax specification, a parser + * does not need to pass all of the text content of a node in one go; it can + * make multiple calls passing part of the data on each call. In particular, + * when the body of an element includes xml entity-references, at least some + * parsers make a separate call to this method to pass just the entity content. + *

+ * In this method, we therefore just append the provided text to a + * "current text" buffer. When the element end is found, or a child element + * is found then we can check whether we have all-whitespace. See method + * addTextIfPresent. + * + * @param ch the characters from the XML document + * @param start the start position in the array + * @param length the number of characters to read from the array + * @throws SAXException if the DOM implementation throws an exception + */ + @Override + public void characters(char[] ch, int start, int length) + throws SAXException { + + topText.append(ch, start, length); + } + + + /** + * Checks whether control needs to be returned to Digester. + * + * @param namespaceURI the namespace URI + * @param localName the local name + * @param qName the qualified (prefixed) name + * @throws SAXException if the DOM implementation throws an exception + */ + @Override + public void endElement(String namespaceURI, String localName, + String qName) + throws SAXException { + + addTextIfPresent(); + + try { + if (depth == 0) { + getDigester().setCustomContentHandler(oldContentHandler); + getDigester().push(root); + getDigester().endElement(namespaceURI, localName, qName); + } + + top = top.getParentNode(); + depth--; + } catch (DOMException e) { + throw new SAXException(e.getMessage()); + } + + } + + + /** + * Adds a new + * {@link org.w3c.dom.ProcessingInstruction ProcessingInstruction} to + * the current node. + * + * @param target the processing instruction target + * @param data the processing instruction data, or null if none was + * supplied + * @throws SAXException if the DOM implementation throws an exception + */ + @Override + public void processingInstruction(String target, String data) + throws SAXException { + + try { + top.appendChild(doc.createProcessingInstruction(target, data)); + } catch (DOMException e) { + throw new SAXException(e.getMessage()); + } + + } + + + /** + * Adds a new child {@link org.w3c.dom.Element Element} to the current + * node. + * + * @param namespaceURI the namespace URI + * @param localName the local name + * @param qName the qualified (prefixed) name + * @param atts the list of attributes + * @throws SAXException if the DOM implementation throws an exception + */ + @Override + public void startElement(String namespaceURI, String localName, + String qName, Attributes atts) + throws SAXException { + + addTextIfPresent(); + + try { + Node previousTop = top; + if ((localName == null) || (localName.length() == 0)) { + top = doc.createElement(qName); + } else { + top = doc.createElementNS(namespaceURI, localName); + } + for (int i = 0; i < atts.getLength(); i++) { + Attr attr = null; + if ((atts.getLocalName(i) == null) || + (atts.getLocalName(i).length() == 0)) { + attr = doc.createAttribute(atts.getQName(i)); + attr.setNodeValue(atts.getValue(i)); + ((Element)top).setAttributeNode(attr); + } else { + attr = doc.createAttributeNS(atts.getURI(i), + atts.getLocalName(i)); + attr.setNodeValue(atts.getValue(i)); + ((Element)top).setAttributeNodeNS(attr); + } + } + previousTop.appendChild(top); + depth++; + } catch (DOMException e) { + throw new SAXException(e.getMessage()); + } + + } + + } + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. Creates an instance of this rule that will create a + * DOM {@link org.w3c.dom.Element Element}. + */ + public NodeCreateRule() throws ParserConfigurationException { + + this(Node.ELEMENT_NODE); + + } + + + /** + * Constructor. Creates an instance of this rule that will create a DOM + * {@link org.w3c.dom.Element Element}, but lets you specify the JAXP + * DocumentBuilder that should be used when constructing the + * node tree. + * + * @param documentBuilder the JAXP DocumentBuilder to use + */ + public NodeCreateRule(DocumentBuilder documentBuilder) { + + this(Node.ELEMENT_NODE, documentBuilder); + + } + + + /** + * Constructor. Creates an instance of this rule that will create either a + * DOM {@link org.w3c.dom.Element Element} or a DOM + * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the + * value of the nodeType parameter. + * + * @param nodeType the type of node to create, which can be either + * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or + * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} + * @throws IllegalArgumentException if the node type is not supported + */ + public NodeCreateRule(int nodeType) throws ParserConfigurationException { + + this(nodeType, + DocumentBuilderFactory.newInstance().newDocumentBuilder()); + + } + + + /** + * Constructor. Creates an instance of this rule that will create either a + * DOM {@link org.w3c.dom.Element Element} or a DOM + * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the + * value of the nodeType parameter. This constructor lets you + * specify the JAXP DocumentBuilder that should be used when + * constructing the node tree. + * + * @param nodeType the type of node to create, which can be either + * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or + * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} + * @param documentBuilder the JAXP DocumentBuilder to use + * @throws IllegalArgumentException if the node type is not supported + */ + public NodeCreateRule(int nodeType, DocumentBuilder documentBuilder) { + + if (!((nodeType == Node.DOCUMENT_FRAGMENT_NODE) || + (nodeType == Node.ELEMENT_NODE))) { + throw new IllegalArgumentException( + "Can only create nodes of type DocumentFragment and Element"); + } + this.nodeType = nodeType; + this.documentBuilder = documentBuilder; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The JAXP DocumentBuilder to use. + */ + private DocumentBuilder documentBuilder = null; + + + /** + * The type of the node that should be created. Must be one of the + * constants defined in {@link org.w3c.dom.Node Node}, but currently only + * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} and + * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} + * are allowed values. + */ + private int nodeType = Node.ELEMENT_NODE; + + + // ----------------------------------------------------------- Rule Methods + + + /** + * When this method fires, the digester is told to forward all SAX + * ContentHandler events to the builder object, resulting in a DOM being + * built instead of normal digester rule-handling occurring. When the + * end of the current xml element is encountered, the original content + * handler is restored (expected to be NULL, allowing normal Digester + * operations to continue). + * + * @param namespaceURI the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @param attributes The attribute list of this element + * @throws Exception indicates a JAXP configuration problem + */ + @Override + public void begin(String namespaceURI, String name, Attributes attributes) + throws Exception { + + Document doc = documentBuilder.newDocument(); + NodeBuilder builder = null; + if (nodeType == Node.ELEMENT_NODE) { + Element element = null; + if (getDigester().getNamespaceAware()) { + element = + doc.createElementNS(namespaceURI, name); + for (int i = 0; i < attributes.getLength(); i++) { + element.setAttributeNS(attributes.getURI(i), + attributes.getQName(i), + attributes.getValue(i)); + } + } else { + element = doc.createElement(name); + for (int i = 0; i < attributes.getLength(); i++) { + element.setAttribute(attributes.getQName(i), + attributes.getValue(i)); + } + } + builder = new NodeBuilder(doc, element); + } else { + builder = new NodeBuilder(doc, doc.createDocumentFragment()); + } + // the NodeBuilder constructor has already saved the original + // value of the digester's custom content handler (expected to + // be null, but we save it just in case). So now we just + // need to tell the digester to forward events to the builder. + getDigester().setCustomContentHandler(builder); + } + + + /** + * Pop the Node off the top of the stack. + */ + @Override + public void end() throws Exception { + + digester.pop(); + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/ObjectCreateRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/ObjectCreateRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/ObjectCreateRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,249 @@ +/* $Id: ObjectCreateRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import org.xml.sax.Attributes; + + +/** + * Rule implementation that creates a new object and pushes it + * onto the object stack. When the element is complete, the + * object will be popped + */ + +public class ObjectCreateRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct an object create rule with the specified class name. + * + * @param digester The associated Digester + * @param className Java class name of the object to be created + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #ObjectCreateRule(String className)} instead. + */ + @Deprecated + public ObjectCreateRule(Digester digester, String className) { + + this(className); + + } + + + /** + * Construct an object create rule with the specified class. + * + * @param digester The associated Digester + * @param clazz Java class name of the object to be created + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #ObjectCreateRule(Class clazz)} instead. + */ + @Deprecated + public ObjectCreateRule(Digester digester, Class clazz) { + + this(clazz); + + } + + + /** + * Construct an object create rule with the specified class name and an + * optional attribute name containing an override. + * + * @param digester The associated Digester + * @param className Java class name of the object to be created + * @param attributeName Attribute name which, if present, contains an + * override of the class name to create + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #ObjectCreateRule(String className, String attributeName)} instead. + */ + @Deprecated + public ObjectCreateRule(Digester digester, String className, + String attributeName) { + + this (className, attributeName); + + } + + + /** + * Construct an object create rule with the specified class and an + * optional attribute name containing an override. + * + * @param digester The associated Digester + * @param attributeName Attribute name which, if present, contains an + * @param clazz Java class name of the object to be created + * override of the class name to create + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #ObjectCreateRule(String attributeName, Class clazz)} instead. + */ + @Deprecated + public ObjectCreateRule(Digester digester, + String attributeName, + Class clazz) { + + this(attributeName, clazz); + + } + + /** + * Construct an object create rule with the specified class name. + * + * @param className Java class name of the object to be created + */ + public ObjectCreateRule(String className) { + + this(className, (String) null); + + } + + + /** + * Construct an object create rule with the specified class. + * + * @param clazz Java class name of the object to be created + */ + public ObjectCreateRule(Class clazz) { + + this(clazz.getName(), (String) null); + + } + + + /** + * Construct an object create rule with the specified class name and an + * optional attribute name containing an override. + * + * @param className Java class name of the object to be created + * @param attributeName Attribute name which, if present, contains an + * override of the class name to create + */ + public ObjectCreateRule(String className, + String attributeName) { + + this.className = className; + this.attributeName = attributeName; + + } + + + /** + * Construct an object create rule with the specified class and an + * optional attribute name containing an override. + * + * @param attributeName Attribute name which, if present, contains an + * @param clazz Java class name of the object to be created + * override of the class name to create + */ + public ObjectCreateRule(String attributeName, + Class clazz) { + + this(clazz.getName(), attributeName); + + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The attribute containing an override class name if it is present. + */ + protected String attributeName = null; + + + /** + * The Java class name of the object to be created. + */ + protected String className = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the beginning of this element. + * + * @param attributes The attribute list of this element + */ + @Override + public void begin(Attributes attributes) throws Exception { + + // Identify the name of the class to instantiate + String realClassName = className; + if (attributeName != null) { + String value = attributes.getValue(attributeName); + if (value != null) { + realClassName = value; + } + } + if (digester.log.isDebugEnabled()) { + digester.log.debug("[ObjectCreateRule]{" + digester.match + + "}New " + realClassName); + } + + // Instantiate the new object and push it on the context stack + Class clazz = digester.getClassLoader().loadClass(realClassName); + Object instance = clazz.newInstance(); + digester.push(instance); + + } + + + /** + * Process the end of this element. + */ + @Override + public void end() throws Exception { + + Object top = digester.pop(); + if (digester.log.isDebugEnabled()) { + digester.log.debug("[ObjectCreateRule]{" + digester.match + + "} Pop " + top.getClass().getName()); + } + + } + + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("ObjectCreateRule["); + sb.append("className="); + sb.append(className); + sb.append(", attributeName="); + sb.append(attributeName); + sb.append("]"); + return (sb.toString()); + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/ObjectCreationFactory.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/ObjectCreationFactory.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/ObjectCreationFactory.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,60 @@ +/* $Id: ObjectCreationFactory.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester; + + +import org.xml.sax.Attributes; + +/** + *

Interface for use with {@link FactoryCreateRule}. + * The rule calls {@link #createObject} to create an object + * to be pushed onto the Digester stack + * whenever it is matched.

+ * + *

{@link AbstractObjectCreationFactory} is an abstract + * implementation suitable for creating anonymous + * ObjectCreationFactory implementations. + */ +public interface ObjectCreationFactory { + + /** + *

Factory method called by {@link FactoryCreateRule} to supply an + * object based on the element's attributes. + * + * @param attributes the element's attributes + * + * @throws Exception any exception thrown will be propagated upwards + */ + public Object createObject(Attributes attributes) throws Exception; + + /** + *

Returns the {@link Digester} that was set by the + * {@link FactoryCreateRule} upon initialization. + */ + public Digester getDigester(); + + /** + *

Set the {@link Digester} to allow the implementation to do logging, + * classloading based on the digester's classloader, etc. + * + * @param digester parent Digester object + */ + public void setDigester(Digester digester); + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/ObjectParamRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/ObjectParamRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/ObjectParamRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,129 @@ +/* $Id: ObjectParamRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + +import org.xml.sax.Attributes; + +/** + *

Rule implementation that saves a parameter for use by a surrounding + * CallMethodRule.

+ * + *

This parameter may be: + *

    + *
  • an arbitrary Object defined programatically, assigned when the element + * pattern associated with the Rule is matched. See + * {@link #ObjectParamRule(int paramIndex, Object param)}. + *
  • an arbitrary Object defined programatically, assigned if the element + * pattern AND specified attribute name are matched. See + * {@link #ObjectParamRule(int paramIndex, String attributeName, Object param)}. + *
+ *

+ * + * @since 1.4 + */ + +public class ObjectParamRule extends Rule { + // ----------------------------------------------------------- Constructors + /** + * Construct a "call parameter" rule that will save the given Object as + * the parameter value. + * + * @param paramIndex The zero-relative parameter number + * @param param the parameter to pass along + */ + public ObjectParamRule(int paramIndex, Object param) { + this(paramIndex, null, param); + } + + + /** + * Construct a "call parameter" rule that will save the given Object as + * the parameter value, provided that the specified attribute exists. + * + * @param paramIndex The zero-relative parameter number + * @param attributeName The name of the attribute to match + * @param param the parameter to pass along + */ + public ObjectParamRule(int paramIndex, String attributeName, Object param) { + this.paramIndex = paramIndex; + this.attributeName = attributeName; + this.param = param; + } + + + // ----------------------------------------------------- Instance Variables + + /** + * The attribute which we are attempting to match + */ + protected String attributeName = null; + + /** + * The zero-relative index of the parameter we are saving. + */ + protected int paramIndex = 0; + + /** + * The parameter we wish to pass to the method call + */ + protected Object param = null; + + + // --------------------------------------------------------- Public Methods + + /** + * Process the start of this element. + * + * @param attributes The attribute list for this element + */ + @Override + public void begin(String namespace, String name, + Attributes attributes) throws Exception { + Object anAttribute = null; + Object parameters[] = (Object[]) digester.peekParams(); + + if (attributeName != null) { + anAttribute = attributes.getValue(attributeName); + if(anAttribute != null) { + parameters[paramIndex] = param; + } + // note -- if attributeName != null and anAttribute == null, this rule + // will pass null as its parameter! + }else{ + parameters[paramIndex] = param; + } + } + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + StringBuffer sb = new StringBuffer("ObjectParamRule["); + sb.append("paramIndex="); + sb.append(paramIndex); + sb.append(", attributeName="); + sb.append(attributeName); + sb.append(", param="); + sb.append(param); + sb.append("]"); + return (sb.toString()); + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/ParserFeatureSetterFactory.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/ParserFeatureSetterFactory.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/ParserFeatureSetterFactory.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,88 @@ +/* $Id: ParserFeatureSetterFactory.java 992075 2010-09-02 19:43:25Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + +import java.util.Properties; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.commons.digester.parser.GenericParser; +import org.apache.commons.digester.parser.XercesParser; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * Creates a SAXParser based on the underlying parser. + * Allows logical properties depending on logical parser versions + * to be set. + * + * @since 1.6 + * @deprecated Create an XMLParser instance yourself, configure validation + * appropriately, and pass it as a parameter to the + * {@link Digester} constructor, or use + * {@link Digester#setXMLSchema(javax.xml.validation.Schema)} for validation. + */ +@Deprecated +public class ParserFeatureSetterFactory { + + /** + * true is Xerces is used. + */ + private static boolean isXercesUsed; + + static { + try{ + // Use reflection to avoid a build dependency with Xerces. + // + // Note that this does not detect Sun's repackaging of + // Xerces as com.sun.org.apache.xerces; perhaps it should? + SAXParserFactory factory = SAXParserFactory.newInstance(); + if (factory.getClass().getName().startsWith("org.apache.xerces")) { + isXercesUsed = true; + } + } catch (Exception ex) { + isXercesUsed = false; + } + } + + /** + * Create a new SAXParser + * @param properties (logical) properties to be set on parser + * @return a SAXParser configured based on the underlying + * parser implementation. + */ + public static SAXParser newSAXParser(Properties properties) + throws ParserConfigurationException, + SAXException, + SAXNotRecognizedException, + SAXNotSupportedException { + + if (isXercesUsed){ + return XercesParser.newSAXParser(properties); + } else { + return GenericParser.newSAXParser(properties); + } + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/PathCallParamRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/PathCallParamRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/PathCallParamRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,96 @@ +/* $Id: PathCallParamRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import org.xml.sax.Attributes; + +/** + *

Rule implementation that saves a parameter containing the + * Digester matching path for use by a surrounding + * CallMethodRule. This Rule is most useful when making + * extensive use of wildcards in rule patterns.

+ * + * @since 1.6 + */ + +public class PathCallParamRule extends Rule { + + // ----------------------------------------------------------- Constructors + + /** + * Construct a "call parameter" rule that will save the body text of this + * element as the parameter value. + * + * @param paramIndex The zero-relative parameter number + */ + public PathCallParamRule(int paramIndex) { + + this.paramIndex = paramIndex; + + } + + // ----------------------------------------------------- Instance Variables + + /** + * The zero-relative index of the parameter we are saving. + */ + protected int paramIndex = 0; + + // --------------------------------------------------------- Public Methods + + + /** + * Process the start of this element. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @param attributes The attribute list for this element + + */ + @Override + public void begin(String namespace, String name, Attributes attributes) throws Exception { + + String param = getDigester().getMatch(); + + if(param != null) { + Object parameters[] = (Object[]) digester.peekParams(); + parameters[paramIndex] = param; + } + + } + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("PathCallParamRule["); + sb.append("paramIndex="); + sb.append(paramIndex); + sb.append("]"); + return (sb.toString()); + + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/RegexMatcher.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/RegexMatcher.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/RegexMatcher.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,40 @@ +/* $Id: RegexMatcher.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester; + + +/** + * Regular expression matching strategy for RegexRules. + * + * @since 1.5 + */ + +abstract public class RegexMatcher { + + /** + * Returns true if the given pattern matches the given path + * according to the regex algorithm that this strategy applies. + * + * @param pathPattern the standard digester path representing the element + * @param rulePattern the regex pattern the path will be tested against + * @return true if the given pattern matches the given path + */ + abstract public boolean match(String pathPattern, String rulePattern); + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/RegexRules.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/RegexRules.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/RegexRules.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,155 @@ +/* $Id: RegexRules.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester; + +import java.util.ArrayList; +import java.util.List; + +/** + *

Rules implementation that uses regular expression matching for paths.

+ * + *

The regex implementation is pluggable, allowing different strategies to be used. + * The basic way that this class work does not vary. + * All patterns are tested to see if they match the path using the regex matcher. + * All those that do are return in the order which the rules were added.

+ * + * @since 1.5 + */ + +public class RegexRules extends AbstractRulesImpl { + + // --------------------------------------------------------- Fields + + /** All registered Rule's */ + private ArrayList registeredRules = new ArrayList(); + /** The regex strategy used by this RegexRules */ + private RegexMatcher matcher; + + // --------------------------------------------------------- Constructor + + /** + * Construct sets the Regex matching strategy. + * + * @param matcher the regex strategy to be used, not null + * @throws IllegalArgumentException if the strategy is null + */ + public RegexRules(RegexMatcher matcher) { + setRegexMatcher(matcher); + } + + // --------------------------------------------------------- Properties + + /** + * Gets the current regex matching strategy. + */ + public RegexMatcher getRegexMatcher() { + return matcher; + } + + /** + * Sets the current regex matching strategy. + * + * @param matcher use this RegexMatcher, not null + * @throws IllegalArgumentException if the strategy is null + */ + public void setRegexMatcher(RegexMatcher matcher) { + if (matcher == null) { + throw new IllegalArgumentException("RegexMatcher must not be null."); + } + this.matcher = matcher; + } + + // --------------------------------------------------------- Public Methods + + /** + * Register a new Rule instance matching the specified pattern. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + @Override + protected void registerRule(String pattern, Rule rule) { + registeredRules.add(new RegisteredRule(pattern, rule)); + } + + /** + * Clear all existing Rule instance registrations. + */ + @Override + public void clear() { + registeredRules.clear(); + } + + /** + * Finds matching rules by using current regex matching strategy. + * The rule associated with each path that matches is added to the list of matches. + * The order of matching rules is the same order that they were added. + * + * @param namespaceURI Namespace URI for which to select matching rules, + * or null to match regardless of namespace URI + * @param pattern Nesting pattern to be matched + * @return a list of matching Rule's + */ + @Override + public List match(String namespaceURI, String pattern) { + // + // not a particularly quick implementation + // regex is probably going to be slower than string equality + // so probably should have a set of strings + // and test each only once + // + // XXX FIX ME - Time And Optimize + // + ArrayList rules = new ArrayList(registeredRules.size()); + for (RegisteredRule rr : registeredRules) { + if (matcher.match(pattern, rr.pattern)) { + rules.add(rr.rule); + } + } + return rules; + } + + + /** + * Return a List of all registered Rule instances, or a zero-length List + * if there are no registered Rule instances. If more than one Rule + * instance has been registered, they must be returned + * in the order originally registered through the add() + * method. + */ + @Override + public List rules() { + ArrayList rules = new ArrayList(registeredRules.size()); + for (RegisteredRule rr : registeredRules) { + rules.add(rr.rule); + } + return rules; + } + + /** Used to associate rules with paths in the rules list */ + private class RegisteredRule { + String pattern; + Rule rule; + + RegisteredRule(String pattern, Rule rule) { + this.pattern = pattern; + this.rule = rule; + } + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/Rule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/Rule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/Rule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,273 @@ +/* $Id: Rule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import org.xml.sax.Attributes; + + +/** + * Concrete implementations of this class implement actions to be taken when + * a corresponding nested pattern of XML elements has been matched. + *

+ * Writing a custom Rule is considered perfectly normal when using Digester, + * and is encouraged whenever the default set of Rule classes don't meet your + * requirements; the digester framework can help process xml even when the + * built-in rules aren't quite what is needed. Creating a custom Rule is + * just as easy as subclassing javax.servlet.http.HttpServlet for webapps, + * or javax.swing.Action for GUI applications. + *

+ * If a rule wishes to manipulate a digester stack (the default object stack, + * a named stack, or the parameter stack) then it should only ever push + * objects in the rule's begin method and always pop exactly the same + * number of objects off the stack during the rule's end method. Of course + * peeking at the objects on the stacks can be done from anywhere. + *

+ * Rule objects should be stateless, ie they should not update any instance + * member during the parsing process. A rule instance that changes state + * will encounter problems if invoked in a "nested" manner; this can happen + * if the same instance is added to digester multiple times or if a + * wildcard pattern is used which can match both an element and a child of the + * same element. The digester object stack and named stacks should be used to + * store any state that a rule requires, making the rule class safe under all + * possible uses. + */ + +public abstract class Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Constructor sets the associated Digester. + * + * @param digester The digester with which this rule is associated + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. Use {@link #Rule()} instead. + */ + @Deprecated + public Rule(Digester digester) { + + super(); + setDigester(digester); + + } + + /** + *

Base constructor. + * Now the digester will be set when the rule is added.

+ */ + public Rule() {} + + + // ----------------------------------------------------- Instance Variables + + + /** + * The Digester with which this Rule is associated. + */ + protected Digester digester = null; + + + /** + * The namespace URI for which this Rule is relevant, if any. + */ + protected String namespaceURI = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Digester with which this Rule is associated. + */ + public Digester getDigester() { + + return (this.digester); + + } + + /** + * Set the Digester with which this Rule is associated. + */ + public void setDigester(Digester digester) { + + this.digester = digester; + + } + + /** + * Return the namespace URI for which this Rule is relevant, if any. + */ + public String getNamespaceURI() { + + return (this.namespaceURI); + + } + + + /** + * Set the namespace URI for which this Rule is relevant, if any. + * + * @param namespaceURI Namespace URI for which this Rule is relevant, + * or null to match independent of namespace. + */ + public void setNamespaceURI(String namespaceURI) { + + this.namespaceURI = namespaceURI; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * This method is called when the beginning of a matching XML element + * is encountered. + * + * @param attributes The attribute list of this element + * @deprecated Use the {@link #begin(String,String,Attributes) begin} + * method with namespace and name + * parameters instead. + */ + @Deprecated + public void begin(Attributes attributes) throws Exception { + + // The default implementation does nothing + + } + + + /** + * This method is called when the beginning of a matching XML element + * is encountered. The default implementation delegates to the deprecated + * method {@link #begin(Attributes) begin} without the + * namespace and name parameters, to retain + * backwards compatibility. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @param attributes The attribute list of this element + * @since Digester 1.4 + */ + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + + begin(attributes); + + } + + + /** + * This method is called when the body of a matching XML element + * is encountered. If the element has no body, this method is + * called with an empty string as the body text. + * + * @param text The text of the body of this element + * @deprecated Use the {@link #body(String,String,String) body} method + * with namespace and name parameters + * instead. + */ + @Deprecated + public void body(String text) throws Exception { + + // The default implementation does nothing + + } + + + /** + * This method is called when the body of a matching XML element is + * encountered. If the element has no body, this method is + * called with an empty string as the body text. + *

+ * The default implementation delegates to the deprecated method + * {@link #body(String) body} without the namespace and + * name parameters, to retain backwards compatibility. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @param text The text of the body of this element + * @since Digester 1.4 + */ + public void body(String namespace, String name, String text) + throws Exception { + + body(text); + + } + + + /** + * This method is called when the end of a matching XML element + * is encountered. + * + * @deprecated Use the {@link #end(String,String) end} method with + * namespace and name parameters instead. + */ + @Deprecated + public void end() throws Exception { + + // The default implementation does nothing + + } + + + /** + * This method is called when the end of a matching XML element + * is encountered. The default implementation delegates to the deprecated + * method {@link #end end} without the + * namespace and name parameters, to retain + * backwards compatibility. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @since Digester 1.4 + */ + public void end(String namespace, String name) + throws Exception { + + end(); + + } + + + /** + * This method is called after all parsing methods have been + * called, to allow Rules to remove temporary data. + */ + public void finish() throws Exception { + + // The default implementation does nothing + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/RuleSet.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/RuleSet.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/RuleSet.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,67 @@ +/* $Id: RuleSet.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester; + + +/** + *

Public interface defining a shorthand means of configuring a complete + * set of related Rule definitions, possibly associated with + * a particular namespace URI, in one operation. To use an instance of a + * class that imlements this interface:

+ *
    + *
  • Create a concrete implementation of this interface.
  • + *
  • Optionally, you can configure a RuleSet to be relevant + * only for a particular namespace URI by configuring the value to be + * returned by getNamespaceURI().
  • + *
  • As you are configuring your Digester instance, call + * digester.addRuleSet() and pass the RuleSet instance.
  • + *
  • Digester will call the addRuleInstances() method of + * your RuleSet to configure the necessary rules.
  • + *
+ */ + +public interface RuleSet { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the namespace URI that will be applied to all Rule instances + * created from this RuleSet. + */ + public String getNamespaceURI(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance. + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public void addRuleInstances(Digester digester); + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/RuleSetBase.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/RuleSetBase.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/RuleSetBase.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,71 @@ +/* $Id: RuleSetBase.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +/** + *

Convenience base class that implements the {@link RuleSet} interface. + * Concrete implementations should list all of their actual rule creation + * logic in the addRuleSet() implementation.

+ */ + +public abstract class RuleSetBase implements RuleSet { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The namespace URI that all Rule instances created by this RuleSet + * will be associated with. + */ + protected String namespaceURI = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the namespace URI that will be applied to all Rule instances + * created from this RuleSet. + */ + public String getNamespaceURI() { + + return (this.namespaceURI); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance. + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public abstract void addRuleInstances(Digester digester); + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/Rules.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/Rules.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/Rules.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,129 @@ +/* $Id: Rules.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import java.util.List; + + +/** + * Public interface defining a collection of Rule instances (and corresponding + * matching patterns) plus an implementation of a matching policy that selects + * the rules that match a particular pattern of nested elements discovered + * during parsing. + */ + +public interface Rules { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Digester instance with which this Rules instance is + * associated. + */ + public Digester getDigester(); + + + /** + * Set the Digester instance with which this Rules instance is associated. + * + * @param digester The newly associated Digester instance + */ + public void setDigester(Digester digester); + + + /** + * Return the namespace URI that will be applied to all subsequently + * added Rule objects. + */ + public String getNamespaceURI(); + + + /** + * Set the namespace URI that will be applied to all subsequently + * added Rule objects. + * + * @param namespaceURI Namespace URI that must match on all + * subsequently added rules, or null for matching + * regardless of the current namespace URI + */ + public void setNamespaceURI(String namespaceURI); + + + // --------------------------------------------------------- Public Methods + + + /** + * Register a new Rule instance matching the specified pattern. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + public void add(String pattern, Rule rule); + + + /** + * Clear all existing Rule instance registrations. + */ + public void clear(); + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param pattern Nesting pattern to be matched + * + * @deprecated Call match(namespaceURI,pattern) instead. + */ + @Deprecated + public List match(String pattern); + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param namespaceURI Namespace URI for which to select matching rules, + * or null to match regardless of namespace URI + * @param pattern Nesting pattern to be matched + */ + public List match(String namespaceURI, String pattern); + + + /** + * Return a List of all registered Rule instances, or a zero-length List + * if there are no registered Rule instances. If more than one Rule + * instance has been registered, they must be returned + * in the order originally registered through the add() + * method. + */ + public List rules(); + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/RulesBase.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/RulesBase.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/RulesBase.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,295 @@ +/* $Id: RulesBase.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + + +/** + *

Default implementation of the Rules interface that supports + * the standard rule matching behavior. This class can also be used as a + * base class for specialized Rules implementations.

+ * + *

The matching policies implemented by this class support two different + * types of pattern matching rules:

+ *
    + *
  • Exact Match - A pattern "a/b/c" exactly matches a + * <c> element, nested inside a <b> + * element, which is nested inside an <a> element.
  • + *
  • Tail Match - A pattern "*/a/b" matches a + * <b> element, nested inside an <a> + * element, no matter how deeply the pair is nested.
  • + *
+ * + *

Note that wildcard patterns are ignored if an explicit match can be found + * (and when multiple wildcard patterns match, only the longest, ie most + * explicit, pattern is considered a match).

+ * + *

See the package documentation for package org.apache.commons.digester + * for more information.

+ */ + +public class RulesBase implements Rules { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The set of registered Rule instances, keyed by the matching pattern. + * Each value is a List containing the Rules for that pattern, in the + * order that they were orginally registered. + */ + protected HashMap> cache = new HashMap>(); + + + /** + * The Digester instance with which this Rules instance is associated. + */ + protected Digester digester = null; + + + /** + * The namespace URI for which subsequently added Rule + * objects are relevant, or null for matching independent + * of namespaces. + */ + protected String namespaceURI = null; + + + /** + * The set of registered Rule instances, in the order that they were + * originally registered. + */ + protected ArrayList rules = new ArrayList(); + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Digester instance with which this Rules instance is + * associated. + */ + public Digester getDigester() { + + return (this.digester); + + } + + + /** + * Set the Digester instance with which this Rules instance is associated. + * + * @param digester The newly associated Digester instance + */ + public void setDigester(Digester digester) { + + this.digester = digester; + for (Rule rule : rules) { + rule.setDigester(digester); + } + + } + + + /** + * Return the namespace URI that will be applied to all subsequently + * added Rule objects. + */ + public String getNamespaceURI() { + + return (this.namespaceURI); + + } + + + /** + * Set the namespace URI that will be applied to all subsequently + * added Rule objects. + * + * @param namespaceURI Namespace URI that must match on all + * subsequently added rules, or null for matching + * regardless of the current namespace URI + */ + public void setNamespaceURI(String namespaceURI) { + + this.namespaceURI = namespaceURI; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Register a new Rule instance matching the specified pattern. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + public void add(String pattern, Rule rule) { + // to help users who accidently add '/' to the end of their patterns + int patternLength = pattern.length(); + if (patternLength>1 && pattern.endsWith("/")) { + pattern = pattern.substring(0, patternLength-1); + } + + + List list = cache.get(pattern); + if (list == null) { + list = new ArrayList(); + cache.put(pattern, list); + } + list.add(rule); + rules.add(rule); + if (this.digester != null) { + rule.setDigester(this.digester); + } + if (this.namespaceURI != null) { + rule.setNamespaceURI(this.namespaceURI); + } + + } + + + /** + * Clear all existing Rule instance registrations. + */ + public void clear() { + + cache.clear(); + rules.clear(); + + } + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param pattern Nesting pattern to be matched + * + * @deprecated Call match(namespaceURI,pattern) instead. + */ + @Deprecated + public List match(String pattern) { + + return (match(null, pattern)); + + } + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param namespaceURI Namespace URI for which to select matching rules, + * or null to match regardless of namespace URI + * @param pattern Nesting pattern to be matched + */ + public List match(String namespaceURI, String pattern) { + + // List rulesList = (List) this.cache.get(pattern); + List rulesList = lookup(namespaceURI, pattern); + if ((rulesList == null) || (rulesList.size() < 1)) { + // Find the longest key, ie more discriminant + String longKey = ""; + for (String key : cache.keySet()) { + if (key.startsWith("*/")) { + if (pattern.equals(key.substring(2)) || + pattern.endsWith(key.substring(1))) { + if (key.length() > longKey.length()) { + // rulesList = (List) this.cache.get(key); + rulesList = lookup(namespaceURI, key); + longKey = key; + } + } + } + } + } + if (rulesList == null) { + rulesList = new ArrayList(); + } + return (rulesList); + + } + + + /** + * Return a List of all registered Rule instances, or a zero-length List + * if there are no registered Rule instances. If more than one Rule + * instance has been registered, they must be returned + * in the order originally registered through the add() + * method. + */ + public List rules() { + + return (this.rules); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return a List of Rule instances for the specified pattern that also + * match the specified namespace URI (if any). If there are no such + * rules, return null. + * + * @param namespaceURI Namespace URI to match, or null to + * select matching rules regardless of namespace URI + * @param pattern Pattern to be matched + */ + protected List lookup(String namespaceURI, String pattern) { + + // Optimize when no namespace URI is specified + List list = this.cache.get(pattern); + if (list == null) { + return (null); + } + if ((namespaceURI == null) || (namespaceURI.length() == 0)) { + return (list); + } + + // Select only Rules that match on the specified namespace URI + ArrayList results = new ArrayList(); + for (Rule item : list) { + if ((namespaceURI.equals(item.getNamespaceURI())) || + (item.getNamespaceURI() == null)) { + results.add(item); + } + } + return (results); + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/SetNestedPropertiesRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/SetNestedPropertiesRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/SetNestedPropertiesRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,472 @@ +/* $Id: SetNestedPropertiesRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import java.util.List; +import java.util.LinkedList; +import java.util.ArrayList; +import java.util.HashMap; +import java.beans.PropertyDescriptor; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.beanutils.DynaBean; +import org.apache.commons.beanutils.DynaProperty; +import org.apache.commons.beanutils.PropertyUtils; + +import org.xml.sax.Attributes; + +import org.apache.commons.logging.Log; + + +/** + *

Rule implementation that sets properties on the object at the top of the + * stack, based on child elements with names matching properties on that + * object.

+ * + *

Example input that can be processed by this rule:

+ *
+ *   [widget]
+ *    [height]7[/height]
+ *    [width]8[/width]
+ *    [label]Hello, world[/label]
+ *   [/widget]
+ * 
+ * + *

For each child element of [widget], a corresponding setter method is + * located on the object on the top of the digester stack, the body text of + * the child element is converted to the type specified for the (sole) + * parameter to the setter method, then the setter method is invoked.

+ * + *

This rule supports custom mapping of xml element names to property names. + * The default mapping for particular elements can be overridden by using + * {@link #SetNestedPropertiesRule(String[] elementNames, + * String[] propertyNames)}. + * This allows child elements to be mapped to properties with different names. + * Certain elements can also be marked to be ignored.

+ * + *

A very similar effect can be achieved using a combination of the + * BeanPropertySetterRule and the ExtendedBaseRules + * rules manager; this Rule, however, works fine with the default + * RulesBase rules manager.

+ * + *

Note that this rule is designed to be used to set only "primitive" + * bean properties, eg String, int, boolean. If some of the child xml elements + * match ObjectCreateRule rules (ie cause objects to be created) then you must + * use one of the more complex constructors to this rule to explicitly skip + * processing of that xml element, and define a SetNextRule (or equivalent) to + * handle assigning the child object to the appropriate property instead.

+ * + *

Implementation Notes

+ * + *

This class works by creating its own simple Rules implementation. When + * begin is invoked on this rule, the digester's current rules object is + * replaced by a custom one. When end is invoked for this rule, the original + * rules object is restored. The digester rules objects therefore behave in + * a stack-like manner.

+ * + *

For each child element encountered, the custom Rules implementation + * ensures that a special AnyChildRule instance is included in the matches + * returned to the digester, and it is this rule instance that is responsible + * for setting the appropriate property on the target object (if such a property + * exists). The effect is therefore like a "trailing wildcard pattern". The + * custom Rules implementation also returns the matches provided by the + * underlying Rules implementation for the same pattern, so other rules + * are not "disabled" during processing of a SetNestedPropertiesRule.

+ * + *

TODO: Optimise this class. Currently, each time begin is called, + * new AnyChildRules and AnyChildRule objects are created. It should be + * possible to cache these in normal use (though watch out for when a rule + * instance is invoked re-entrantly!).

+ * + * @since 1.6 + */ + +public class SetNestedPropertiesRule extends Rule { + + private Log log = null; + + private boolean trimData = true; + private boolean allowUnknownChildElements = false; + + private HashMap elementNames = new HashMap(); + + // ----------------------------------------------------------- Constructors + + /** + * Base constructor, which maps every child element into a bean property + * with the same name as the xml element. + * + *

It is an error if a child xml element exists but the target java + * bean has no such property (unless setAllowUnknownChildElements has been + * set to true).

+ */ + public SetNestedPropertiesRule() { + // nothing to set up + } + + /** + *

Convenience constructor which overrides the default mappings for + * just one property.

+ * + *

For details about how this works, see + * {@link #SetNestedPropertiesRule(String[] elementNames, + * String[] propertyNames)}.

+ * + * @param elementName is the child xml element to match + * @param propertyName is the java bean property to be assigned the value + * of the specified xml element. This may be null, in which case the + * specified xml element will be ignored. + */ + public SetNestedPropertiesRule(String elementName, String propertyName) { + elementNames.put(elementName, propertyName); + } + + /** + *

Constructor which allows element->property mapping to be overridden. + *

+ * + *

Two arrays are passed in. One contains xml element names and the + * other java bean property names. The element name / property name pairs + * are matched by position; in order words, the first string in the element + * name array corresponds to the first string in the property name array + * and so on.

+ * + *

If a property name is null or the xml element name has no matching + * property name due to the arrays being of different lengths then this + * indicates that the xml element should be ignored.

+ * + *
Example One
+ *

The following constructs a rule that maps the alt-city + * element to the city property and the alt-state + * to the state property. All other child elements are mapped + * as usual using exact name matching. + *

+     *      SetNestedPropertiesRule(
+     *                new String[] {"alt-city", "alt-state"}, 
+     *                new String[] {"city", "state"});
+     * 
+ *

+ * + *
Example Two
+ *

The following constructs a rule that maps the class + * xml element to the className property. The xml element + * ignore-me is not mapped, ie is ignored. All other elements + * are mapped as usual using exact name matching. + *

+     *      SetPropertiesRule(
+     *                new String[] {"class", "ignore-me"}, 
+     *                new String[] {"className"});
+     * 
+ *

+ * + * @param elementNames names of elements to map + * @param propertyNames names of properties mapped to + */ + public SetNestedPropertiesRule(String[] elementNames, String[] propertyNames) { + for (int i=0, size=elementNames.length; i + * When set to false, any child element for which there is no + * corresponding object property will cause an error to be reported. + *

+ * When set to true, any child element for which there is no + * corresponding object property will simply be ignored. + *

+ * The default value of this attribute is false (unknown child elements + * are not allowed). + */ + public void setAllowUnknownChildElements(boolean allowUnknownChildElements) { + this.allowUnknownChildElements = allowUnknownChildElements; + } + + /** See {@link #setAllowUnknownChildElements}. */ + public boolean getAllowUnknownChildElements() { + return allowUnknownChildElements; + } + + /** + * Process the beginning of this element. + * + * @param namespace is the namespace this attribute is in, or null + * @param name is the name of the current xml element + * @param attributes is the attribute list of this element + */ + @Override + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + Rules oldRules = digester.getRules(); + AnyChildRule anyChildRule = new AnyChildRule(); + anyChildRule.setDigester(digester); + AnyChildRules newRules = new AnyChildRules(anyChildRule); + newRules.init(digester.getMatch()+"/", oldRules); + digester.setRules(newRules); + } + + /** + * This is only invoked after all child elements have been processed, + * so we can remove the custom Rules object that does the + * child-element-matching. + */ + @Override + public void body(String bodyText) throws Exception { + AnyChildRules newRules = (AnyChildRules) digester.getRules(); + digester.setRules(newRules.getOldRules()); + } + + /** + * Add an additional custom xml-element -> property mapping. + *

+ * This is primarily intended to be used from the xml rules module + * (as it is not possible there to pass the necessary parameters to the + * constructor for this class). However it is valid to use this method + * directly if desired. + */ + public void addAlias(String elementName, String propertyName) { + elementNames.put(elementName, propertyName); + } + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + StringBuffer sb = new StringBuffer("SetNestedPropertiesRule["); + sb.append("allowUnknownChildElements="); + sb.append(allowUnknownChildElements); + sb.append(", trimData="); + sb.append(trimData); + sb.append(", elementNames="); + sb.append(elementNames); + sb.append("]"); + return sb.toString(); + } + + //----------------------------------------- local classes + + /** Private Rules implementation */ + private class AnyChildRules implements Rules { + private String matchPrefix = null; + private Rules decoratedRules = null; + + private ArrayList rules = new ArrayList(1); + private AnyChildRule rule; + + public AnyChildRules(AnyChildRule rule) { + this.rule = rule; + rules.add(rule); + } + + public Digester getDigester() { return null; } + public void setDigester(Digester digester) {} + public String getNamespaceURI() {return null;} + public void setNamespaceURI(String namespaceURI) {} + public void add(String pattern, Rule rule) {} + public void clear() {} + + public List match(String matchPath) { + return match(null,matchPath); + } + + public List match(String namespaceURI, String matchPath) { + List match = decoratedRules.match(namespaceURI, matchPath); + + if ((matchPath.startsWith(matchPrefix)) && + (matchPath.indexOf('/', matchPrefix.length()) == -1)) { + + // The current element is a direct child of the element + // specified in the init method, so we want to ensure that + // the rule passed to this object's constructor is included + // in the returned list of matching rules. + + if ((match == null || match.size()==0)) { + // The "real" rules class doesn't have any matches for + // the specified path, so we return a list containing + // just one rule: the one passed to this object's + // constructor. + return rules; + } + else { + // The "real" rules class has rules that match the current + // node, so we return this list *plus* the rule passed to + // this object's constructor. + // + // It might not be safe to modify the returned list, + // so clone it first. + LinkedList newMatch = new LinkedList(match); + newMatch.addLast(rule); + return newMatch; + } + } + else { + return match; + } + } + + public List rules() { + // This is not actually expected to be called during normal + // processing. + // + // There is only one known case where this is called; when a rule + // returned from AnyChildRules.match is invoked and throws a + // SAXException then method Digester.endDocument will be called + // without having "uninstalled" the AnyChildRules ionstance. That + // method attempts to invoke the "finish" method for every Rule + // instance - and thus needs to call rules() on its Rules object, + // which is this one. Actually, java 1.5 and 1.6beta2 have a + // bug in their xml implementation such that endDocument is not + // called after a SAXException, but other parsers (eg Aelfred) + // do call endDocument. Here, we therefore need to return the + // rules registered with the underlying Rules object. + log.debug("AnyChildRules.rules invoked."); + return decoratedRules.rules(); + } + + public void init(String prefix, Rules rules) { + matchPrefix = prefix; + decoratedRules = rules; + } + + public Rules getOldRules() { + return decoratedRules; + } + } + + private class AnyChildRule extends Rule { + private String currChildNamespaceURI = null; + private String currChildElementName = null; + + @Override + public void begin(String namespaceURI, String name, + Attributes attributes) throws Exception { + + currChildNamespaceURI = namespaceURI; + currChildElementName = name; + } + + @Override + public void body(String value) throws Exception { + String propName = currChildElementName; + if (elementNames.containsKey(currChildElementName)) { + // overide propName + propName = elementNames.get(currChildElementName); + if (propName == null) { + // user wants us to ignore this element + return; + } + } + + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("[SetNestedPropertiesRule]{" + digester.match + + "} Setting property '" + propName + "' to '" + + value + "'"); + } + + // Populate the corresponding properties of the top object + Object top = digester.peek(); + if (debug) { + if (top != null) { + log.debug("[SetNestedPropertiesRule]{" + digester.match + + "} Set " + top.getClass().getName() + + " properties"); + } else { + log.debug("[SetPropertiesRule]{" + digester.match + + "} Set NULL properties"); + } + } + + if (trimData) { + value = value.trim(); + } + + if (!allowUnknownChildElements) { + // Force an exception if the property does not exist + // (BeanUtils.setProperty() silently returns in this case) + if (top instanceof DynaBean) { + DynaProperty desc = + ((DynaBean) top).getDynaClass().getDynaProperty(propName); + if (desc == null) { + throw new NoSuchMethodException + ("Bean has no property named " + propName); + } + } else /* this is a standard JavaBean */ { + PropertyDescriptor desc = + PropertyUtils.getPropertyDescriptor(top, propName); + if (desc == null) { + throw new NoSuchMethodException + ("Bean has no property named " + propName); + } + } + } + + try + { + BeanUtils.setProperty(top, propName, value); + } + catch(NullPointerException e) { + log.error("NullPointerException: " + + "top=" + top + ",propName=" + propName + ",value=" + value + "!"); + throw e; + } + } + + @Override + public void end(String namespace, String name) throws Exception { + currChildElementName = null; + } + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/SetNextRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/SetNextRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/SetNextRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,244 @@ +/* $Id: SetNextRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import org.apache.commons.beanutils.MethodUtils; + + +/** + *

Rule implementation that calls a method on the (top-1) (parent) + * object, passing the top object (child) as an argument. It is + * commonly used to establish parent-child relationships.

+ * + *

This rule now supports more flexible method matching by default. + * It is possible that this may break (some) code + * written against release 1.1.1 or earlier. + * See {@link #isExactMatch()} for more details.

+ * + *

Note that while CallMethodRule uses commons-beanutils' data-conversion + * functionality (ConvertUtils class) to convert parameter values into + * the appropriate type for the parameter to the called method, this + * rule does not. Needing to use ConvertUtils functionality when building + * parent-child relationships is expected to be very rare; however if you + * do need this then instead of using this rule, create a CallMethodRule + * specifying targetOffset of 1 in the constructor.

+ */ + +public class SetNextRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "set next" rule with the specified method name. The + * method's argument type is assumed to be the class of the + * child object. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetNextRule(String methodName)} instead. + */ + @Deprecated + public SetNextRule(Digester digester, String methodName) { + + this(methodName); + + } + + + /** + * Construct a "set next" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramType Java class of the parent method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetNextRule(String methodName,String paramType)} instead. + */ + @Deprecated + public SetNextRule(Digester digester, String methodName, + String paramType) { + + this(methodName, paramType); + + } + + /** + * Construct a "set next" rule with the specified method name. The + * method's argument type is assumed to be the class of the + * child object. + * + * @param methodName Method name of the parent method to call + */ + public SetNextRule(String methodName) { + + this(methodName, null); + + } + + + /** + * Construct a "set next" rule with the specified method name. + * + * @param methodName Method name of the parent method to call + * @param paramType Java class of the parent method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public SetNextRule(String methodName, + String paramType) { + + this.methodName = methodName; + this.paramType = paramType; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The method name to call on the parent object. + */ + protected String methodName = null; + + + /** + * The Java class name of the parameter type expected by the method. + */ + protected String paramType = null; + + /** + * Should we use exact matching. Default is no. + */ + protected boolean useExactMatch = false; + + // --------------------------------------------------------- Public Methods + + + /** + *

Is exact matching being used.

+ * + *

This rule uses org.apache.commons.beanutils.MethodUtils + * to introspect the relevent objects so that the right method can be called. + * Originally, MethodUtils.invokeExactMethod was used. + * This matches methods very strictly + * and so may not find a matching method when one exists. + * This is still the behaviour when exact matching is enabled.

+ * + *

When exact matching is disabled, MethodUtils.invokeMethod is used. + * This method finds more methods but is less precise when there are several methods + * with correct signatures. + * So, if you want to choose an exact signature you might need to enable this property.

+ * + *

The default setting is to disable exact matches.

+ * + * @return true iff exact matching is enabled + * @since Digester Release 1.1.1 + */ + public boolean isExactMatch() { + + return useExactMatch; + } + + /** + *

Set whether exact matching is enabled.

+ * + *

See {@link #isExactMatch()}.

+ * + * @param useExactMatch should this rule use exact method matching + * @since Digester Release 1.1.1 + */ + public void setExactMatch(boolean useExactMatch) { + + this.useExactMatch = useExactMatch; + } + + /** + * Process the end of this element. + */ + @Override + public void end() throws Exception { + + // Identify the objects to be used + Object child = digester.peek(0); + Object parent = digester.peek(1); + if (digester.log.isDebugEnabled()) { + if (parent == null) { + digester.log.debug("[SetNextRule]{" + digester.match + + "} Call [NULL PARENT]." + + methodName + "(" + child + ")"); + } else { + digester.log.debug("[SetNextRule]{" + digester.match + + "} Call " + parent.getClass().getName() + "." + + methodName + "(" + child + ")"); + } + } + + // Call the specified method + Class paramTypes[] = new Class[1]; + if (paramType != null) { + paramTypes[0] = + digester.getClassLoader().loadClass(paramType); + } else { + paramTypes[0] = child.getClass(); + } + + if (useExactMatch) { + + MethodUtils.invokeExactMethod(parent, methodName, + new Object[]{ child }, paramTypes); + + } else { + + MethodUtils.invokeMethod(parent, methodName, + new Object[]{ child }, paramTypes); + + } + } + + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("SetNextRule["); + sb.append("methodName="); + sb.append(methodName); + sb.append(", paramType="); + sb.append(paramType); + sb.append("]"); + return (sb.toString()); + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/SetPropertiesRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/SetPropertiesRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/SetPropertiesRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,335 @@ +/* $Id: SetPropertiesRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import java.util.HashMap; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.beanutils.PropertyUtils; +import org.xml.sax.Attributes; + + +/** + *

Rule implementation that sets properties on the object at the top of the + * stack, based on attributes with corresponding names.

+ * + *

This rule supports custom mapping of attribute names to property names. + * The default mapping for particular attributes can be overridden by using + * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}. + * This allows attributes to be mapped to properties with different names. + * Certain attributes can also be marked to be ignored.

+ */ + +public class SetPropertiesRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor sets only the the associated Digester. + * + * @param digester The digester with which this rule is associated + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetPropertiesRule()} instead. + */ + @Deprecated + public SetPropertiesRule(Digester digester) { + + this(); + + } + + + /** + * Base constructor. + */ + public SetPropertiesRule() { + + // nothing to set up + + } + + /** + *

Convenience constructor overrides the mapping for just one property.

+ * + *

For details about how this works, see + * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}.

+ * + * @param attributeName map this attribute + * @param propertyName to a property with this name + */ + public SetPropertiesRule(String attributeName, String propertyName) { + + attributeNames = new String[1]; + attributeNames[0] = attributeName; + propertyNames = new String[1]; + propertyNames[0] = propertyName; + } + + /** + *

Constructor allows attribute->property mapping to be overriden.

+ * + *

Two arrays are passed in. + * One contains the attribute names and the other the property names. + * The attribute name / property name pairs are match by position + * In order words, the first string in the attribute name list matches + * to the first string in the property name list and so on.

+ * + *

If a property name is null or the attribute name has no matching + * property name, then this indicates that the attibute should be ignored.

+ * + *
Example One
+ *

The following constructs a rule that maps the alt-city + * attribute to the city property and the alt-state + * to the state property. + * All other attributes are mapped as usual using exact name matching. + *

+     *      SetPropertiesRule(
+     *                new String[] {"alt-city", "alt-state"}, 
+     *                new String[] {"city", "state"});
+     * 
+ * + *
Example Two
+ *

The following constructs a rule that maps the class + * attribute to the className property. + * The attribute ignore-me is not mapped. + * All other attributes are mapped as usual using exact name matching. + *

+     *      SetPropertiesRule(
+     *                new String[] {"class", "ignore-me"}, 
+     *                new String[] {"className"});
+     * 
+ * + * @param attributeNames names of attributes to map + * @param propertyNames names of properties mapped to + */ + public SetPropertiesRule(String[] attributeNames, String[] propertyNames) { + // create local copies + this.attributeNames = new String[attributeNames.length]; + for (int i=0, size=attributeNames.length; iproperty mapping + */ + private String [] attributeNames; + /** + * Property names used to override natural attribute->property mapping + */ + private String [] propertyNames; + + /** + * Used to determine whether the parsing should fail if an property specified + * in the XML is missing from the bean. Default is true for backward compatibility. + */ + private boolean ignoreMissingProperty = true; + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the beginning of this element. + * + * @param attributes The attribute list of this element + */ + @Override + public void begin(Attributes attributes) throws Exception { + + // Build a set of attribute names and corresponding values + HashMap values = new HashMap(); + + // set up variables for custom names mappings + int attNamesLength = 0; + if (attributeNames != null) { + attNamesLength = attributeNames.length; + } + int propNamesLength = 0; + if (propertyNames != null) { + propNamesLength = propertyNames.length; + } + + + for (int i = 0; i < attributes.getLength(); i++) { + String name = attributes.getLocalName(i); + if ("".equals(name)) { + name = attributes.getQName(i); + } + String value = attributes.getValue(i); + + // we'll now check for custom mappings + for (int n = 0; nAdd an additional attribute name to property name mapping. + * This is intended to be used from the xml rules. + */ + public void addAlias(String attributeName, String propertyName) { + + // this is a bit tricky. + // we'll need to resize the array. + // probably should be synchronized but digester's not thread safe anyway + if (attributeNames == null) { + + attributeNames = new String[1]; + attributeNames[0] = attributeName; + propertyNames = new String[1]; + propertyNames[0] = propertyName; + + } else { + int length = attributeNames.length; + String [] tempAttributes = new String[length + 1]; + for (int i=0; iAre attributes found in the xml without matching properties to be ignored? + *

+ * If false, the parsing will interrupt with an NoSuchMethodException + * if a property specified in the XML is not found. The default is true. + *

+ * @return true if skipping the unmatched attributes. + */ + public boolean isIgnoreMissingProperty() { + + return this.ignoreMissingProperty; + } + + /** + * Sets whether attributes found in the xml without matching properties + * should be ignored. + * If set to false, the parsing will throw an NoSuchMethodException + * if an unmatched + * attribute is found. This allows to trap misspellings in the XML file. + * @param ignoreMissingProperty false to stop the parsing on unmatched attributes. + */ + public void setIgnoreMissingProperty(boolean ignoreMissingProperty) { + + this.ignoreMissingProperty = ignoreMissingProperty; + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/SetPropertyRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/SetPropertyRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/SetPropertyRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,182 @@ +/* $Id: SetPropertyRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import java.beans.PropertyDescriptor; + +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.beanutils.DynaBean; +import org.apache.commons.beanutils.DynaProperty; +import org.apache.commons.beanutils.PropertyUtils; +import org.xml.sax.Attributes; + + +/** + * Rule implementation that sets an individual property on the object at the + * top of the stack, based on attributes with specified names. + */ + +public class SetPropertyRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "set property" rule with the specified name and value + * attributes. + * + * @param digester The digester with which this rule is associated + * @param name Name of the attribute that will contain the name of the + * property to be set + * @param value Name of the attribute that will contain the value to which + * the property should be set + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetPropertyRule(String name, String value)} instead. + */ + @Deprecated + public SetPropertyRule(Digester digester, String name, String value) { + + this(name, value); + + } + + /** + * Construct a "set property" rule with the specified name and value + * attributes. + * + * @param name Name of the attribute that will contain the name of the + * property to be set + * @param value Name of the attribute that will contain the value to which + * the property should be set + */ + public SetPropertyRule(String name, String value) { + + this.name = name; + this.value = value; + + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The attribute that will contain the property name. + */ + protected String name = null; + + + /** + * The attribute that will contain the property value. + */ + protected String value = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the beginning of this element. + * + * @param attributes The attribute list of this element + * + * @exception NoSuchMethodException if the bean does not + * have a writeable property of the specified name + */ + @Override + public void begin(Attributes attributes) throws Exception { + + if (attributes.getLength() == 0 ) { + return; + } + + // Identify the actual property name and value to be used + String actualName = null; + String actualValue = null; + for (int i = 0; i < attributes.getLength(); i++) { + String name = attributes.getLocalName(i); + if ("".equals(name)) { + name = attributes.getQName(i); + } + String value = attributes.getValue(i); + if (name.equals(this.name)) { + actualName = value; + } else if (name.equals(this.value)) { + actualValue = value; + } + } + + // Get a reference to the top object + Object top = digester.peek(); + + // Log some debugging information + if (digester.log.isDebugEnabled()) { + digester.log.debug("[SetPropertyRule]{" + digester.match + + "} Set " + top.getClass().getName() + " property " + + actualName + " to " + actualValue); + } + + // Force an exception if the property does not exist + // (BeanUtils.setProperty() silently returns in this case) + // + // This code should probably use PropertyUtils.isWriteable(), + // like SetPropertiesRule does. + if (top instanceof DynaBean) { + DynaProperty desc = + ((DynaBean) top).getDynaClass().getDynaProperty(actualName); + if (desc == null) { + throw new NoSuchMethodException + ("Bean has no property named " + actualName); + } + } else /* this is a standard JavaBean */ { + PropertyDescriptor desc = + PropertyUtils.getPropertyDescriptor(top, actualName); + if (desc == null) { + throw new NoSuchMethodException + ("Bean has no property named " + actualName); + } + } + + // Set the property (with conversion as necessary) + BeanUtils.setProperty(top, actualName, actualValue); + + } + + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("SetPropertyRule["); + sb.append("name="); + sb.append(name); + sb.append(", value="); + sb.append(value); + sb.append("]"); + return (sb.toString()); + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/SetRootRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/SetRootRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/SetRootRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,237 @@ +/* $Id: SetRootRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import org.apache.commons.beanutils.MethodUtils; + + +/** + *

Rule implementation that calls a method on the root object on the stack, + * passing the top object (child) as an argument. + * It is important to remember that this rule acts on end.

+ * + *

This rule now supports more flexible method matching by default. + * It is possible that this may break (some) code + * written against release 1.1.1 or earlier. + * See {@link #isExactMatch()} for more details.

+ */ + +public class SetRootRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "set root" rule with the specified method name. The + * method's argument type is assumed to be the class of the + * child object. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetRootRule(String methodName)} instead. + */ + @Deprecated + public SetRootRule(Digester digester, String methodName) { + + this(methodName); + + } + + + /** + * Construct a "set root" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramType Java class of the parent method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetRootRule(String methodName,String paramType)} instead. + */ + @Deprecated + public SetRootRule(Digester digester, String methodName, + String paramType) { + + this(methodName, paramType); + + } + + /** + * Construct a "set root" rule with the specified method name. The + * method's argument type is assumed to be the class of the + * child object. + * + * @param methodName Method name of the parent method to call + */ + public SetRootRule(String methodName) { + + this(methodName, null); + + } + + + /** + * Construct a "set root" rule with the specified method name. + * + * @param methodName Method name of the parent method to call + * @param paramType Java class of the parent method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public SetRootRule(String methodName, + String paramType) { + + this.methodName = methodName; + this.paramType = paramType; + + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The method name to call on the parent object. + */ + protected String methodName = null; + + + /** + * The Java class name of the parameter type expected by the method. + */ + protected String paramType = null; + + /** + * Should we use exact matching. Default is no. + */ + protected boolean useExactMatch = false; + + + // --------------------------------------------------------- Public Methods + + + /** + *

Is exact matching being used.

+ * + *

This rule uses org.apache.commons.beanutils.MethodUtils + * to introspect the relevent objects so that the right method can be called. + * Originally, MethodUtils.invokeExactMethod was used. + * This matches methods very strictly + * and so may not find a matching method when one exists. + * This is still the behaviour when exact matching is enabled.

+ * + *

When exact matching is disabled, MethodUtils.invokeMethod is used. + * This method finds more methods but is less precise when there are several methods + * with correct signatures. + * So, if you want to choose an exact signature you might need to enable this property.

+ * + *

The default setting is to disable exact matches.

+ * + * @return true iff exact matching is enabled + * @since Digester Release 1.1.1 + */ + public boolean isExactMatch() { + + return useExactMatch; + } + + + /** + *

Set whether exact matching is enabled.

+ * + *

See {@link #isExactMatch()}.

+ * + * @param useExactMatch should this rule use exact method matching + * @since Digester Release 1.1.1 + */ + public void setExactMatch(boolean useExactMatch) { + + this.useExactMatch = useExactMatch; + } + + /** + * Process the end of this element. + */ + @Override + public void end() throws Exception { + + // Identify the objects to be used + Object child = digester.peek(0); + Object parent = digester.root; + if (digester.log.isDebugEnabled()) { + if (parent == null) { + digester.log.debug("[SetRootRule]{" + digester.match + + "} Call [NULL ROOT]." + + methodName + "(" + child + ")"); + } else { + digester.log.debug("[SetRootRule]{" + digester.match + + "} Call " + parent.getClass().getName() + "." + + methodName + "(" + child + ")"); + } + } + + // Call the specified method + Class paramTypes[] = new Class[1]; + if (paramType != null) { + paramTypes[0] = + digester.getClassLoader().loadClass(paramType); + } else { + paramTypes[0] = child.getClass(); + } + + if (useExactMatch) { + + MethodUtils.invokeExactMethod(parent, methodName, + new Object[]{ child }, paramTypes); + + } else { + + MethodUtils.invokeMethod(parent, methodName, + new Object[]{ child }, paramTypes); + + } + } + + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("SetRootRule["); + sb.append("methodName="); + sb.append(methodName); + sb.append(", paramType="); + sb.append(paramType); + sb.append("]"); + return (sb.toString()); + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/SetTopRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/SetTopRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/SetTopRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,236 @@ +/* $Id: SetTopRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + + +import org.apache.commons.beanutils.MethodUtils; + + +/** + *

Rule implementation that calls a "set parent" method on the top (child) + * object, passing the (top-1) (parent) object as an argument.

+ * + *

This rule now supports more flexible method matching by default. + * It is possible that this may break (some) code + * written against release 1.1.1 or earlier. + * See {@link #isExactMatch()} for more details.

+ */ + +public class SetTopRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "set parent" rule with the specified method name. The + * "set parent" method's argument type is assumed to be the class of the + * parent object. + * + * @param digester The associated Digester + * @param methodName Method name of the "set parent" method to call + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetTopRule(String methodName)} instead. + */ + @Deprecated + public SetTopRule(Digester digester, String methodName) { + + this(methodName); + + } + + + /** + * Construct a "set parent" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the "set parent" method to call + * @param paramType Java class of the "set parent" method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetTopRule(String methodName, String paramType)} instead. + */ + @Deprecated + public SetTopRule(Digester digester, String methodName, + String paramType) { + + this(methodName, paramType); + + } + + /** + * Construct a "set parent" rule with the specified method name. The + * "set parent" method's argument type is assumed to be the class of the + * parent object. + * + * @param methodName Method name of the "set parent" method to call + */ + public SetTopRule(String methodName) { + + this(methodName, null); + + } + + + /** + * Construct a "set parent" rule with the specified method name. + * + * @param methodName Method name of the "set parent" method to call + * @param paramType Java class of the "set parent" method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public SetTopRule(String methodName, + String paramType) { + + this.methodName = methodName; + this.paramType = paramType; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The method name to call on the child object. + */ + protected String methodName = null; + + + /** + * The Java class name of the parameter type expected by the method. + */ + protected String paramType = null; + + /** + * Should we use exact matching. Default is no. + */ + protected boolean useExactMatch = false; + + + // --------------------------------------------------------- Public Methods + + /** + *

Is exact matching being used.

+ * + *

This rule uses org.apache.commons.beanutils.MethodUtils + * to introspect the relevent objects so that the right method can be called. + * Originally, MethodUtils.invokeExactMethod was used. + * This matches methods very strictly + * and so may not find a matching method when one exists. + * This is still the behaviour when exact matching is enabled.

+ * + *

When exact matching is disabled, MethodUtils.invokeMethod is used. + * This method finds more methods but is less precise when there are several methods + * with correct signatures. + * So, if you want to choose an exact signature you might need to enable this property.

+ * + *

The default setting is to disable exact matches.

+ * + * @return true iff exact matching is enabled + * @since Digester Release 1.1.1 + */ + public boolean isExactMatch() { + + return useExactMatch; + } + + /** + *

Set whether exact matching is enabled.

+ * + *

See {@link #isExactMatch()}.

+ * + * @param useExactMatch should this rule use exact method matching + * @since Digester Release 1.1.1 + */ + public void setExactMatch(boolean useExactMatch) { + + this.useExactMatch = useExactMatch; + } + + /** + * Process the end of this element. + */ + @Override + public void end() throws Exception { + + // Identify the objects to be used + Object child = digester.peek(0); + Object parent = digester.peek(1); + + if (digester.log.isDebugEnabled()) { + if (child == null) { + digester.log.debug("[SetTopRule]{" + digester.match + + "} Call [NULL CHILD]." + + methodName + "(" + parent + ")"); + } else { + digester.log.debug("[SetTopRule]{" + digester.match + + "} Call " + child.getClass().getName() + "." + + methodName + "(" + parent + ")"); + } + } + + // Call the specified method + Class paramTypes[] = new Class[1]; + if (paramType != null) { + paramTypes[0] = + digester.getClassLoader().loadClass(paramType); + } else { + paramTypes[0] = parent.getClass(); + } + + if (useExactMatch) { + + MethodUtils.invokeExactMethod(child, methodName, + new Object[]{ parent }, paramTypes); + + } else { + + MethodUtils.invokeMethod(child, methodName, + new Object[]{ parent }, paramTypes); + + } + } + + + /** + * Render a printable version of this Rule. + */ + @Override + public String toString() { + + StringBuffer sb = new StringBuffer("SetTopRule["); + sb.append("methodName="); + sb.append(methodName); + sb.append(", paramType="); + sb.append(paramType); + sb.append("]"); + return (sb.toString()); + + } + + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/SimpleRegexMatcher.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/SimpleRegexMatcher.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/SimpleRegexMatcher.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,157 @@ +/* $Id: SimpleRegexMatcher.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + *

Simple regex pattern matching algorithm.

+ * + *

This uses just two wildcards: + *

    + *
  • * matches any sequence of none, one or more characters + *
  • ? matches any one character + *
+ * Escaping these wildcards is not supported .

+ * + * @since 1.5 + */ + +public class SimpleRegexMatcher extends RegexMatcher { + + // --------------------------------------------------------- Fields + + /** Default log (class wide) */ + private static final Log baseLog = LogFactory.getLog(SimpleRegexMatcher.class); + + /** Custom log (can be set per object) */ + private Log log = baseLog; + + // --------------------------------------------------------- Properties + + /** + * Gets the Log implementation. + */ + public Log getLog() { + return log; + } + + /** + * Sets the current Log implementation used by this class. + */ + public void setLog(Log log) { + this.log = log; + } + + // --------------------------------------------------------- Public Methods + + /** + * Matches using simple regex algorithm. + * + * + * @param basePattern the standard digester path representing the element + * @param regexPattern the regex pattern the path will be tested against + * @return true if the given pattern matches the given path + */ + @Override + public boolean match(String basePattern, String regexPattern) { + // check for nulls + if (basePattern == null || regexPattern == null) { + return false; + } + return match(basePattern, regexPattern, 0, 0); + } + + // --------------------------------------------------------- Implementations Methods + + /** + * Implementation of regex matching algorithm. + * This calls itself recursively. + */ + private boolean match(String basePattern, String regexPattern, int baseAt, int regexAt) { + if (log.isTraceEnabled()) { + log.trace("Base: " + basePattern); + log.trace("Regex: " + regexPattern); + log.trace("Base@" + baseAt); + log.trace("Regex@" + regexAt); + } + + // check bounds + if (regexAt >= regexPattern.length()) { + // maybe we've got a match + if (baseAt >= basePattern.length()) { + // ok! + return true; + } + // run out early + return false; + + } else { + if (baseAt >= basePattern.length()) { + // run out early + return false; + } + } + + // ok both within bounds + char regexCurrent = regexPattern.charAt(regexAt); + switch (regexCurrent) { + case '*': + // this is the tricky case + // check for terminal + if (++regexAt >= regexPattern.length()) { + // this matches anything let - so return true + return true; + } + // go through every subsequent apperance of the next character + // and so if the rest of the regex matches + char nextRegex = regexPattern.charAt(regexAt); + if (log.isTraceEnabled()) { + log.trace("Searching for next '" + nextRegex + "' char"); + } + int nextMatch = basePattern.indexOf(nextRegex, baseAt); + while (nextMatch != -1) { + if (log.isTraceEnabled()) { + log.trace("Trying '*' match@" + nextMatch); + } + if (match(basePattern, regexPattern, nextMatch, regexAt)) { + return true; + } + nextMatch = basePattern.indexOf(nextRegex, nextMatch + 1); + } + log.trace("No matches found."); + return false; + + case '?': + // this matches anything + return match(basePattern, regexPattern, ++baseAt, ++regexAt); + + default: + if (log.isTraceEnabled()) { + log.trace("Camparing " + regexCurrent + " to " + basePattern.charAt(baseAt)); + } + if (regexCurrent == basePattern.charAt(baseAt)) { + // still got more to go + return match(basePattern, regexPattern, ++baseAt, ++regexAt); + } + return false; + } + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/StackAction.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/StackAction.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/StackAction.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,78 @@ +/* $Id: StackAction.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester; + +/** + * An interface that can be implemented in order to get notifications of + * objects being pushed onto a digester stack or popped from one. + *

+ * Because objects are pushed onto the main object stack when a rule + * has created a new object, this gives the ability to intercept such + * operations and perform modifications on created objects. + *

+ * One use expected for this interface is to store information about the xml + * line that a particular object was created from. An implementation of this + * interface can detect whenever an object is pushed onto the digester object + * stack, call Digester.getDocumentLocator() to get the location within the + * current xml file, and store this either on the object on the stack (if it + * supports some user-specific interface for this purpose), or build a map of + * (object->locationinfo) separately. + *

+ * It is recommended that objects implementing this interface provide + * a method to set a "next" action, and invoke it from the callback + * methods. This allows multiple actions to be "chained" together. + *

+ * See also Digester.setStackAction. + * + * @since 1.8 + */ +public interface StackAction { + /** + * Invoked just before an object is to be pushed onto a digester stack. + * + * @param d is the digester instance. + * + * @param stackName is the name of the stack onto which the object + * has been pushed. Null is passed to indicate the default stack. + * + * @param o is the object that has just been pushed. Calling peek on the + * specified stack will return the same object. + * + * @return the object to be pushed. Normally, parameter o is returned + * but this method could return an alternate object to be pushed + * instead (eg a proxy for the provided object). + */ + public Object onPush(Digester d, String stackName, Object o); + + /** + * Invoked just after an object has been popped from a digester stack. + * + * @param d is the digester instance. + * + * @param stackName is the name of the stack from which the object + * has been popped. Null is passed to indicate the default stack. + * + * @param o is the object that has just been popped. + * + * @return the object to be returned to the called. Normally, parameter + * o is returned but this method could return an alternate object. + */ + public Object onPop(Digester d, String stackName, Object o); +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/Substitutor.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/Substitutor.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/Substitutor.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,67 @@ +/* $Id: Substitutor.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester; + +import org.xml.sax.Attributes; + +/** + *

(Logical) Interface for substitution strategies. + * (It happens to be implemented as a Java abstract class to allow + * future additions to be made without breaking backwards compatibility.) + *

+ *

+ * Usage: When {@link Digester#setSubstitutor} is set, Digester + * calls the methods in this interface to create substitute values which will + * be passed into the Rule implementations. + * Of course, it is perfectly acceptable for implementations not to make + * substitutions and simply return the inputs. + *

+ *

Different strategies are supported for attributes and body text.

+ * + * @since 1.6 + */ +public abstract class Substitutor { + + /** + *

Substitutes the attributes (before they are passed to the + * Rule implementations's).

+ * + *

Digester will only call this method a second time + * once the original Attributes instance can be safely reused. + * The implementation is therefore free to reuse the same Attributes instance + * for all calls.

+ * + * @param attributes the Attributes passed into Digester by the SAX parser, + * not null (but may be empty) + * @return Attributes to be passed to the Rule implementations. + * This method may pass back the Attributes passed in. + * Not null but possibly empty. + */ + public abstract Attributes substitute(Attributes attributes); + + /** + * Substitutes for the body text. + * This method may substitute values into the body text of the + * elements that Digester parses. + * + * @param bodyText the body text (as passed to Digester) + * @return the body text to be passed to the Rule implementations + */ + public abstract String substitute(String bodyText); +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/WithDefaultsRulesWrapper.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/WithDefaultsRulesWrapper.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/WithDefaultsRulesWrapper.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,161 @@ +/* $Id: WithDefaultsRulesWrapper.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester; + +import java.util.ArrayList; +import java.util.List; + +/** + *

Rules Decorator that returns default rules + * when no matches are returned by the wrapped implementation.

+ * + *

This allows default Rule instances to be added to any + * existing Rules implementation. These default Rule + * instances will be returned for any match for which the wrapped + * implementation does not return any matches.

+ *

For example, + *

+ *   Rule alpha;
+ *   ...
+ *   WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
+ *   rules.addDefault(alpha);
+ *   ...
+ *   digester.setRules(rules);
+ *   ...
+ * 
+ * when a pattern does not match any other rule, then rule alpha will be called. + *

+ *

WithDefaultsRulesWrapper follows the Decorator pattern.

+ * + * @since 1.6 + */ + +public class WithDefaultsRulesWrapper implements Rules { + + // --------------------------------------------------------- Fields + + /** The Rules implementation that this class wraps. */ + private Rules wrappedRules; + /** Rules to be fired when the wrapped implementations returns none. */ + private List defaultRules = new ArrayList(); + /** All rules (preserves order in which they were originally added) */ + private List allRules = new ArrayList(); + + // --------------------------------------------------------- Constructor + + /** + * Base constructor. + * + * @param wrappedRules the wrapped Rules implementation, not null + * @throws IllegalArgumentException when wrappedRules is null + */ + public WithDefaultsRulesWrapper(Rules wrappedRules) { + if (wrappedRules == null) { + throw new IllegalArgumentException("Wrapped rules must not be null"); + } + this.wrappedRules = wrappedRules; + } + + // --------------------------------------------------------- Properties + + /** Gets digester using these Rules */ + public Digester getDigester() { + return wrappedRules.getDigester(); + } + + /** Sets digeseter using these Rules */ + public void setDigester(Digester digester) { + wrappedRules.setDigester(digester); + for (Rule rule : defaultRules) { + rule.setDigester(digester); + } + } + + /** Gets namespace to apply to Rule's added */ + public String getNamespaceURI() { + return wrappedRules.getNamespaceURI(); + } + + /** Sets namespace to apply to Rule's added subsequently */ + public void setNamespaceURI(String namespaceURI) { + wrappedRules.setNamespaceURI(namespaceURI); + } + + /** Gets Rule's which will be fired when the wrapped implementation returns no matches */ + public List getDefaults() { + return defaultRules; + } + + // --------------------------------------------------------- Public Methods + + public List match(String pattern) { + return match("", pattern); + } + + /** + * Return list of rules matching given pattern. + * If wrapped implementation returns any matches return those. + * Otherwise, return default matches. + */ + public List match(String namespaceURI, String pattern) { + List matches = wrappedRules.match(namespaceURI, pattern); + if (matches == null || matches.isEmpty()) { + // a little bit of defensive programming + return new ArrayList(defaultRules); + } + // otherwise + return matches; + } + + /** Adds a rule to be fired when wrapped implementation returns no matches */ + public void addDefault(Rule rule) { + // set up rule + if (wrappedRules.getDigester() != null) { + rule.setDigester(wrappedRules.getDigester()); + } + + if (wrappedRules.getNamespaceURI() != null) { + rule.setNamespaceURI(wrappedRules.getNamespaceURI()); + } + + defaultRules.add(rule); + allRules.add(rule); + } + + /** Gets all rules */ + public List rules() { + return allRules; + } + + /** Clears all Rule's */ + public void clear() { + wrappedRules.clear(); + allRules.clear(); + defaultRules.clear(); + } + + /** + * Adds a Rule to be fired on given pattern. + * Pattern matching is delegated to wrapped implementation. + */ + public void add(String pattern, Rule rule) { + wrappedRules.add(pattern, rule); + allRules.add(rule); + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/AnnotationRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/AnnotationRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/AnnotationRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,49 @@ +/* $Id: AnnotationRuleProvider.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +import org.apache.commons.digester.Rule; + +/** + * An object capable of providing instances of {@link Rule}. + * + * @since 2.1 + */ +public interface AnnotationRuleProvider { + + /** + * Initializes the provider. + * + * @param annotation the annotation instance. + * @param element the annotated element reference. + */ + void init(A annotation, E element); + + /** + * Provides an instance of {@link Rule}. + * + * Must never return null. + * + * @return an instance of {@link Rule}. + */ + R get(); + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/CreationRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/CreationRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/CreationRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,37 @@ +/* $Id: CreationRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks a Digester rule as a creation rule, that's crucial for the + * {@code setNext} rule. + * + * @since 2.1 + */ +@Documented +@Target(ElementType.ANNOTATION_TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface CreationRule { + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoader.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoader.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoader.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,221 @@ +/* $Id: DigesterLoader.java 992084 2010-09-02 19:52:17Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.Rule; +import org.apache.commons.digester.RuleSet; +import org.apache.commons.digester.annotations.handlers.DefaultLoaderHandler; +import org.apache.commons.digester.annotations.internal.RuleSetCache; +import org.apache.commons.digester.annotations.reflect.MethodArgument; +import org.apache.commons.digester.annotations.spi.AnnotationRuleProviderFactory; +import org.apache.commons.digester.annotations.spi.DigesterLoaderHandlerFactory; +import org.apache.commons.digester.annotations.utils.AnnotationUtils; + +/** + * This class manages the creation of Digester instances analyzing target classes + * annotated with digester annotations. + * + * @since 2.1 + */ +public final class DigesterLoader { + + /** + * In-memory LRU cache that stores already analyzed classes and relative + * {@link RuleSet}. + */ + private final RuleSetCache cachedRuleSet = new RuleSetCache(); + + private final AnnotationRuleProviderFactory annotationRuleProviderFactory; + + private final DigesterLoaderHandlerFactory digesterLoaderHandlerFactory; + + /** + * Creates a new {@link DigesterLoader} instance. + * + * @param annotationRuleProviderFactory + * @param digesterLoaderHandlerFactory + */ + protected DigesterLoader(AnnotationRuleProviderFactory annotationRuleProviderFactory, + DigesterLoaderHandlerFactory digesterLoaderHandlerFactory) { + this.annotationRuleProviderFactory = annotationRuleProviderFactory; + this.digesterLoaderHandlerFactory = digesterLoaderHandlerFactory; + } + + protected AnnotationRuleProviderFactory getAnnotationRuleProviderFactory() { + return annotationRuleProviderFactory; + } + + protected DigesterLoaderHandlerFactory getDigesterLoaderHandlerFactory() { + return digesterLoaderHandlerFactory; + } + + /** + * Creates a new digester which rules are defined by analyzing the digester + * annotations in the target class. + * + * @param target the class has to be analyzed. + * @return a new Digester instance. + */ + public Digester createDigester(final Class target) { + Digester digester = new Digester(); + digester.setClassLoader(target.getClassLoader()); + addRules(target, digester); + return digester; + } + + /** + * Add rules to an already created Digester instance, analyzing the digester + * annotations in the target class. + * + * @param target the class has to be analyzed. + * @param digester the Digester instance reference. + */ + public void addRules(final Class target, final Digester digester) { + RuleSet ruleSet = getRuleSet(target); + ruleSet.addRuleInstances(digester); + } + + /** + * Builds a new {@link RuleSet} analyzing the digester annotations in the + * target class. + * + * It avoids iterate the annotations analysis for already analyzed classes, + * using an in-memory LRU cache. + * + * @param target the class has to be analyzed. + * @return a new {@link RuleSet}. + */ + public RuleSet getRuleSet(final Class target) { + if (this.cachedRuleSet.containsKey(target)) { + return this.cachedRuleSet.get(target); + } + + FromAnnotationsRuleSet ruleSet = new FromAnnotationsRuleSet(this); + addRulesTo(target, ruleSet); + this.cachedRuleSet.put(target, ruleSet); + + return ruleSet; + } + + /** + * Analyzes the target class and adds the {@link AnnotationRuleProvider}s to + * the existing {@link FromAnnotationsRuleSet}. + * + * @param target the class has to be analyzed. + * @param ruleSet the RuleSet where adding the providers. + */ + public void addRulesTo(final Class target, FromAnnotationsRuleSet ruleSet) { + if (target == Object.class + || target.isInterface() + || ruleSet.mapsClass(target)) { + return; + } + + if (this.cachedRuleSet.containsKey(target)) { + ruleSet.addRulesProviderFrom(this.cachedRuleSet.get(target)); + ruleSet.addMappedClass(target); + return; + } + + // current analyzed class + handle(target, ruleSet); + + // class fields + for (Field field : target.getDeclaredFields()) { + handle(field, ruleSet); + } + + // class methods + for (Method method : target.getDeclaredMethods()) { + handle(method, ruleSet); + + // method args + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); + Class[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < parameterTypes.length; i++) { + handle(new MethodArgument(i, parameterTypes[i], parameterAnnotations[i]), ruleSet); + } + } + + ruleSet.addMappedClass(target); + addRulesTo(target.getSuperclass(), ruleSet); + } + + /** + * Executes an analysis for each annotation present in the element. + * + * @param element the current element under analysis. + * @param ruleSet the ruleSet where add providers. + */ + private void handle(AnnotatedElement element, FromAnnotationsRuleSet ruleSet) { + for (Annotation annotation : element.getAnnotations()) { + handle(annotation, element, ruleSet); + } + } + + /** + * Handles the current visited element and related annotation, invoking the + * right handler putting the rule provider in the rule set. + * + * @param annotation the current visited annotation. + * @param element the current visited element. + */ + @SuppressWarnings("unchecked") + private void handle(A annotation, + E element, + FromAnnotationsRuleSet ruleSet) { + Class annotationType = annotation.annotationType(); + + // check if it is one of the @*.List annotation + if (annotationType.isAnnotationPresent(DigesterRuleList.class)) { + Annotation[] annotations = AnnotationUtils.getAnnotationsArrayValue(annotation); + if (annotations != null && annotations.length > 0) { + // if it is an annotations array, process them + for (Annotation ptr : annotations) { + handle(ptr, element, ruleSet); + } + } + } else if (annotationType.isAnnotationPresent(DigesterRule.class)) { + DigesterRule digesterRule = annotationType.getAnnotation(DigesterRule.class); + + if (DefaultLoaderHandler.class == digesterRule.handledBy()) { + Class> providerType = + (Class>) digesterRule.providedBy(); + ruleSet.addRuleProvider(AnnotationUtils.getAnnotationPattern(annotation), + providerType, + annotation, + element); + } else { + Class> handlerType = + (Class>) digesterRule.handledBy(); + DigesterLoaderHandler handler = + this.digesterLoaderHandlerFactory.newInstance(handlerType); + + // run! + handler.handle(annotation, element, ruleSet); + } + } + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoaderBuilder.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoaderBuilder.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoaderBuilder.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,70 @@ +/* $Id: DigesterLoaderBuilder.java 992099 2010-09-02 20:09:12Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +import org.apache.commons.digester.annotations.internal.DefaultAnnotationRuleProviderFactory; +import org.apache.commons.digester.annotations.spi.AnnotationRuleProviderFactory; + +/** + * {@link DigesterLoader} builder implementation. + * + * @since 2.1 + */ +public final class DigesterLoaderBuilder { + + /** + * Builds a new {@link DigesterLoader} using the default SPI + * implementations. + * + * @return a new {@link DigesterLoader} using the default SPI + * implementations. + */ + public static DigesterLoader byDefaultFactories() { + return new DigesterLoaderBuilder() + .useDefaultAnnotationRuleProviderFactory() + .useDefaultDigesterLoaderHandlerFactory(); + } + + /** + * Builds a new {@link DigesterLoader} using the default + * {@link AnnotationRuleProviderFactory} implementation. + * + * @return the next chained builder. + * @see DefaultAnnotationRuleProviderFactory + */ + public FromAnnotationRuleProviderFactory useDefaultAnnotationRuleProviderFactory() { + return this.useAnnotationRuleProviderFactory(new DefaultAnnotationRuleProviderFactory()); + } + + /** + * Builds a new {@link DigesterLoader} using the user defined + * {@link AnnotationRuleProviderFactory} implementation. + * + * @param annotationRuleProviderFactory the user defined + * {@link AnnotationRuleProviderFactory} implementation. + * @return the next chained builder. + */ + public FromAnnotationRuleProviderFactory + useAnnotationRuleProviderFactory(AnnotationRuleProviderFactory annotationRuleProviderFactory) { + if (annotationRuleProviderFactory == null) { + throw new IllegalArgumentException("Parameter 'annotationRuleProviderFactory' must be not null"); + } + return new FromAnnotationRuleProviderFactory(annotationRuleProviderFactory); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoaderHandler.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoaderHandler.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoaderHandler.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,43 @@ +/* $Id: DigesterLoaderHandler.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +/** + * A {@code DigesterLoaderHandler} intercept a {@code Class} visit performed by + * the {@link DigesterLoader} and performs the + * {@link DigesterLoaderHandler#handle(Annotation, AnnotatedElement, FromAnnotationsRuleSet)} + * method. + * + * @since 2.1 + */ +public interface DigesterLoaderHandler { + + /** + * Handles the current visited element with the related current annotation. + * + * @param annotation the current visited annotation. + * @param element the current visited element. + * @param ruleSet the annotations {@code RuleSet} where providers have to be + * added. + */ + void handle(A annotation, E element, FromAnnotationsRuleSet ruleSet); + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoadingException.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoadingException.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterLoadingException.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,62 @@ +/* $Id: DigesterLoadingException.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +/** + * The exception thrown when an error occurs while analyzing targets and + * building rule sets. + * + * @since 2.1 + */ +public final class DigesterLoadingException extends RuntimeException { + + /** + * The default serial version UID. + */ + private static final long serialVersionUID = 1L; + + /** + * Constructs a new loading exception with the specified detail message. + * + * @param message the detail message. + */ + public DigesterLoadingException(String message) { + super(message); + } + + /** + * Constructs a new loading exception with the specified cause. + * + * @param cause the specified cause. + */ + public DigesterLoadingException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new loading exception with the specified detail message + * and cause. + * + * @param message the detail message. + * @param cause the specified cause. + */ + public DigesterLoadingException(String message, Throwable cause) { + super(message, cause); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,66 @@ +/* $Id: DigesterRule.java 992737 2010-09-05 08:49:48Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.AnnotatedElement; + +import org.apache.commons.digester.Rule; +import org.apache.commons.digester.annotations.handlers.DefaultLoaderHandler; + +/** + * Meta-annotation that marks an annotation as part of commons-digester. + * + * @since 2.1 + */ +@Documented +@Target(ElementType.ANNOTATION_TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface DigesterRule { + + /** + * The reflected commons-digester rule. + * + * @return the reflected commons-digester rule. + */ + Class reflectsRule(); + + /** + * The handler that takes care on converting this annotation in the related + * {@link AnnotationRuleProvider} and adds it o the {@link FromAnnotationsRuleSet} + * + * @return the {@link DigesterLoaderHandler} + */ + Class> + handledBy() default DefaultLoaderHandler.class; + + /** + * Define the {@link AnnotationRuleProvider} that builds the {@link Rule} + * related to the digester rule. + * + * @return the {@link AnnotationRuleProvider}. + */ + Class> + providedBy(); + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterRuleList.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterRuleList.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/DigesterRuleList.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,37 @@ +/* $Id: DigesterRuleList.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Meta-annotation that marks an annotation as a list of commons-digester + * annotations. + * + * @since 2.1 + */ +@Documented +@Target(ElementType.ANNOTATION_TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface DigesterRuleList { + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/FromAnnotationRuleProviderFactory.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/FromAnnotationRuleProviderFactory.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/FromAnnotationRuleProviderFactory.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,73 @@ +/* $Id: FromAnnotationRuleProviderFactory.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +import org.apache.commons.digester.annotations.internal.DefaultDigesterLoaderHandlerFactory; +import org.apache.commons.digester.annotations.spi.AnnotationRuleProviderFactory; +import org.apache.commons.digester.annotations.spi.DigesterLoaderHandlerFactory; + +/** + * {@link DigesterLoader} builder implementation. + * + * @since 2.1 + */ +public final class FromAnnotationRuleProviderFactory { + + /** + * The {@link AnnotationRuleProviderFactory} selected in the previous + * chained builder. + */ + private final AnnotationRuleProviderFactory annotationRuleProviderFactory; + + /** + * {@link DigesterLoader} builder implementation. + * + * @param annotationRuleProviderFactory the + * {@link AnnotationRuleProviderFactory} selected in the previous + * chained builder. + */ + protected FromAnnotationRuleProviderFactory( + AnnotationRuleProviderFactory annotationRuleProviderFactory) { + this.annotationRuleProviderFactory = annotationRuleProviderFactory; + } + + /** + * Builds a new {@link DigesterLoader} using the default + * {@link DigesterLoaderHandlerFactory} implementation. + * + * @return the {@link DigesterLoader}. + */ + public DigesterLoader useDefaultDigesterLoaderHandlerFactory() { + return this.useDigesterLoaderHandlerFactory(new DefaultDigesterLoaderHandlerFactory()); + } + + /** + * Builds a new {@link DigesterLoader} using the user defined + * {@link DigesterLoaderHandlerFactory} implementation. + * + * @param digesterLoaderHandlerFactory + * @return the {@link DigesterLoader}. + */ + public DigesterLoader useDigesterLoaderHandlerFactory(DigesterLoaderHandlerFactory digesterLoaderHandlerFactory) { + if (digesterLoaderHandlerFactory == null) { + throw new IllegalArgumentException("Parameter 'digesterLoaderHandlerFactory' must be not null"); + } + return new DigesterLoader(this.annotationRuleProviderFactory, digesterLoaderHandlerFactory); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/FromAnnotationsRuleSet.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/FromAnnotationsRuleSet.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/FromAnnotationsRuleSet.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,242 @@ +/* $Id: FromAnnotationsRuleSet.java 992746 2010-09-05 09:31:53Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.Rule; +import org.apache.commons.digester.RuleSet; + +/** + * A {@link RuleSet} implementation that's able to inject {@link Rule}s created + * with the annotations analysis. + * + * @since 2.1 + */ +public final class FromAnnotationsRuleSet implements RuleSet { + + /** + * The data structure that stores the patterns/{@link AnnotationRuleProvider} + * pairs. + */ + private final Map>> rules = + new LinkedHashMap>>(); + + /** + * Maintains all the classes that this RuleSet produces mapping for. + */ + private final Set> mappedClasses = new HashSet>(); + + private final DigesterLoader digesterLoader; + + /** + * The namespace URI. + */ + private volatile String namespaceURI; + + /** + * Created a new {@code FromAnnotationsRuleSet} instance. + * + * @param digesterLoader the parent DigesterLoader. + */ + protected FromAnnotationsRuleSet(DigesterLoader digesterLoader) { + this.digesterLoader = digesterLoader; + } + + /** + * {@inheritDoc} + */ + public void addRuleInstances(Digester digester) { + String pattern; + Rule rule; + for (Entry>> entry : + this.rules.entrySet()) { + pattern = entry.getKey(); + for (AnnotationRuleProvider provider : entry.getValue()) { + rule = provider.get(); + if (this.namespaceURI != null) { + rule.setNamespaceURI(this.namespaceURI); + } + digester.addRule(pattern, rule); + } + } + } + + /** + * Analyzes the target class and adds the {@link AnnotationRuleProvider}s to + * this {@link FromAnnotationsRuleSet}. + * + * @param target the class has to be analyzed. + */ + public void addRules(Class target) { + this.digesterLoader.addRulesTo(target, this); + } + + /** + * Builds and register an {@link AnnotationRuleProvider} for a specific + * pattern. + * + * @param the {@link AnnotationRuleProvider} type. + * @param pattern the pattern has to be associated to the rule provider. + * @param klass the {@link AnnotationRuleProvider} type has to be instantiated. + * @param annotation the current visited annotation. + * @param element the current visited element. + */ + public > + void addRuleProvider(String pattern, + Class klass, + A annotation, + E element) { + + T annotationRuleProvider = + this.digesterLoader.getAnnotationRuleProviderFactory().newInstance(klass); + annotationRuleProvider.init(annotation, element); + this.addRuleProvider(pattern, annotationRuleProvider); + } + + /** + * Register an {@link AnnotationRuleProvider} for a specific pattern. + * + * @param pattern the pattern has to be associated to the rule provider. + * @param ruleProvider the provider that builds the digester rule. + */ + @SuppressWarnings("unchecked") + public void addRuleProvider(String pattern, + AnnotationRuleProvider ruleProvider) { + List> rules; + + if (this.rules.containsKey(pattern)) { + rules = this.rules.get(pattern); + } else { + rules = new ArrayList>(); + this.rules.put(pattern, rules); + } + + rules.add((AnnotationRuleProvider) ruleProvider); + } + + /** + * Retrieves a specific instance of the {@link AnnotationRuleProvider} for + * the input pattern. + * + * @param the {@link AnnotationRuleProvider} type + * @param pattern the input pattern + * @param providerClass the {@link AnnotationRuleProvider} class + * @return an {@link AnnotationRuleProvider} for the input pattern if found, + * null otherwise. + */ + public > + T getProvider(String pattern, Class providerClass) { + + if (!this.rules.containsKey(pattern)) { + return null; + } + + for (AnnotationRuleProvider rule : this.rules.get(pattern)) { + if (providerClass.isInstance(rule)) { + return providerClass.cast(rule); + } + } + + return null; + } + + /** + * Add created {@link AnnotationRuleProvider}s created in another analysis + * session. + * + * @param ruleSet the {@code RuleSet} created in another analysis session. + */ + public void addRulesProviderFrom(final FromAnnotationsRuleSet ruleSet) { + this.rules.putAll(ruleSet.getRules()); + } + + /** + * Checks if this RuleSet builds Digester mapping rules for the input type. + * + * @param clazz the input type. + * @return true, if this RuleSet builds Digester mapping rules for the input + * type, false otherwise. + */ + protected boolean mapsClass(Class clazz) { + return this.mappedClasses.contains(clazz); + } + + /** + * Remember that this RuleSet is able to build Digester mapping rules for + * the input type. + * + * @param clazz the input type. + */ + protected void addMappedClass(Class clazz) { + this.mappedClasses.add(clazz); + } + + /** + * Returns the data structure the patterns/{@link AnnotationRuleProvider} + * pairs. + * + * @return the data structure the patterns/{@link AnnotationRuleProvider} + * pairs. + */ + private Map>> getRules() { + return this.rules; + } + + /** + * {@inheritDoc} + */ + public String getNamespaceURI() { + return this.namespaceURI; + } + + /** + * Sets the namespace URI that will be applied to all Rule instances + * created from this RuleSet. + * + * @param namespaceURI the namespace URI that will be applied to all Rule + * instances created from this RuleSet. + */ + public void setNamespaceURI(String namespaceURI) { + this.namespaceURI = namespaceURI; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return "{ mappedClasses=" + + this.mappedClasses + + ", rules=" + + this.rules.toString() + + ", namespaceURI=" + + this.namespaceURI + + " }"; + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/DefaultLoaderHandler.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/DefaultLoaderHandler.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/DefaultLoaderHandler.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,33 @@ +/* $Id: DefaultLoaderHandler.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.handlers; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +import org.apache.commons.digester.annotations.DigesterLoaderHandler; + +/** + * The DefaultLoaderHandler marks rules that have to be processed by the built-in + * Digester annotation rules engine. + * + * @since 2.1 + */ +public interface DefaultLoaderHandler extends DigesterLoaderHandler { + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/MethodHandler.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/MethodHandler.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/MethodHandler.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,137 @@ +/* $Id: MethodHandler.java 992091 2010-09-02 19:58:12Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.handlers; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.commons.digester.Rule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.CreationRule; +import org.apache.commons.digester.annotations.DigesterLoaderHandler; +import org.apache.commons.digester.annotations.DigesterLoadingException; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.FromAnnotationsRuleSet; +import org.apache.commons.digester.annotations.utils.AnnotationUtils; + +/** + * Handler that takes care to create the + * {@link org.apache.commons.digester.annotations.providers.SetNextRuleProvider} + * and + * {@link org.apache.commons.digester.annotations.providers.SetRootRuleProvider}. + * + * @since 2.1 + */ +public final class MethodHandler implements DigesterLoaderHandler { + + /** + * The default args size the method has to have in order to be analyzed. + */ + private static final int SUPPORTED_ARGS = 1; + + /** + * {@inheritDoc} + */ + public void handle(Annotation annotation, Method element, FromAnnotationsRuleSet ruleSet) { + if (SUPPORTED_ARGS != element.getParameterTypes().length) { + DigesterRule rule = annotation.annotationType().getAnnotation(DigesterRule.class); + + throw new DigesterLoadingException("Methods annotated with digester annotation rule @" + + rule.reflectsRule().getName() + + " must have just one argument"); + } + + Object explicitTypesObject = AnnotationUtils.getAnnotationValue(annotation); + if (explicitTypesObject == null + || !explicitTypesObject.getClass().isArray() + || Class.class != explicitTypesObject.getClass().getComponentType()) { + throw new DigesterLoadingException("Impossible to apply this handler, @" + + annotation.getClass().getName() + + ".value() has to be of type 'Class[]'"); + } + + Class[] explicitTypes = (Class[]) explicitTypesObject; + Class paramType = element.getParameterTypes()[0]; + + if (explicitTypes.length > 0) { + for (Class explicitType : explicitTypes) { + if (!paramType.isAssignableFrom(explicitType)) { + throw new DigesterLoadingException("Impossible to handle annotation " + + annotation + + " on method " + + element.toGenericString() + + ", " + + explicitType.getName() + + " has to be a " + + paramType.getName()); + } + + this.doHandle(annotation, element, explicitType, ruleSet); + } + } else { + this.doHandle(annotation, element, paramType, ruleSet); + } + } + + private void doHandle(Annotation methodAnnotation, Method method, Class type, FromAnnotationsRuleSet ruleSet) { + if (type.isInterface() + && Modifier.isAbstract(type.getModifiers())) { + throw new DigesterLoadingException("Impossible to proceed analyzing " + + methodAnnotation + + ", specified type '" + + type.getName() + + "' is an interface/abstract"); + } + + for (Annotation annotation : type.getAnnotations()) { + this.doHandle(methodAnnotation, annotation, method, type, ruleSet); + } + } + + @SuppressWarnings("unchecked") + private void doHandle(A methodAnnotation, + Annotation annotation, + Method method, + Class type, + FromAnnotationsRuleSet ruleSet) { + if (annotation.annotationType().isAnnotationPresent(DigesterRule.class) + && annotation.annotationType().isAnnotationPresent(CreationRule.class)) { + ruleSet.addRules(type); + + DigesterRule digesterRule = methodAnnotation.annotationType().getAnnotation(DigesterRule.class); + Class> providerType = + (Class>) digesterRule.providedBy(); + ruleSet.addRuleProvider(AnnotationUtils.getAnnotationPattern(annotation), + providerType, + methodAnnotation, + method); + } else if (annotation.annotationType().isAnnotationPresent(DigesterRuleList.class)) { + // check if it is one of the *.List annotation + Annotation[] annotations = AnnotationUtils.getAnnotationsArrayValue(annotation); + if (annotations != null) { + // if it is an annotations array, process them + for (Annotation ptr : annotations) { + this.doHandle(methodAnnotation, ptr, method, type, ruleSet); + } + } + } + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/SetPropertiesLoaderHandler.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/SetPropertiesLoaderHandler.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/SetPropertiesLoaderHandler.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,49 @@ +/* $Id: SetPropertiesLoaderHandler.java 992073 2010-09-02 19:37:06Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.handlers; + +import java.lang.reflect.Field; + +import org.apache.commons.digester.annotations.DigesterLoaderHandler; +import org.apache.commons.digester.annotations.FromAnnotationsRuleSet; +import org.apache.commons.digester.annotations.providers.SetPropertiesRuleProvider; +import org.apache.commons.digester.annotations.rules.SetProperty; + +/** + * Handler that takes care to create the {@link SetPropertiesRuleProvider}. + * + * @since 2.1 + */ +public final class SetPropertiesLoaderHandler implements DigesterLoaderHandler { + + /** + * {@inheritDoc} + */ + public void handle(SetProperty annotation, Field element, FromAnnotationsRuleSet ruleSet) { + SetPropertiesRuleProvider ruleProvider = + ruleSet.getProvider(annotation.pattern(), SetPropertiesRuleProvider.class); + + if (ruleProvider == null) { + ruleProvider = new SetPropertiesRuleProvider(); + ruleSet.addRuleProvider(annotation.pattern(), ruleProvider); + } + + ruleProvider.addAlias(annotation, element); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/handlers/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,24 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * The handlers package contains + * {@link org.apache.commons.digester.annotations.DigesterLoaderHandler} + * implementations. + */ +package org.apache.commons.digester.annotations.handlers; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/DefaultAnnotationRuleProviderFactory.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/DefaultAnnotationRuleProviderFactory.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/DefaultAnnotationRuleProviderFactory.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,49 @@ +/* $Id: DefaultAnnotationRuleProviderFactory.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.internal; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +import org.apache.commons.digester.Rule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.DigesterLoadingException; +import org.apache.commons.digester.annotations.spi.AnnotationRuleProviderFactory; + +/** + * Default {@link AnnotationRuleProviderFactory} implementation. + * + * @since 2.1 + */ +public final class DefaultAnnotationRuleProviderFactory implements AnnotationRuleProviderFactory { + + /** + * {@inheritDoc} + */ + public > + T newInstance(Class type) throws DigesterLoadingException { + try { + return type.newInstance(); + } catch (Exception e) { + throw new DigesterLoadingException("An error occurred while creating '" + + type + + "' instance", e); + } + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/DefaultDigesterLoaderHandlerFactory.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/DefaultDigesterLoaderHandlerFactory.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/DefaultDigesterLoaderHandlerFactory.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,48 @@ +/* $Id: DefaultDigesterLoaderHandlerFactory.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.internal; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +import org.apache.commons.digester.annotations.DigesterLoaderHandler; +import org.apache.commons.digester.annotations.DigesterLoadingException; +import org.apache.commons.digester.annotations.spi.DigesterLoaderHandlerFactory; + +/** + * Default {@link DigesterLoaderHandlerFactory} implementation. + * + * @since 2.1 + */ +public final class DefaultDigesterLoaderHandlerFactory implements DigesterLoaderHandlerFactory { + + /** + * {@inheritDoc} + */ + public > L newInstance( + Class type) throws DigesterLoadingException { + try { + return type.newInstance(); + } catch (Exception e) { + throw new DigesterLoadingException("An error occurred while creating '" + + type + + "' instance", e); + } + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/RuleSetCache.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/RuleSetCache.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/RuleSetCache.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,125 @@ +/* $Id: RuleSetCache.java 992080 2010-09-02 19:46:29Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.internal; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.digester.annotations.FromAnnotationsRuleSet; + +/** + * Simple in-memory LRU cache implementation. + * + * @since 2.1 + */ +public final class RuleSetCache implements Serializable { + + /** + * This class serialVersionUID. + */ + private static final long serialVersionUID = 1L; + + /** + * The fixed cache size. + */ + private final int cacheSize = 255; + + /** + * The fixed cache load facor. + */ + private final float loadFactor = 0.75f; + + /** + * The fixed cache capacity. + */ + private final int capacity = (int) Math.ceil(this.cacheSize / this.loadFactor) + 1; + + /** + * The map that implements the LRU cache. + */ + private final Map, FromAnnotationsRuleSet> data = + new LinkedHashMap, FromAnnotationsRuleSet>(capacity, loadFactor) { + + /** + * This class serialVersionUID. + */ + private static final long serialVersionUID = 1L; + + /** + * {@inheritDoc} + */ + @Override + protected boolean removeEldestEntry(Map.Entry, FromAnnotationsRuleSet> eldest) { + return size() > cacheSize; + } + }; + + /** + * Returns true if this cache contains a mapping for the specified key. + * + * @param key key whose presence in this map is to be tested. + * @return true if this map contains a mapping for the specified key, false + * otherwise. + */ + public boolean containsKey(Class key) { + checkKey(key); + return this.data.containsKey(key); + } + + /** + * Returns the value to which the specified key is cached, or null if this + * cache contains no mapping for the key. + * + * Key parameter must not be null. + * + * @param key the key has to be checked it is present, it must not be null. + * @return the value to which the specified key is cached, null if this + * cache contains no mapping for the key. + */ + public FromAnnotationsRuleSet get(Class key) { + checkKey(key); + return this.data.get(key); + } + + /** + * Associates the specified value with the specified key in this cache. + * + * Key parameter must not be null. + * + * @param key key with which the specified value is to be associated. + * @param value value to be associated with the specified key. + */ + public void put(Class key, FromAnnotationsRuleSet value) { + checkKey(key); + this.data.put(key, value); + } + + /** + * Verify that a key is not null. + * + * @param the generic key type. + * @param key the key object. + */ + private static void checkKey(Class key) { + if (key == null) { + throw new IllegalArgumentException("null keys not supported"); + } + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/internal/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,22 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * This package contains internal use only classes, users can ignore it. + */ +package org.apache.commons.digester.annotations.internal; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,23 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * The annotations package provides for Java5 Annotations + * meta data-based definition of rules for Digester. + */ +package org.apache.commons.digester.annotations; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/AttributeCallParamRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/AttributeCallParamRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/AttributeCallParamRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,53 @@ +/* $Id: AttributeCallParamRuleProvider.java 992746 2010-09-05 09:31:53Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import org.apache.commons.digester.CallParamRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.reflect.MethodArgument; +import org.apache.commons.digester.annotations.rules.AttributeCallParam; + +/** + * Provides instances of {@link CallParamRule}. + * + * @see CallParamRule#CallParamRule(int,String) + * @since 2.1 + */ +public final class AttributeCallParamRuleProvider + implements AnnotationRuleProvider { + + private String attribute; + + private int index; + + /** + * {@inheritDoc} + */ + public void init(AttributeCallParam annotation, MethodArgument element) { + this.attribute = annotation.attribute(); + this.index = element.getIndex(); + } + + /** + * {@inheritDoc} + */ + public CallParamRule get() { + return new CallParamRule(this.index, this.attribute); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/BeanPropertySetterRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/BeanPropertySetterRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/BeanPropertySetterRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,50 @@ +/* $Id: BeanPropertySetterRuleProvider.java 992074 2010-09-02 19:38:01Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import java.lang.reflect.Field; + +import org.apache.commons.digester.BeanPropertySetterRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.rules.BeanPropertySetter; + +/** + * Provides instances of {@code BeanPropertySetterRule}. + * + * @since 2.1 + */ +public final class BeanPropertySetterRuleProvider + implements AnnotationRuleProvider { + + private String name; + + /** + * {@inheritDoc} + */ + public void init(BeanPropertySetter annotation, Field element) { + this.name = element.getName(); + } + + /** + * {@inheritDoc} + */ + public BeanPropertySetterRule get() { + return new BeanPropertySetterRule(this.name); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/CallMethodRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/CallMethodRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/CallMethodRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,54 @@ +/* $Id: CallMethodRuleProvider.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import java.lang.reflect.Method; + +import org.apache.commons.digester.CallMethodRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.rules.CallMethod; + +/** + * Provides instances of {@code CallMethodRule} + * + * @since 2.1 + */ +public final class CallMethodRuleProvider implements AnnotationRuleProvider { + + private String methodName; + + private Class[] parameterTypes; + + /** + * {@inheritDoc} + */ + public void init(CallMethod annotation, Method element) { + this.methodName = element.getName(); + this.parameterTypes = element.getParameterTypes(); + } + + /** + * {@inheritDoc} + */ + public CallMethodRule get() { + return new CallMethodRule(this.methodName, + this.parameterTypes.length, + this.parameterTypes); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/CallParamRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/CallParamRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/CallParamRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,49 @@ +/* $Id: CallParamRuleProvider.java 992746 2010-09-05 09:31:53Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import org.apache.commons.digester.CallParamRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.reflect.MethodArgument; +import org.apache.commons.digester.annotations.rules.CallParam; + +/** + * Provides instances of {@link CallParamRule}. + * + * @see CallParamRule#CallParamRule(int) + * @since 2.1 + */ +public final class CallParamRuleProvider implements AnnotationRuleProvider { + + private int index; + + /** + * {@inheritDoc} + */ + public void init(CallParam annotation, MethodArgument element) { + this.index = element.getIndex(); + } + + /** + * {@inheritDoc} + */ + public CallParamRule get() { + return new CallParamRule(this.index); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/FactoryCreateRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/FactoryCreateRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/FactoryCreateRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,52 @@ +/* $Id: FactoryCreateRuleProvider.java 992068 2010-09-02 19:24:16Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import org.apache.commons.digester.FactoryCreateRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.rules.FactoryCreate; + +/** + * Provides instances of {@link FactoryCreateRule}. + * + * @since 2.1 + */ +public final class FactoryCreateRuleProvider + implements AnnotationRuleProvider, FactoryCreateRule> { + + private Class factoryClass; + + private boolean ignoreCreateExceptions; + + /** + * {@inheritDoc} + */ + public void init(FactoryCreate annotation, Class element) { + this.factoryClass = annotation.factoryClass(); + this.ignoreCreateExceptions = annotation.ignoreCreateExceptions(); + } + + /** + * {@inheritDoc} + */ + public FactoryCreateRule get() { + return new FactoryCreateRule(this.factoryClass, + this.ignoreCreateExceptions); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/ObjectCreateRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/ObjectCreateRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/ObjectCreateRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,48 @@ +/* $Id: ObjectCreateRuleProvider.java 992096 2010-09-02 20:06:04Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import org.apache.commons.digester.ObjectCreateRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.rules.ObjectCreate; + +/** + * Provides instances of {@link ObjectCreateRule}. + * + * @since 2.1 + */ +public final class ObjectCreateRuleProvider + implements AnnotationRuleProvider, ObjectCreateRule> { + + private Class clazz; + + /** + * {@inheritDoc} + */ + public void init(ObjectCreate annotation, Class element) { + this.clazz = element; + } + + /** + * {@inheritDoc} + */ + public ObjectCreateRule get() { + return new ObjectCreateRule(this.clazz); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/PathCallParamRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/PathCallParamRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/PathCallParamRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,49 @@ +/* $Id: PathCallParamRuleProvider.java 992093 2010-09-02 19:59:20Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import org.apache.commons.digester.PathCallParamRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.reflect.MethodArgument; +import org.apache.commons.digester.annotations.rules.PathCallParam; + +/** + * Provides instances of {@link PathCallParamRule}. + * + * @since 2.1 + */ +public final class PathCallParamRuleProvider + implements AnnotationRuleProvider { + + private int index; + + /** + * {@inheritDoc} + */ + public void init(PathCallParam annotation, MethodArgument element) { + this.index = element.getIndex(); + } + + /** + * {@inheritDoc} + */ + public PathCallParamRule get() { + return new PathCallParamRule(this.index); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetNextRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetNextRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetNextRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,52 @@ +/* $Id: SetNextRuleProvider.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import java.lang.reflect.Method; + +import org.apache.commons.digester.SetNextRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.rules.SetNext; + +/** + * Provides instances of {@link SetNextRule}. + * + * @since 2.1 + */ +public final class SetNextRuleProvider implements AnnotationRuleProvider { + + private String methodName; + + private String paramType; + + /** + * {@inheritDoc} + */ + public void init(SetNext annotation, Method element) { + this.methodName = element.getName(); + this.paramType = element.getParameterTypes()[0].getName(); + } + + /** + * {@inheritDoc} + */ + public SetNextRule get() { + return new SetNextRule(this.methodName, this.paramType); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetPropertiesRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetPropertiesRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetPropertiesRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,82 @@ +/* $Id: SetPropertiesRuleProvider.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.digester.SetPropertiesRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.rules.SetProperty; + +/** + * Provides instances of {@code SetPropertiesRule}. + * + * @since 2.1 + */ +public final class SetPropertiesRuleProvider implements AnnotationRuleProvider { + + /** + * The data structure that stores the aliases. + */ + private final Map aliases = new HashMap(); + + /** + * {@inheritDoc} + */ + public void init(SetProperty annotation, Field element) { + this.addAlias(annotation, element); + } + + /** + * Adds a new alias attribute/property name; if the attribute name is not + * specified, the alias will be considered as property name identity. + * + * @param annotation the {@link SetProperty} reference. + * @param element the annotated element reference. + */ + public void addAlias(SetProperty annotation, Field element) { + String attributeName = annotation.attributeName(); + String propertyName = element.getName(); + + if (attributeName.length() > 0) { + this.aliases.put(attributeName, propertyName); + } else { + this.aliases.put(propertyName, propertyName); + } + } + + /** + * {@inheritDoc} + */ + public SetPropertiesRule get() { + String[] attributeNames = new String[this.aliases.size()]; + String[] propertyNames = new String[this.aliases.size()]; + + int i = 0; + for (Entry alias : this.aliases.entrySet()) { + attributeNames[i] = alias.getKey(); + propertyNames[i++] = alias.getValue(); + } + + return new SetPropertiesRule(attributeNames, propertyNames); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetRootRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetRootRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetRootRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,52 @@ +/* $Id: SetRootRuleProvider.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import java.lang.reflect.Method; + +import org.apache.commons.digester.SetRootRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.rules.SetRoot; + +/** + * Provides instances of {@link SetRootRule}. + * + * @since 2.1 + */ +public final class SetRootRuleProvider implements AnnotationRuleProvider{ + + private String methodName; + + private String paramType; + + /** + * {@inheritDoc} + */ + public void init(SetRoot annotation, Method element) { + this.methodName = element.getName(); + this.paramType = element.getParameterTypes()[0].getName(); + } + + /** + * {@inheritDoc} + */ + public SetRootRule get() { + return new SetRootRule(this.methodName, this.paramType); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetTopRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetTopRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/SetTopRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,52 @@ +/* $Id: SetTopRuleProvider.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import java.lang.reflect.Method; + +import org.apache.commons.digester.SetTopRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.rules.SetTop; + +/** + * Provides instances of {@link SetTopRule}. + * + * @since 2.1 + */ +public final class SetTopRuleProvider implements AnnotationRuleProvider{ + + private String methodName; + + private String paramType; + + /** + * {@inheritDoc} + */ + public void init(SetTop annotation, Method element) { + this.methodName = element.getName(); + this.paramType = element.getParameterTypes()[0].getName(); + } + + /** + * {@inheritDoc} + */ + public SetTopRule get() { + return new SetTopRule(this.methodName, this.paramType); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/StackCallParamRuleProvider.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/StackCallParamRuleProvider.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/StackCallParamRuleProvider.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,53 @@ +/* $Id: StackCallParamRuleProvider.java 992746 2010-09-05 09:31:53Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.providers; + +import org.apache.commons.digester.CallParamRule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.reflect.MethodArgument; +import org.apache.commons.digester.annotations.rules.StackCallParam; + +/** + * Provides instances of {@link CallParamRule}. + * + * @see CallParamRule#CallParamRule(int,int) + * @since 2.1 + */ +public final class StackCallParamRuleProvider + implements AnnotationRuleProvider { + + private int paramIndex; + + private int stackIndex; + + /** + * {@inheritDoc} + */ + public void init(StackCallParam annotation, MethodArgument element) { + this.paramIndex = element.getIndex(); + this.stackIndex = annotation.stackIndex(); + } + + /** + * {@inheritDoc} + */ + public CallParamRule get() { + return new CallParamRule(this.paramIndex, this.stackIndex); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/providers/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,24 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * This package contains + * {@link org.apache.commons.digester.annotations.AnnotationRuleProvider} + * implementations. + */ +package org.apache.commons.digester.annotations.providers; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/reflect/MethodArgument.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/reflect/MethodArgument.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/reflect/MethodArgument.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,128 @@ +/* $Id: MethodArgument.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.reflect; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +/** + * Class to supply the missing Java {@code AnnotatedElement} for method + * arguments. + * + * @since 2.1 + */ +public final class MethodArgument implements AnnotatedElement { + + /** + * The method argument index. + */ + private final int index; + + /** + * The method argument type. + */ + private final Class parameterType; + + /** + * The method argument annotations. + */ + private final Annotation[] annotations; + + /** + * Creates a new method argument as {@code AnnotatedElement}. + * + * @param index the method argument index. + * @param parameterType the method argument type. + * @param annotations the method argument annotations. + */ + public MethodArgument(int index, Class parameterType, Annotation[] annotations) { + this.index = index; + this.parameterType = parameterType; + this.annotations = annotations; + } + + /** + * Returns the method argument index. + * + * @return the method argument index. + */ + public int getIndex() { + return this.index; + } + + /** + * Returns the method argument type. + * + * @return the method argument type. + */ + public Class getParameterType() { + return this.parameterType; + } + + /** + * {@inheritDoc} + */ + public T getAnnotation(Class annotationType) { + for (Annotation annotation : this.annotations) { + if (annotationType == annotation.annotationType()) { + return annotationType.cast(annotation); + } + } + return null; + } + + /** + * {@inheritDoc} + */ + public Annotation[] getAnnotations() { + return this.getAnnotationsArrayCopy(); + } + + /** + * {@inheritDoc} + */ + public Annotation[] getDeclaredAnnotations() { + return this.getAnnotationsArrayCopy(); + } + + /** + * Returns an annotations array, copy of the declared annotations in this + * method argument. + * + * @return an annotations array, copy of the declared annotations in this + * method argument. + */ + private Annotation[] getAnnotationsArrayCopy() { + Annotation[] annotations = new Annotation[this.annotations.length]; + System.arraycopy(this.annotations, 0, annotations, 0, annotations.length); + return annotations; + } + + /** + * {@inheritDoc} + */ + public boolean isAnnotationPresent(Class annotationType) { + for (Annotation annotation : this.annotations) { + if (annotationType == annotation.annotationType()) { + return true; + } + } + return false; + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/reflect/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/reflect/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/reflect/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,23 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * The reflect package supply missing JVM classes to alow user + * manipulate entities as {@link java.lang.reflect.AnnotatedElement}. + */ +package org.apache.commons.digester.annotations.reflect; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/AttributeCallParam.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/AttributeCallParam.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/AttributeCallParam.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,74 @@ +/* $Id: AttributeCallParam.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.CallParamRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.providers.AttributeCallParamRuleProvider; + +/** + * Methods arguments annotated with {@code AttributeCallParam} will be bound + * with {@code CallParamRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addCallParam(String,int,String) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@DigesterRule( + reflectsRule = CallParamRule.class, + providedBy = AttributeCallParamRuleProvider.class +) +public @interface AttributeCallParam { + + /** + * Attribute whose value is used as the parameter value. + * + * @return the attribute whose value is used as the parameter value. + */ + String attribute(); + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * Defines several {@code @AttributeCallParam} annotations on the same element. + * + * @see AttributeCallParam + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + AttributeCallParam[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/BeanPropertySetter.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/BeanPropertySetter.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/BeanPropertySetter.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,67 @@ +/* $Id: BeanPropertySetter.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.BeanPropertySetterRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.providers.BeanPropertySetterRuleProvider; + +/** + * Fields annotated with {@code BeanPropertySetter} will be bound with + * {@code BeanPropertySetterRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addBeanPropertySetter(String,String) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@DigesterRule( + reflectsRule = BeanPropertySetterRule.class, + providedBy = BeanPropertySetterRuleProvider.class +) +public @interface BeanPropertySetter { + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * Defines several {@code @BeanPropertySetter} annotations on the same element. + * + * @see BeanPropertySetter + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + BeanPropertySetter[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/CallMethod.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/CallMethod.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/CallMethod.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,67 @@ +/* $Id: CallMethod.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.CallMethodRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.providers.CallMethodRuleProvider; + +/** + * Methods annotated with {@code CallMethod} will be bound with + * {@code CallMethodRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addCallMethod(String,String,int,Class[]) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@DigesterRule( + reflectsRule = CallMethodRule.class, + providedBy = CallMethodRuleProvider.class +) +public @interface CallMethod { + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * Defines several {@code @CallMethod} annotations on the same element. + * + * @see CallMethod + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + CallMethod[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/CallParam.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/CallParam.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/CallParam.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,67 @@ +/* $Id: CallParam.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.CallParamRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.providers.CallParamRuleProvider; + +/** + * Methods arguments annotated with {@code CallParam} will be bound with + * {@code CallParamRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addCallParam(String,int) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@DigesterRule( + reflectsRule = CallParamRule.class, + providedBy = CallParamRuleProvider.class +) +public @interface CallParam { + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * Defines several {@code @CallParam} annotations on the same element. + * + * @see CallParam + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + CallParam[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/FactoryCreate.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/FactoryCreate.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/FactoryCreate.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,85 @@ +/* $Id: FactoryCreate.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.AbstractObjectCreationFactory; +import org.apache.commons.digester.FactoryCreateRule; +import org.apache.commons.digester.annotations.CreationRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.providers.FactoryCreateRuleProvider; + +/** + * Classes annotated with {@code FactoryCreate} will be bound with + * {@code FactoryCreateRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addFactoryCreate(String,org.apache.commons.digester.ObjectCreationFactory,boolean) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@CreationRule +@DigesterRule( + reflectsRule = FactoryCreateRule.class, + providedBy = FactoryCreateRuleProvider.class +) +public @interface FactoryCreate { + + /** + * The Java class of the object creation factory class + * + * @return the Java class of the object creation factory class. + */ + Class factoryClass(); + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * When true any exceptions thrown during object creation will be ignored. + * + * @return when true any exceptions thrown during object creation will be + * ignored. + */ + boolean ignoreCreateExceptions() default false; + + /** + * Defines several {@code @FactoryCreate} annotations on the same element. + * + * @see FactoryCreate + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + FactoryCreate[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/ObjectCreate.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/ObjectCreate.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/ObjectCreate.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,69 @@ +/* $Id: ObjectCreate.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.ObjectCreateRule; +import org.apache.commons.digester.annotations.CreationRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.providers.ObjectCreateRuleProvider; + +/** + * Classes annotated with {@code ObjectCreate} will be bound with + * {@code ObjectCreateRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addObjectCreate(String,Class) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@CreationRule +@DigesterRule( + reflectsRule = ObjectCreateRule.class, + providedBy = ObjectCreateRuleProvider.class +) +public @interface ObjectCreate { + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * Defines several {@code @ObjectCreate} annotations on the same element. + * + * @see ObjectCreate + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + ObjectCreate[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/PathCallParam.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/PathCallParam.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/PathCallParam.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,67 @@ +/* $Id: PathCallParam.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.PathCallParamRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.providers.PathCallParamRuleProvider; + +/** + * Methods arguments annotated with {@code PathCallParam} will be bound + * with {@code PathCallParamRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addCallParamPath(String,int) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@DigesterRule( + reflectsRule = PathCallParamRule.class, + providedBy = PathCallParamRuleProvider.class +) +public @interface PathCallParam { + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * Defines several {@code @PathCallParam} annotations on the same element. + * + * @see PathCallParam + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + PathCallParam[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetNext.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetNext.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetNext.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,57 @@ +/* $Id: SetNext.java 992732 2010-09-05 08:44:36Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.SetNextRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.handlers.MethodHandler; +import org.apache.commons.digester.annotations.providers.SetNextRuleProvider; + +/** + * Methods annotated with {@code SetNext} will be bound + * with {@code SetNextRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addSetNext(String,String,String) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@DigesterRule( + reflectsRule = SetNextRule.class, + providedBy = SetNextRuleProvider.class, + handledBy = MethodHandler.class +) +public @interface SetNext { + + /** + * Defines the concrete implementation(s) of @SetNext annotated method + * argument. + * + * @return the concrete implementation(s) of @SetNext annotated method + * argument. + */ + Class[] value() default {}; + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetProperty.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetProperty.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetProperty.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,76 @@ +/* $Id: SetProperty.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.SetPropertiesRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.handlers.SetPropertiesLoaderHandler; +import org.apache.commons.digester.annotations.providers.SetPropertiesRuleProvider; + +/** + * Fields annotated with {@code SetProperty} will be bound + * with {@code SetPropertiesRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addSetProperties(String,String[],String[]) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@DigesterRule( + reflectsRule = SetPropertiesRule.class, + providedBy = SetPropertiesRuleProvider.class, + handledBy = SetPropertiesLoaderHandler.class +) +public @interface SetProperty { + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * The overridden parameter. + * + * @return the overridden parameter. + */ + String attributeName() default ""; + + /** + * Defines several {@code @SetProperty} annotations on the same element. + * + * @see SetProperty + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + SetProperty[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetRoot.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetRoot.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetRoot.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,57 @@ +/* $Id: SetRoot.java 992732 2010-09-05 08:44:36Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.SetRootRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.handlers.MethodHandler; +import org.apache.commons.digester.annotations.providers.SetRootRuleProvider; + +/** + * Methods annotated with {@code SetRoot} will be bound + * with {@code SetRootRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addSetRoot(String,String,String) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@DigesterRule( + reflectsRule = SetRootRule.class, + providedBy = SetRootRuleProvider.class, + handledBy = MethodHandler.class +) +public @interface SetRoot { + + /** + * Defines the concrete implementation(s) of @SetRoot annotated method + * argument. + * + * @return the concrete implementation(s) of @SetRoot annotated method + * argument. + */ + Class[] value() default {}; + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetTop.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetTop.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/SetTop.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,67 @@ +/* $Id: SetTop.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.SetTopRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.providers.SetTopRuleProvider; + +/** + * Methods annotated with {@code SetTop} will be bound + * with {@code SetTopRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addSetTop(String,String,String) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@DigesterRule( + reflectsRule = SetTopRule.class, + providedBy = SetTopRuleProvider.class +) +public @interface SetTop { + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * Defines several {@code @SetTop} annotations on the same element + * + * @see SetTop + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + SetTop[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/StackCallParam.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/StackCallParam.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/StackCallParam.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,75 @@ +/* $Id: StackCallParam.java 992750 2010-09-05 09:54:37Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.rules; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.commons.digester.CallParamRule; +import org.apache.commons.digester.annotations.DigesterRule; +import org.apache.commons.digester.annotations.DigesterRuleList; +import org.apache.commons.digester.annotations.providers.StackCallParamRuleProvider; + +/** + * Methods arguments annotated with {@code StackCallParam} will be bound + * with {@code CallParamRule} digester rule. + * + * @see org.apache.commons.digester.Digester#addCallParam(String,int,int) + * @since 2.1 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@DigesterRule( + reflectsRule = CallParamRule.class, + providedBy = StackCallParamRuleProvider.class +) +public @interface StackCallParam { + + /** + * The element matching pattern. + * + * @return the element matching pattern. + */ + String pattern(); + + /** + * 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. + * + * @return the stackIndex'th object down the stack. + */ + int stackIndex() default 0; + + /** + * Defines several {@code StackCallParam} annotations on the same element. + * + * @see StackCallParam + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @DigesterRuleList + @interface List { + StackCallParam[] value(); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/rules/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,22 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * Classes contained in this package are annotations that reflect Digester rules. + */ +package org.apache.commons.digester.annotations.rules; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/spi/AnnotationRuleProviderFactory.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/spi/AnnotationRuleProviderFactory.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/spi/AnnotationRuleProviderFactory.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,46 @@ +/* $Id: AnnotationRuleProviderFactory.java 992719 2010-09-05 07:49:25Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.spi; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +import org.apache.commons.digester.Rule; +import org.apache.commons.digester.annotations.AnnotationRuleProvider; +import org.apache.commons.digester.annotations.DigesterLoadingException; + +/** + * An object capable of providing instances of {@link AnnotationRuleProvider}. + * + * @since 2.1 + */ +public interface AnnotationRuleProviderFactory { + + /** + * Return an {@link AnnotationRuleProvider} instance of the specified type. + * + * @param the {@link AnnotationRuleProvider} type. + * @param type the class of the object to be returned. + * @return an instance of the specified class. + * @throws DigesterLoadingException if any error occurs while creating the + * {@code type} instance. + */ + > + T newInstance(Class type) throws DigesterLoadingException; + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/spi/DigesterLoaderHandlerFactory.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/spi/DigesterLoaderHandlerFactory.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/spi/DigesterLoaderHandlerFactory.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,45 @@ +/* $Id: DigesterLoaderHandlerFactory.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.spi; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +import org.apache.commons.digester.annotations.DigesterLoaderHandler; +import org.apache.commons.digester.annotations.DigesterLoadingException; + +/** + * An object capable of providing instances of {@link DigesterLoaderHandler}. + * + * @since 2.1 + */ +public interface DigesterLoaderHandlerFactory { + + /** + * Return an instance of the specified type. + * + * @param + * @param type the class of the object to be returned. + * @return an instance of the specified class. + * @throws DigesterLoadingException if any error occurs while creating the + * {@code type} instance. + */ + > L newInstance( + Class type) throws DigesterLoadingException; + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/spi/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/spi/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/spi/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,22 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * Contains annotations package SPI definition. + */ +package org.apache.commons.digester.annotations.spi; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/utils/AnnotationUtils.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/utils/AnnotationUtils.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/utils/AnnotationUtils.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,104 @@ +/* $Id: AnnotationUtils.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.annotations.utils; + +import java.lang.annotation.Annotation; + +import org.apache.commons.beanutils.MethodUtils; + +/** + * Simple utility class to introspect annotations. + * + * @since 2.1 + */ +public class AnnotationUtils { + + /** + * The {@code value} string constant. + */ + private static final String VALUE = "value"; + + /** + * The {@code pattern} string constant. + */ + private static final String PATTERN = "pattern"; + + /** + * This class can't be instantiated. + */ + private AnnotationUtils() { + // this class can' be instantiated + } + + /** + * Extract the {@code value()} from annotation. + * + * @param annotation the annotation has to be introspected. + * @return the annotation {@code value()}. + */ + public static Object getAnnotationValue(Annotation annotation) { + return invokeAnnotationMethod(annotation, VALUE); + } + + /** + * Extract the {@code pattern()} from annotation. + * + * @param annotation the annotation has to be introspected. + * @return the annotation {@code pattern()}. + */ + public static String getAnnotationPattern(Annotation annotation) { + Object ret = invokeAnnotationMethod(annotation, PATTERN); + if (ret != null) { + return (String) ret; + } + return null; + } + + /** + * Extract the Annotations array {@code value()} from annotation if present, + * nul otherwise. + * + * @param annotation the annotation has to be introspected. + * @return the annotation {@code value()} as Annotations array. + */ + public static Annotation[] getAnnotationsArrayValue(Annotation annotation) { + Object value = getAnnotationValue(annotation); + if (value != null + && value.getClass().isArray() + && Annotation.class.isAssignableFrom(value.getClass().getComponentType())) { + return (Annotation[]) value; + } + return null; + } + + /** + * Invokes an annotation method. + * + * @param annotationn the annotation has to be introspected. + * @param method the method name to execute. + * @return the annotation method value, null if any error occurs. + */ + private static Object invokeAnnotationMethod(Annotation annotation, String method) { + try { + return MethodUtils.invokeExactMethod(annotation, method, null); + } catch (Throwable t) { + return null; + } + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/utils/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/utils/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/annotations/utils/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,22 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * Contains commons utilities classes for Java5 Annotations manipulation. + */ +package org.apache.commons.digester.annotations.utils; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,25 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * The xmlrules package provides for XML-based definition of + * rules for Digester. This improves maintainability of Java code, + * as rules are now defined in XML and read into Digester + * at run-time. + */ +package org.apache.commons.digester; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/parser/GenericParser.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/parser/GenericParser.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/parser/GenericParser.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,92 @@ +/* $Id: GenericParser.java 992077 2010-09-02 19:45:22Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.parser; + +import java.util.Properties; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; + +/** + * Create a SAXParser configured to support XML Schema and DTD. + * + * @since 1.6 + * @deprecated Create an XMLParser instance yourself, configure validation + * appropriately, and pass it as a parameter to the + * {@link org.apache.commons.digester.Digester} constructor, or use + * {@link org.apache.commons.digester.Digester#setXMLSchema(javax.xml.validation.Schema)} for validation. + */ + +@Deprecated +public class GenericParser{ + + /** + * The Log to which all SAX event related logging calls will be made. + */ + protected static Log log = + LogFactory.getLog("org.apache.commons.digester.Digester.sax"); + + /** + * The JAXP 1.2 property required to set up the schema location. + */ + private static final String JAXP_SCHEMA_SOURCE = + "http://java.sun.com/xml/jaxp/properties/schemaSource"; + + /** + * The JAXP 1.2 property to set up the schemaLanguage used. + */ + protected static String JAXP_SCHEMA_LANGUAGE = + "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + + /** + * Create a SAXParser configured to support XML Scheman and DTD + * @param properties parser specific properties/features + * @return an XML Schema/DTD enabled SAXParser + */ + public static SAXParser newSAXParser(Properties properties) + throws ParserConfigurationException, + SAXException, + SAXNotRecognizedException{ + + SAXParserFactory factory = + (SAXParserFactory)properties.get("SAXParserFactory"); + SAXParser parser = factory.newSAXParser(); + String schemaLocation = (String)properties.get("schemaLocation"); + String schemaLanguage = (String)properties.get("schemaLanguage"); + + try{ + if (schemaLocation != null) { + parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage); + parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation); + } + } catch (SAXNotRecognizedException e){ + log.info(parser.getClass().getName() + ": " + + e.getMessage() + " not supported."); + } + return parser; + } + +} \ No newline at end of file Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/parser/XercesParser.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/parser/XercesParser.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/parser/XercesParser.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,200 @@ +/* $Id: XercesParser.java 992082 2010-09-02 19:50:06Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.parser; + +import java.lang.reflect.Method; +import java.util.Properties; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * Create a SAXParser based on the underlying Xerces version. + * Currently, Xerces 2.3 and up doesn't implement schema validation the same way + * 2.1 was. In other to support schema validation in a portable way between + * parser, some features/properties need to be set. + * + * @since 1.6 + * @deprecated Create an XMLParser instance yourself, configure validation + * appropriately, and pass it as a parameter to the + * {@link org.apache.commons.digester.Digester} constructor, or use + * {@link org.apache.commons.digester.Digester#setXMLSchema(javax.xml.validation.Schema)} for validation. + */ + +@Deprecated +public class XercesParser{ + + /** + * The Log to which all SAX event related logging calls will be made. + */ + protected static Log log = + LogFactory.getLog("org.apache.commons.digester.Digester.sax"); + + + /** + * The JAXP 1.2 property required to set up the schema location. + */ + private static final String JAXP_SCHEMA_SOURCE = + "http://java.sun.com/xml/jaxp/properties/schemaSource"; + + + /** + * The JAXP 1.2 property to set up the schemaLanguage used. + */ + protected static String JAXP_SCHEMA_LANGUAGE = + "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + + + /** + * Xerces dynamic validation property + */ + protected static String XERCES_DYNAMIC = + "http://apache.org/xml/features/validation/dynamic"; + + + /** + * Xerces schema validation property + */ + protected static String XERCES_SCHEMA = + "http://apache.org/xml/features/validation/schema"; + + + /** + * A float representing the underlying Xerces version + */ + protected static float version; + + + /** + * The current Xerces version. + */ + protected static String versionNumber = null; + + + /** + * Return the current Xerces version. + * @return the current Xerces version. + */ + private static String getXercesVersion() { + // If for some reason we can't get the version, set it to 1.0. + String versionNumber = "1.0"; + try{ + // Use reflection to avoid a build dependency with Xerces. + Class versionClass = + Class.forName("org.apache.xerces.impl.Version"); + // Will return Xerces-J 2.x.0 + Method method = + versionClass.getMethod("getVersion", (Class[])null); + String version = (String)method.invoke(null, (Object[])null); + versionNumber = version.substring( "Xerces-J".length() , + version.lastIndexOf(".") ); + } catch (Exception ex){ + // Do nothing. + } + return versionNumber; + } + + + /** + * Create a SAXParser based on the underlying + * Xerces version. + * @param properties parser specific properties/features + * @return an XML Schema/DTD enabled SAXParser + */ + public static SAXParser newSAXParser(Properties properties) + throws ParserConfigurationException, + SAXException, + SAXNotSupportedException { + + SAXParserFactory factory = + (SAXParserFactory)properties.get("SAXParserFactory"); + + if (versionNumber == null){ + versionNumber = getXercesVersion(); + version = new Float( versionNumber ).floatValue(); + } + + // Note: 2.2 is completely broken (with XML Schema). + if (version > 2.1) { + + configureXerces(factory); + return factory.newSAXParser(); + } else { + SAXParser parser = factory.newSAXParser(); + configureOldXerces(parser,properties); + return parser; + } + } + + + /** + * Configure schema validation as recommended by the JAXP 1.2 spec. + * The properties object may contains information about + * the schema local and language. + * @param properties parser optional info + */ + private static void configureOldXerces(SAXParser parser, + Properties properties) + throws ParserConfigurationException, + SAXNotSupportedException { + + String schemaLocation = (String)properties.get("schemaLocation"); + String schemaLanguage = (String)properties.get("schemaLanguage"); + + try{ + if (schemaLocation != null) { + parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage); + parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation); + } + } catch (SAXNotRecognizedException e){ + log.info(parser.getClass().getName() + ": " + + e.getMessage() + " not supported."); + } + + } + + + /** + * Configure schema validation as recommended by the Xerces spec. + * Both DTD and Schema validation will be enabled simultaneously. + *

+ * NOTE: This method is broken. It is supposed to set up validation + * against the schema specified in property "schemaLocation", but + * it doesn't. + * + * @param factory SAXParserFactory to be configured + */ + private static void configureXerces(SAXParserFactory factory) + throws ParserConfigurationException, + SAXNotRecognizedException, + SAXNotSupportedException { + + factory.setFeature(XERCES_DYNAMIC, true); + factory.setFeature(XERCES_SCHEMA, true); + + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/parser/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/parser/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/parser/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,25 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * DEPRECATED PACKAGE:
+ * This package contains legacy schema support code used in the v1.x line of + * Digester releases. Starting v2.0, the recommended way to use schema + * validation is via the javax.xml.validation.Schema support. + */ +package org.apache.commons.digester.parser; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/Declaration.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/Declaration.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/Declaration.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,216 @@ +/* $Id: Declaration.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins; + +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.digester.Digester; + +/** + * Represents a Class that can be instantiated by a PluginCreateRule, plus + * info on how to load custom digester rules for mapping xml into that + * plugged-in class. + * + * @since 1.6 + */ +public class Declaration { + + /** The class of the object to be instantiated. */ + private Class pluginClass; + + /** The name of the class of the object to be instantiated. */ + private String pluginClassName; + + /** See {@link #setId}. */ + private String id; + + /** See {@link #setProperties}. */ + private Properties properties = new Properties(); + + /** See {@link #init}. */ + private boolean initialized = false; + + /** + * Class which is responsible for dynamically loading this + * plugin's rules on demand. + */ + private RuleLoader ruleLoader = null; + + //---------------------- constructors ---------------------------------- + + /** + * Constructor. + */ + public Declaration(String pluginClassName) { + // We can't load the pluginClass at this time, because we don't + // have a digester instance yet to load it through. So just + // save the name away, and we'll load the Class object in the + // init method. + this.pluginClassName = pluginClassName; + } + + /** + * Constructor. + */ + public Declaration(Class pluginClass) { + this.pluginClass = pluginClass; + this.pluginClassName = pluginClass.getName(); + } + + /** + * Create an instance where a fully-initialised ruleLoader instance + * is provided by the caller instead of having the PluginManager + * "discover" an appropriate one. + */ + public Declaration(Class pluginClass, RuleLoader ruleLoader) { + this.pluginClass = pluginClass; + this.pluginClassName = pluginClass.getName(); + this.ruleLoader = ruleLoader; + } + + //---------------------- properties ----------------------------------- + + /** + * The id that the user associated with a particular plugin declaration + * in the input xml. This id is later used in the input xml to refer + * back to the original declaration. + *

+ * For plugins declared "in-line", the id is null. + */ + public void setId(String id) { + this.id = id; + } + + /** + * Return the id associated with this declaration. For plugins + * declared "inline", null will be returned. + * + * @return The id value. May be null. + */ + public String getId() { + return id; + } + + /** + * Copy all (key,value) pairs in the param into the properties member of + * this object. + *

+ * The declaration properties cannot be explicit member variables, + * because the set of useful properties a user can provide on a declaration + * depends on what RuleFinder classes are available - and extra RuleFinders + * can be added by the user. So here we keep a map of the settings, and + * let the RuleFinder objects look for whatever properties they consider + * significant. + *

+ * The "id" and "class" properties are treated differently. + */ + public void setProperties(Properties p) { + properties.putAll(p); + } + + /** + * Return plugin class associated with this declaration. + * + * @return The pluginClass. + */ + public Class getPluginClass() { + return pluginClass; + } + + //---------------------- methods ----------------------------------- + + /** + * Must be called exactly once, and must be called before any call + * to the configure method. + */ + public void init(Digester digester, PluginManager pm) throws PluginException { + Log log = digester.getLogger(); + boolean debug = log.isDebugEnabled(); + if (debug) { + log.debug("init being called!"); + } + + if (initialized) { + throw new PluginAssertionFailure("Init called multiple times."); + } + + if ((pluginClass == null) && (pluginClassName != null)) { + try { + // load the plugin class object + pluginClass = + digester.getClassLoader().loadClass(pluginClassName); + } catch(ClassNotFoundException cnfe) { + throw new PluginException( + "Unable to load class " + pluginClassName, cnfe); + } + } + + if (ruleLoader == null) { + // the caller didn't provide a ruleLoader to the constructor, + // so get the plugin manager to "discover" one. + log.debug("Searching for ruleloader..."); + ruleLoader = pm.findLoader(digester, id, pluginClass, properties); + } else { + log.debug("This declaration has an explicit ruleLoader."); + } + + if (debug) { + if (ruleLoader == null) { + log.debug( + "No ruleLoader found for plugin declaration" + + " id [" + id + "]" + + ", class [" + pluginClass.getClass().getName() + "]."); + } else { + log.debug( + "RuleLoader of type [" + ruleLoader.getClass().getName() + + "] associated with plugin declaration" + + " id [" + id + "]" + + ", class [" + pluginClass.getClass().getName() + "]."); + } + } + + initialized = true; + } + + /** + * Attempt to load custom rules for the target class at the specified + * pattern. + *

+ * On return, any custom rules associated with the plugin class have + * been loaded into the Rules object currently associated with the + * specified digester object. + */ + + public void configure(Digester digester, String pattern) + throws PluginException { + Log log = digester.getLogger(); + boolean debug = log.isDebugEnabled(); + if (debug) { + log.debug("configure being called!"); + } + + if (!initialized) { + throw new PluginAssertionFailure("Not initialized."); + } + + if (ruleLoader != null) { + ruleLoader.addRules(digester, pattern); + } + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/InitializableRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/InitializableRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/InitializableRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,43 @@ +/* $Id: InitializableRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins; + +/** + * Defines an interface that a Rule class can implement if it wishes to get an + * initialisation callback after the rule has been added to the set of Rules + * within a PluginRules instance. + * + * @since 1.6 + */ + +public interface InitializableRule { + + /** + * Called after this Rule object has been added to the list of all Rules. + * Note that if a single InitializableRule instance is associated with + * more than one pattern, then this method will be called more than once. + * + * @param pattern is the digester match pattern that will trigger this + * rule. + * @exception + * PluginConfigurationException is thrown if the InitializableRule + * determines that it cannot correctly initialise itself for any reason. + */ + public void postRegisterInit(String pattern) + throws PluginConfigurationException; +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/LogUtils.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/LogUtils.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/LogUtils.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,73 @@ +/* $Id: LogUtils.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins; + +import org.apache.commons.digester.Digester; +import org.apache.commons.logging.Log; + +/** + * Simple utility class to assist in logging. + *

+ * This class is intended only for the use of the code in the + * plugins packages. No "user" code should use this package. + *

+ * The Digester module has an interesting approach to logging: + * all logging should be done via the Log object stored on the + * digester instance that the object *doing* the logging is associated + * with. + *

+ * This is done because apparently some "container"-type applications + * such as Avalon and Tomcat need to be able to configure different logging + * for different instances of the Digester class which have been + * loaded from the same ClassLoader [info from Craig McClanahan]. + * Not only the logging of the Digester instance should be affected; all + * objects associated with that Digester instance should obey the + * reconfiguration of their owning Digester instance's logging. The current + * solution is to force all objects to output logging info via a single + * Log object stored on the Digester instance they are associated with. + *

+ * Of course this causes problems if logging is attempted before an + * object has a valid reference to its owning Digester. The + * getLogging method provided here resolves this issue by returning a + * Log object which silently discards all logging output in this + * situation. + *

+ * And it also implies that logging filtering can no longer be applied + * to subcomponents of the Digester, because all logging is done via + * a single Log object (a single Category). C'est la vie... + * + * @since 1.6 + */ + +class LogUtils { + + /** + * Get the Log object associated with the specified Digester instance, + * or a "no-op" logging object if the digester reference is null. + *

+ * You should use this method instead of digester.getLogger() in + * any situation where the digester might be null. + */ + static Log getLogger(Digester digester) { + if (digester == null) { + return new org.apache.commons.logging.impl.NoOpLog(); + } + + return digester.getLogger(); + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginAssertionFailure.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginAssertionFailure.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginAssertionFailure.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,87 @@ +/* $Id: PluginAssertionFailure.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester.plugins; + +/** + * Thrown when a bug is detected in the plugins code. + *

+ * This class is intended to be used in assertion statements, similar to + * the way that java 1.4's native assertion mechanism is used. However there + * is a difference: when a java 1.4 assertion fails, an AssertionError + * is thrown, which is a subclass of Error; here, the PluginAssertionFailure + * class extends RuntimeException rather than Error. + *

+ * This difference in design is because throwing Error objects is not + * good in a container-based architecture. + *

+ * Example: + *

+ *   if (impossibleCondition) {
+ *     throw new PluginAssertionFailure(
+ *       "internal error: impossible condition is true");
+ *   }
+ * 
+ *

+ * Note that PluginAssertionFailure should not be thrown when user + * input is bad, or when code external to the Digester module passes invalid + * parameters to a plugins method. It should be used only in checks for + * problems which indicate internal bugs within the plugins module. + * + * @since 1.6 + */ +public class PluginAssertionFailure extends RuntimeException { + + private static final long serialVersionUID = 1L; + private Throwable cause = null; + + /** + * @param cause underlying exception that caused this to be thrown + */ + public PluginAssertionFailure(Throwable cause) { + this(cause.getMessage()); + this.cause = cause; + } + + /** + * @param msg describes the reason this exception is being thrown. + */ + public PluginAssertionFailure(String msg) { + super(msg); + } + + /** + * @param msg describes the reason this exception is being thrown. + * @param cause underlying exception that caused this to be thrown + */ + public PluginAssertionFailure(String msg, Throwable cause) { + this(msg); + this.cause = cause; + } + + /** + * Return the cause of this exception (if any) as specified in the + * exception constructor. + * + * @since 1.8 + */ + @Override + public Throwable getCause() { + return cause; + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginConfigurationException.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginConfigurationException.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginConfigurationException.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,70 @@ +/* $Id: PluginConfigurationException.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester.plugins; + +/** + * Thrown when an error occurs due to the way the calling application uses + * the plugins module. Because the pre-existing Digester API doesn't provide + * any option for throwing checked exceptions at some points where Plugins + * can potentially fail, this exception extends RuntimeException so that it + * can "tunnel" through these points. + * + * @since 1.6 + */ + +public class PluginConfigurationException extends RuntimeException { + + private static final long serialVersionUID = 1L; + private Throwable cause = null; + + /** + * @param cause underlying exception that caused this to be thrown + */ + public PluginConfigurationException(Throwable cause) { + this(cause.getMessage()); + this.cause = cause; + } + + /** + * @param msg describes the reason this exception is being thrown. + */ + public PluginConfigurationException(String msg) { + super(msg); + } + + /** + * @param msg describes the reason this exception is being thrown. + * @param cause underlying exception that caused this to be thrown + */ + public PluginConfigurationException(String msg, Throwable cause) { + this(msg); + this.cause = cause; + } + + /** + * Return the cause of this exception (if any) as specified in the + * exception constructor. + * + * @since 1.8 + */ + @Override + public Throwable getCause() { + return cause; + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginContext.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginContext.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginContext.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,247 @@ +/* $Id: PluginContext.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins; + +import java.util.List; +import java.util.LinkedList; + +import org.apache.commons.digester.plugins.strategies.FinderFromFile; +import org.apache.commons.digester.plugins.strategies.FinderFromResource; +import org.apache.commons.digester.plugins.strategies.FinderFromClass; +import org.apache.commons.digester.plugins.strategies.FinderFromMethod; +import org.apache.commons.digester.plugins.strategies.FinderFromDfltMethod; +import org.apache.commons.digester.plugins.strategies.FinderFromDfltClass; +import org.apache.commons.digester.plugins.strategies.FinderFromDfltResource; +import org.apache.commons.digester.plugins.strategies.FinderSetProperties; + +/** + * Provides data and services which should exist only once per digester. + *

+ * This class holds a number of useful items which should be shared by all + * plugin objects. Such data cannot be stored on the PluginRules or + * PluginManager classes, as there can be multiple instances of these at + * various times during a parse. + *

+ * The name "Context" refers to the similarity between this class and a + * ServletContext class in a servlet engine. A ServletContext object provides + * access to the container's services such as obtaining global configuration + * parameters for the container, or getting access to logging services. For + * plugins, a Digester instance can be regarded as "the container". + * + * @since 1.6 + */ + +public class PluginContext { + + // TODO: Consider making following four constants static in 2.0 + // the xml attribute the user uses on an xml element to specify + // the plugin's class + public final String DFLT_PLUGIN_CLASS_ATTR_NS = null; + public final String DFLT_PLUGIN_CLASS_ATTR = "plugin-class"; + + // the xml attribute the user uses on an xml element to specify + // the plugin's class + public final String DFLT_PLUGIN_ID_ATTR_NS = null; + public final String DFLT_PLUGIN_ID_ATTR = "plugin-id"; + + /** See {@link #setPluginClassAttribute}. */ + private String pluginClassAttrNs = DFLT_PLUGIN_CLASS_ATTR_NS; + + /** See {@link #setPluginClassAttribute}. */ + private String pluginClassAttr = DFLT_PLUGIN_CLASS_ATTR; + + /** See {@link #setPluginClassAttribute}. */ + private String pluginIdAttrNs = DFLT_PLUGIN_ID_ATTR_NS; + + /** See {@link #setPluginClassAttribute}. */ + private String pluginIdAttr = DFLT_PLUGIN_ID_ATTR; + + /** + * A list of RuleFinder objects used by all Declarations (and thus + * indirectly by all PluginCreateRules to locate the custom rules + * for plugin classes. + */ + private List ruleFinders; + + //------------------- constructors --------------------------------------- + + public PluginContext() { + } + + //------------------- methods --------------------------------------- + + /** + * Return the list of RuleFinder objects. Under normal circumstances + * this method creates a default list of these objects when first called + * (ie "on-demand" or "lazy initialization"). However if setRuleFinders + * has been called first, then the list specified there is returned. + *

+ * It is explicitly permitted for the caller to modify this list + * by inserting or removing RuleFinder objects. + */ + public List getRuleFinders() { + if (ruleFinders == null) { + // when processing a plugin declaration, attempts are made to + // find custom rules in the order in which the Finder objects + // are added below. However this list can be modified + ruleFinders = new LinkedList(); + ruleFinders.add(new FinderFromFile()); + ruleFinders.add(new FinderFromResource()); + ruleFinders.add(new FinderFromClass()); + ruleFinders.add(new FinderFromMethod()); + ruleFinders.add(new FinderFromDfltMethod()); + ruleFinders.add(new FinderFromDfltClass()); + ruleFinders.add(new FinderFromDfltResource()); + ruleFinders.add(new FinderFromDfltResource(".xml")); + ruleFinders.add(new FinderSetProperties()); + } + return ruleFinders; + } + + /** + * Set the list of RuleFinder objects. This may be useful if working + * in a non-english language, allowing the application developer to + * replace the standard list with a list of objects which look for xml + * attributes in the local language. + *

+ * If the intent is just to add an additional rule-finding algorithm, then + * it may be better to call #getRuleFinders, and insert a new object into + * the start of the list. + */ + public void setRuleFinders(List ruleFinders) { + this.ruleFinders = ruleFinders; + } + + /** + * Sets the xml attribute which the input xml uses to indicate to a + * PluginCreateRule which class should be instantiated. + *

+ * Example: + *

+     * setPluginClassAttribute(null, "class");
+     * 
+ * will allow this in the input xml: + *
+     *  <root>
+     *    <some-plugin class="com.acme.widget"> ......
+     * 
+ * instead of the default syntax: + *
+     *  <root>
+     *    <some-plugin plugin-class="com.acme.widget"> ......
+     * 
+ * This is particularly useful if the input xml document is not in + * English. + *

+ * Note that the xml attributes used by PluginDeclarationRules are not + * affected by this method. + * + * @param namespaceUri is the namespace uri that the specified attribute + * is in. If the attribute is in no namespace, then this should be null. + * Note that if a namespace is used, the attrName value should not + * contain any kind of namespace-prefix. Note also that if you are using + * a non-namespace-aware parser, this parameter must be null. + * + * @param attrName is the attribute whose value contains the name of the + * class to be instantiated. + */ + public void setPluginClassAttribute(String namespaceUri, + String attrName) { + pluginClassAttrNs = namespaceUri; + pluginClassAttr = attrName; + } + + /** + * Sets the xml attribute which the input xml uses to indicate to a + * PluginCreateRule which plugin declaration is being referenced. + *

+ * Example: + *

+     * setPluginIdAttribute(null, "id");
+     * 
+ * will allow this in the input xml: + *
+     *  <root>
+     *    <some-plugin id="widget"> ......
+     * 
+ * rather than the default behaviour: + *
+     *  <root>
+     *    <some-plugin plugin-id="widget"> ......
+     * 
+ * This is particularly useful if the input xml document is not in + * English. + *

+ * Note that the xml attributes used by PluginDeclarationRules are not + * affected by this method. + * + * @param namespaceUri is the namespace uri that the specified attribute + * is in. If the attribute is in no namespace, then this should be null. + * Note that if a namespace is used, the attrName value should not + * contain any kind of namespace-prefix. Note also that if you are using + * a non-namespace-aware parser, this parameter must be null. + * + * @param attrName is the attribute whose value contains the id of the + * plugin declaration to be used when instantiating an object. + */ + public void setPluginIdAttribute(String namespaceUri, + String attrName) { + pluginIdAttrNs = namespaceUri; + pluginIdAttr = attrName; + } + + /** + * Get the namespace for the xml attribute which indicates to a + * PluginCreateRule which class is to be plugged in. + *

+ * May be null (in fact, normally will be). + */ + public String getPluginClassAttrNs() { + return pluginClassAttrNs; + } + + /** + * Get the namespace for the xml attribute which indicates to a + * PluginCreateRule which class is to be plugged in. + *

+ * The return value is never null. + */ + public String getPluginClassAttr() { + return pluginClassAttr; + } + + /** + * Get the namespace for the xml attribute which indicates to a + * PluginCreateRule which previous plugin declaration should be used. + *

+ * May be null (in fact, normally will be). + */ + public String getPluginIdAttrNs() { + return pluginIdAttrNs; + } + + /** + * Get the namespace for the xml attribute which indicates to a + * PluginCreateRule which previous plugin declaration should be used. + *

+ * The return value is never null. + */ + public String getPluginIdAttr() { + return pluginIdAttr; + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginCreateRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginCreateRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginCreateRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,584 @@ +/* $Id: PluginCreateRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins; + +import java.util.List; + +import org.apache.commons.digester.Rule; +import org.apache.commons.logging.Log; + +/** + * Allows the original rules for parsing the configuration file to define + * points at which plugins are allowed, by configuring a PluginCreateRule + * with the appropriate pattern. + * + * @since 1.6 + */ +public class PluginCreateRule extends Rule implements InitializableRule { + + // see setPluginClassAttribute + private String pluginClassAttrNs = null; + private String pluginClassAttr = null; + + // see setPluginIdAttribute + private String pluginIdAttrNs = null; + private String pluginIdAttr = null; + + /** + * In order to invoke the addRules method on the plugin class correctly, + * we need to know the pattern which this rule is matched by. + */ + private String pattern; + + /** A base class that any plugin must derive from. */ + private Class baseClass = null; + + /** + * Info about optional default plugin to be used if no plugin-id is + * specified in the input data. This can simplify the syntax where one + * particular plugin is usually used. + */ + private Declaration defaultPlugin; + + /** + * Currently, none of the Rules methods allow exceptions to be thrown. + * Therefore if this class cannot initialise itself properly, it cannot + * cause the digester to stop. Instead, we cache the exception and throw + * it the first time the begin() method is called. + */ + private PluginConfigurationException initException; + + //-------------------- constructors ------------------------------------- + + /** + * Create a plugin rule where the user must specify a plugin-class + * or plugin-id. + * + * @param baseClass is the class which any specified plugin must be + * descended from. + */ + public PluginCreateRule(Class baseClass) { + this.baseClass = baseClass; + } + + /** + * Create a plugin rule where the user may specify a plugin. + * If the user doesn't specify a plugin, then the default class specified + * in this constructor is used. + * + * @param baseClass is the class which any specified plugin must be + * descended from. + * @param dfltPluginClass is the class which will be used if the user + * doesn't specify any plugin-class or plugin-id. This class will have + * custom rules installed for it just like a declared plugin. + */ + public PluginCreateRule(Class baseClass, Class dfltPluginClass) { + this.baseClass = baseClass; + if (dfltPluginClass != null) { + defaultPlugin = new Declaration(dfltPluginClass); + } + } + + /** + * Create a plugin rule where the user may specify a plugin. + * If the user doesn't specify a plugin, then the default class specified + * in this constructor is used. + * + * @param baseClass is the class which any specified plugin must be + * descended from. + * @param dfltPluginClass is the class which will be used if the user + * doesn't specify any plugin-class or plugin-id. This class will have + * custom rules installed for it just like a declared plugin. + * @param dfltPluginRuleLoader is a RuleLoader instance which knows how + * to load the custom rules associated with this default plugin. + */ + public PluginCreateRule(Class baseClass, Class dfltPluginClass, + RuleLoader dfltPluginRuleLoader) { + + this.baseClass = baseClass; + if (dfltPluginClass != null) { + defaultPlugin = + new Declaration(dfltPluginClass, dfltPluginRuleLoader); + } + } + + //------------------- properties --------------------------------------- + + /** + * Sets the xml attribute which the input xml uses to indicate to a + * PluginCreateRule which class should be instantiated. + *

+ * See {@link PluginRules#setPluginClassAttribute} for more info. + */ + public void setPluginClassAttribute(String namespaceUri, String attrName) { + pluginClassAttrNs = namespaceUri; + pluginClassAttr = attrName; + } + + /** + * Sets the xml attribute which the input xml uses to indicate to a + * PluginCreateRule which plugin declaration is being referenced. + *

+ * See {@link PluginRules#setPluginIdAttribute} for more info. + */ + public void setPluginIdAttribute(String namespaceUri, String attrName) { + pluginIdAttrNs = namespaceUri; + pluginIdAttr = attrName; + } + + //------------------- methods -------------------------------------------- + + /** + * Invoked after this rule has been added to the set of digester rules, + * associated with the specified pattern. Check all configuration data is + * valid and remember the pattern for later. + * + * @param matchPattern is the digester match pattern that is associated + * with this rule instance, eg "root/widget". + * @exception PluginConfigurationException + */ + public void postRegisterInit(String matchPattern) + throws PluginConfigurationException { + Log log = LogUtils.getLogger(digester); + boolean debug = log.isDebugEnabled(); + if (debug) { + log.debug("PluginCreateRule.postRegisterInit" + + ": rule registered for pattern [" + matchPattern + "]"); + } + + if (digester == null) { + // We require setDigester to be called before this method. + // Note that this means that PluginCreateRule cannot be added + // to a Rules object which has not yet been added to a + // Digester object. + initException = new PluginConfigurationException( + "Invalid invocation of postRegisterInit" + + ": digester not set."); + throw initException; + } + + if (pattern != null) { + // We have been called twice, ie a single instance has been + // associated with multiple patterns. + // + // Generally, Digester Rule instances can be associated with + // multiple patterns. However for plugins, this creates some + // complications. Some day this may be supported; however for + // now we just reject this situation. + initException = new PluginConfigurationException( + "A single PluginCreateRule instance has been mapped to" + + " multiple patterns; this is not supported."); + throw initException; + } + + if (matchPattern.indexOf('*') != -1) { + // having wildcards in patterns is extremely difficult to + // deal with. For now, we refuse to allow this. + // + // TODO: check for any chars not valid in xml element name + // rather than just *. + // + // Reasons include: + // (a) handling recursive plugins, and + // (b) determining whether one pattern is "below" another, + // as done by PluginRules. Without wildcards, "below" + // just means startsWith, which is easy to check. + initException = new PluginConfigurationException( + "A PluginCreateRule instance has been mapped to" + + " pattern [" + matchPattern + "]." + + " This pattern includes a wildcard character." + + " This is not supported by the plugin architecture."); + throw initException; + } + + if (baseClass == null) { + baseClass = Object.class; + } + + PluginRules rules = (PluginRules) digester.getRules(); + PluginManager pm = rules.getPluginManager(); + + // check default class is valid + if (defaultPlugin != null) { + if (!baseClass.isAssignableFrom(defaultPlugin.getPluginClass())) { + initException = new PluginConfigurationException( + "Default class [" + + defaultPlugin.getPluginClass().getName() + + "] does not inherit from [" + + baseClass.getName() + "]."); + throw initException; + } + + try { + defaultPlugin.init(digester, pm); + + } catch(PluginException pwe) { + + throw new PluginConfigurationException( + pwe.getMessage(), pwe.getCause()); + } + } + + // remember the pattern for later + pattern = matchPattern; + + if (pluginClassAttr == null) { + // the user hasn't set explicit xml attr names on this rule, + // so fetch the default values + pluginClassAttrNs = rules.getPluginClassAttrNs(); + pluginClassAttr = rules.getPluginClassAttr(); + + if (debug) { + log.debug( + "init: pluginClassAttr set to per-digester values [" + + "ns=" + pluginClassAttrNs + + ", name=" + pluginClassAttr + "]"); + } + } else { + if (debug) { + log.debug( + "init: pluginClassAttr set to rule-specific values [" + + "ns=" + pluginClassAttrNs + + ", name=" + pluginClassAttr + "]"); + } + } + + if (pluginIdAttr == null) { + // the user hasn't set explicit xml attr names on this rule, + // so fetch the default values + pluginIdAttrNs = rules.getPluginIdAttrNs(); + pluginIdAttr = rules.getPluginIdAttr(); + + if (debug) { + log.debug( + "init: pluginIdAttr set to per-digester values [" + + "ns=" + pluginIdAttrNs + + ", name=" + pluginIdAttr + "]"); + } + } else { + if (debug) { + log.debug( + "init: pluginIdAttr set to rule-specific values [" + + "ns=" + pluginIdAttrNs + + ", name=" + pluginIdAttr + "]"); + } + } + } + + /** + * Invoked when the Digester matches this rule against an xml element. + *

+ * A new instance of the target class is created, and pushed onto the + * stack. A new "private" PluginRules object is then created and set as + * the digester's default Rules object. Any custom rules associated with + * the plugin class are then loaded into that new Rules object. + * Finally, any custom rules that are associated with the current pattern + * (such as SetPropertiesRules) have their begin methods executed. + * + * @param namespace + * @param name + * @param attributes + * + * @throws ClassNotFoundException + * @throws PluginInvalidInputException + * @throws PluginConfigurationException + */ + @Override + public void begin(String namespace, String name, + org.xml.sax.Attributes attributes) + throws java.lang.Exception { + Log log = digester.getLogger(); + boolean debug = log.isDebugEnabled(); + if (debug) { + log.debug("PluginCreateRule.begin" + ": pattern=[" + pattern + "]" + + " match=[" + digester.getMatch() + "]"); + } + + if (initException != null) { + // we had a problem during initialisation that we could + // not report then; report it now. + throw initException; + } + + // load any custom rules associated with the plugin + PluginRules oldRules = (PluginRules) digester.getRules(); + PluginManager pluginManager = oldRules.getPluginManager(); + Declaration currDeclaration = null; + + String pluginClassName; + if (pluginClassAttrNs == null) { + // Yep, this is ugly. + // + // In a namespace-aware parser, the one-param version will + // return attributes with no namespace. + // + // In a non-namespace-aware parser, the two-param version will + // never return any attributes, ever. + pluginClassName = attributes.getValue(pluginClassAttr); + } else { + pluginClassName = + attributes.getValue(pluginClassAttrNs, pluginClassAttr); + } + + String pluginId; + if (pluginIdAttrNs == null) { + pluginId = attributes.getValue(pluginIdAttr); + } else { + pluginId = + attributes.getValue(pluginIdAttrNs, pluginIdAttr); + } + + if (pluginClassName != null) { + // The user is using a plugin "inline", ie without a previous + // explicit declaration. If they have used the same plugin class + // before, we have already gone to the effort of creating a + // Declaration object, so retrieve it. If there is no existing + // declaration object for this class, then create one. + + currDeclaration = pluginManager.getDeclarationByClass( + pluginClassName); + + if (currDeclaration == null) { + currDeclaration = new Declaration(pluginClassName); + try { + currDeclaration.init(digester, pluginManager); + } catch(PluginException pwe) { + throw new PluginInvalidInputException( + pwe.getMessage(), pwe.getCause()); + } + pluginManager.addDeclaration(currDeclaration); + } + } else if (pluginId != null) { + currDeclaration = pluginManager.getDeclarationById(pluginId); + + if (currDeclaration == null) { + throw new PluginInvalidInputException( + "Plugin id [" + pluginId + "] is not defined."); + } + } else if (defaultPlugin != null) { + currDeclaration = defaultPlugin; + } else { + throw new PluginInvalidInputException( + "No plugin class specified for element " + + pattern); + } + + // get the class of the user plugged-in type + Class pluginClass = currDeclaration.getPluginClass(); + + String path = digester.getMatch(); + + // create a new Rules object and effectively push it onto a stack of + // rules objects. The stack is actually a linked list; using the + // PluginRules constructor below causes the new instance to link + // to the previous head-of-stack, then the Digester.setRules() makes + // the new instance the new head-of-stack. + PluginRules newRules = new PluginRules(digester, path, oldRules, pluginClass); + digester.setRules(newRules); + + if (debug) { + log.debug("PluginCreateRule.begin: installing new plugin: " + + "oldrules=" + oldRules.toString() + + ", newrules=" + newRules.toString()); + } + + // load up the custom rules + currDeclaration.configure(digester, pattern); + + // create an instance of the plugin class + Object instance = pluginClass.newInstance(); + getDigester().push(instance); + if (debug) { + log.debug( + "PluginCreateRule.begin" + ": pattern=[" + pattern + "]" + + " match=[" + digester.getMatch() + "]" + + " pushed instance of plugin [" + pluginClass.getName() + "]"); + } + + // and now we have to fire any custom rules which would have + // been matched by the same path that matched this rule, had + // they been loaded at that time. + List rules = newRules.getDecoratedRules().match(namespace, path); + fireBeginMethods(rules, namespace, name, attributes); + } + + /** + * Process the body text of this element. + * + * @param text The body text of this element + */ + @Override + public void body(String namespace, String name, String text) + throws Exception { + + // While this class itself has no work to do in the body method, + // we do need to fire the body methods of all dynamically-added + // rules matching the same path as this rule. During begin, we had + // to manually execute the dynamic rules' begin methods because they + // didn't exist in the digester's Rules object when the match begin. + // So in order to ensure consistent ordering of rule execution, the + // PluginRules class deliberately avoids returning any such rules + // in later calls to the match method, instead relying on this + // object to execute them at the appropriate time. + // + // Note that this applies only to rules matching exactly the path + // which is also matched by this PluginCreateRule. + + String path = digester.getMatch(); + PluginRules newRules = (PluginRules) digester.getRules(); + List rules = newRules.getDecoratedRules().match(namespace, path); + fireBodyMethods(rules, namespace, name, text); + } + + /** + * Invoked by the digester when the closing tag matching this Rule's + * pattern is encountered. + *

+ * + * @param namespace Description of the Parameter + * @param name Description of the Parameter + * @exception Exception Description of the Exception + * + * @see #begin + */ + @Override + public void end(String namespace, String name) + throws Exception { + + + // see body method for more info + String path = digester.getMatch(); + PluginRules newRules = (PluginRules) digester.getRules(); + List rules = newRules.getDecoratedRules().match(namespace, path); + fireEndMethods(rules, namespace, name); + + // pop the stack of PluginRules instances, which + // discards all custom rules associated with this plugin + digester.setRules(newRules.getParent()); + + // and get rid of the instance of the plugin class from the + // digester object stack. + digester.pop(); + } + + /** + * Return the pattern that this Rule is associated with. + *

+ * In general, Rule instances can be associated with multiple + * patterns. A PluginCreateRule, however, will only function correctly + * when associated with a single pattern. It is possible to fix this, but + * I can't be bothered just now because this feature is unlikely to be + * used. + *

+ * + * @return The pattern value + */ + public String getPattern() { + return pattern; + } + + /** + * Duplicate the processing that the Digester does when firing the + * begin methods of rules. It would be really nice if the Digester + * class provided a way for this functionality to just be invoked + * directly. + */ + public void fireBeginMethods(List rules, + String namespace, String name, + org.xml.sax.Attributes list) + throws java.lang.Exception { + + if ((rules != null) && (rules.size() > 0)) { + Log log = digester.getLogger(); + boolean debug = log.isDebugEnabled(); + for (int i = 0; i < rules.size(); i++) { + try { + Rule rule = rules.get(i); + if (debug) { + log.debug(" Fire begin() for " + rule); + } + rule.begin(namespace, name, list); + } catch (Exception e) { + throw digester.createSAXException(e); + } catch (Error e) { + throw e; + } + } + } + } + + /** + * Duplicate the processing that the Digester does when firing the + * body methods of rules. It would be really nice if the Digester + * class provided a way for this functionality to just be invoked + * directly. + */ + private void fireBodyMethods(List rules, + String namespaceURI, String name, + String text) throws Exception { + + if ((rules != null) && (rules.size() > 0)) { + Log log = digester.getLogger(); + boolean debug = log.isDebugEnabled(); + for (int i = 0; i < rules.size(); i++) { + try { + Rule rule = rules.get(i); + if (debug) { + log.debug(" Fire body() for " + rule); + } + rule.body(namespaceURI, name, text); + } catch (Exception e) { + throw digester.createSAXException(e); + } catch (Error e) { + throw e; + } + } + } + } + + /** + * Duplicate the processing that the Digester does when firing the + * end methods of rules. It would be really nice if the Digester + * class provided a way for this functionality to just be invoked + * directly. + */ + public void fireEndMethods(List rules, + String namespaceURI, String name) + throws Exception { + + // Fire "end" events for all relevant rules in reverse order + if (rules != null) { + Log log = digester.getLogger(); + boolean debug = log.isDebugEnabled(); + for (int i = 0; i < rules.size(); i++) { + int j = (rules.size() - i) - 1; + try { + Rule rule = rules.get(j); + if (debug) { + log.debug(" Fire end() for " + rule); + } + rule.end(namespaceURI, name); + } catch (Exception e) { + throw digester.createSAXException(e); + } catch (Error e) { + throw e; + } + } + } + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginDeclarationRule.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginDeclarationRule.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginDeclarationRule.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,121 @@ +/* $Id: PluginDeclarationRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester.plugins; + +import java.util.Properties; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.Rule; + +/** + * A Digester rule which allows the user to pre-declare a class which is to + * be referenced later at a plugin point by a PluginCreateRule. + *

+ * Normally, a PluginDeclarationRule is added to a Digester instance with + * the pattern "{root}/plugin" or "* /plugin" where {root} is the name of + * the root tag in the input document. + * + * @since 1.6 + */ + +public class PluginDeclarationRule extends Rule { + + //------------------- constructors --------------------------------------- + + /** constructor */ + public PluginDeclarationRule() { + super(); + } + + //------------------- methods -------------------------------------------- + + /** + * Invoked upon reading a tag defining a plugin declaration. The tag + * must have the following mandatory attributes: + *

    + *
  • id
  • + *
  • class
  • + *
+ * + *@param namespace The xml namespace in which the xml element which + * triggered this rule resides. + *@param name The name of the xml element which triggered this rule. + *@param attributes The set of attributes on the xml element which + * triggered this rule. + *@exception java.lang.Exception + */ + + @Override + public void begin(String namespace, String name, + org.xml.sax.Attributes attributes) + throws java.lang.Exception { + + int nAttrs = attributes.getLength(); + Properties props = new Properties(); + for(int i=0; i + * One instance of this class exists per PluginRules instance. + * + * @since 1.6 + */ + +public class PluginManager { + + /** Map of classname->Declaration */ + private HashMap declarationsByClass = new HashMap(); + + /** Map of id->Declaration */ + private HashMap declarationsById = new HashMap(); + + /** the parent manager to which this one may delegate lookups. */ + private PluginManager parent; + + /** + * The object containing data that should only exist once for each + * Digester instance. + */ + private PluginContext pluginContext; + + //------------------- constructors --------------------------------------- + + /** Construct a "root" PluginManager, ie one with no parent. */ + public PluginManager(PluginContext r) { + pluginContext = r; + } + + /** + * Construct a "child" PluginManager. When declarations are added to + * a "child", they are stored within the child and do not modify the + * parent, so when the child goes out of scope, those declarations + * disappear. When asking a "child" to retrieve a declaration, it + * delegates the search to its parent if it does not hold a matching + * entry itself. + *

+ * @param parent must be non-null. + */ + public PluginManager(PluginManager parent) { + this.parent = parent; + this.pluginContext = parent.pluginContext; + } + + //------------------- methods -------------------------------------------- + + /** + * Add the declaration to the set of known declarations. + *

+ * TODO: somehow get a reference to a Digester object + * so that we can really log here. Currently, all + * logging is disabled from this method. + * + *@param decl an object representing a plugin class. + */ + public void addDeclaration(Declaration decl) { + Log log = LogUtils.getLogger(null); + boolean debug = log.isDebugEnabled(); + + Class pluginClass = decl.getPluginClass(); + String id = decl.getId(); + + declarationsByClass.put(pluginClass.getName(), decl); + + if (id != null) { + declarationsById.put(id, decl); + if (debug) { + log.debug( + "Indexing plugin-id [" + id + "]" + + " -> class [" + pluginClass.getName() + "]"); + } + } + } + + /** + * Return the declaration object with the specified class. + * If no such plugin is known, null is returned. + */ + public Declaration getDeclarationByClass(String className) { + Declaration decl = + declarationsByClass.get(className); + + if ((decl == null) && (parent != null)) { + decl = parent.getDeclarationByClass(className); + } + + return decl; + } + + /** + * Return the declaration object with the specified id. + * If no such plugin is known, null is returned. + * + *@param id Description of the Parameter + *@return The declaration value + */ + public Declaration getDeclarationById(String id) { + Declaration decl = declarationsById.get(id); + + if ((decl == null) && (parent != null)) { + decl = parent.getDeclarationById(id); + } + + return decl; + } + + /** + * Given a plugin class and some associated properties, scan the + * list of known RuleFinder instances until one detects a source of + * custom rules for this plugin (aka a RuleLoader). + *

+ * If no source of custom rules can be found, null is returned. + */ + public RuleLoader findLoader(Digester digester, String id, + Class pluginClass, Properties props) + throws PluginException { + + // iterate over the list of RuleFinders, trying each one + // until one of them locates a source of dynamic rules given + // this specific plugin class and the associated declaration + // properties. + Log log = LogUtils.getLogger(digester); + boolean debug = log.isDebugEnabled(); + log.debug("scanning ruleFinders to locate loader.."); + + List ruleFinders = pluginContext.getRuleFinders(); + RuleLoader ruleLoader = null; + try { + for(Iterator i = ruleFinders.iterator(); + i.hasNext() && ruleLoader == null; ) { + + RuleFinder finder = i.next(); + if (debug) { + log.debug("checking finder of type " + finder.getClass().getName()); + } + ruleLoader = finder.findLoader(digester, pluginClass, props); + } + } + catch(PluginException e) { + throw new PluginException( + "Unable to locate plugin rules for plugin" + + " with id [" + id + "]" + + ", and class [" + pluginClass.getName() + "]" + + ":" + e.getMessage(), e.getCause()); + } + log.debug("scanned ruleFinders."); + + return ruleLoader; + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginRules.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginRules.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/PluginRules.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,429 @@ +/* $Id: PluginRules.java 992104 2010-09-02 20:24:31Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins; + +import java.util.List; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.Rule; +import org.apache.commons.digester.Rules; +import org.apache.commons.digester.RulesBase; +import org.apache.commons.logging.Log; + +/** + * A custom digester Rules manager which must be used as the Rules object + * when using the plugins module functionality. + *

+ * During parsing, a linked list of PluginCreateRule instances develop, and + * this list also acts like a stack. The original instance that was set before + * the Digester started parsing is always at the tail of the list, and the + * Digester always holds a reference to the instance at the head of the list + * in the rules member. Initially, this list/stack holds just one instance, + * ie head and tail are the same object. + *

+ * When the start of an xml element causes a PluginCreateRule to fire, a new + * PluginRules instance is created and inserted at the head of the list (ie + * pushed onto the stack of Rules objects). Digester.getRules() therefore + * returns this new Rules object, and any custom rules associated with that + * plugin are added to that instance. + *

+ * When the end of the xml element is encountered (and therefore the + * PluginCreateRule end method fires), the stack of Rules objects is popped, + * so that Digester.getRules returns the previous Rules object. + * + * @since 1.6 + */ + +public class PluginRules implements Rules { + + /** + * The Digester instance with which this Rules instance is associated. + */ + protected Digester digester = null; + + /** + * The (optional) object which generates new rules instances. + */ + private RulesFactory rulesFactory; + + /** + * The rules implementation that we are "enhancing" with plugins + * functionality, as per the Decorator pattern. + */ + private Rules decoratedRules; + + /** Object which contains information about all known plugins. */ + private PluginManager pluginManager; + + /** + * The path below which this rules object has responsibility. + * For paths shorter than or equal the mountpoint, the parent's + * match is called. + */ + private String mountPoint = null; + + /** + * The Rules object that holds rules applying "above" the mountpoint, + * ie the next Rules object down in the stack. + */ + private PluginRules parent = null; + + /** + * A reference to the object that holds all data which should only + * exist once per digester instance. + */ + private PluginContext pluginContext = null; + + // ------------------------------------------------------------- Constructor + + /** + * Constructor for top-level Rules objects. Exactly one of these must + * be created and installed into the Digester instance as the Rules + * object before parsing starts. + */ + public PluginRules() { + this(new RulesBase()); + } + + /** + * Constructor for top-level Rules object which handles rule-matching + * using the specified implementation. + */ + public PluginRules(Rules decoratedRules) { + this.decoratedRules = decoratedRules; + + pluginContext = new PluginContext(); + pluginManager = new PluginManager(pluginContext); + } + + /** + * Constructs a Rules instance which has a parent Rules object + * (which is different from having a delegate rules object). + *

+ * One of these is created each time a PluginCreateRule's begin method + * fires, in order to manage the custom rules associated with whatever + * concrete plugin class the user has specified. + * + * @param digester is the object this rules will be associated with. + * @param mountPoint is the digester match path for the element + * matching a PluginCreateRule which caused this "nested parsing scope" + * to begin. This is expected to be equal to digester.getMatch(). + * @param parent must be non-null. + * @param pluginClass is the plugin class whose custom rules will be + * loaded into this new PluginRules object. + */ + PluginRules( + Digester digester, + String mountPoint, + PluginRules parent, + Class pluginClass) + throws PluginException { + // no need to set digester or decoratedRules.digester, + // because when Digester.setRules is called, the setDigester + // method on this object will be called. + + this.digester = digester; + this.mountPoint = mountPoint; + this.parent = parent; + this.rulesFactory = parent.rulesFactory; + + if (rulesFactory == null) { + decoratedRules = new RulesBase(); + } else { + decoratedRules = rulesFactory.newRules(digester, pluginClass); + } + + pluginContext = parent.pluginContext; + pluginManager = new PluginManager(parent.pluginManager); + } + + // ------------------------------------------------------------- Properties + + /** + * Return the parent Rules object. + */ + public Rules getParent() { + return parent; + } + + /** + * Return the Digester instance with which this instance is associated. + */ + public Digester getDigester() { + return digester; + } + + /** + * Set the Digester instance with which this Rules instance is associated. + * + * @param digester The newly associated Digester instance + */ + public void setDigester(Digester digester) { + this.digester = digester; + decoratedRules.setDigester(digester); + } + + /** + * Return the namespace URI that will be applied to all subsequently + * added Rule objects. + */ + public String getNamespaceURI() { + return decoratedRules.getNamespaceURI(); + } + + /** + * Set the namespace URI that will be applied to all subsequently + * added Rule objects. + * + * @param namespaceURI Namespace URI that must match on all + * subsequently added rules, or null for matching + * regardless of the current namespace URI + */ + public void setNamespaceURI(String namespaceURI) { + decoratedRules.setNamespaceURI(namespaceURI); + } + + /** + * Return the object which "knows" about all declared plugins. + * + * @return The pluginManager value + */ + public PluginManager getPluginManager() { + return pluginManager; + } + + /** + * See {@link PluginContext#getRuleFinders}. + */ + public List getRuleFinders() { + return pluginContext.getRuleFinders(); + } + + /** + * See {@link PluginContext#setRuleFinders}. + */ + public void setRuleFinders(List ruleFinders) { + pluginContext.setRuleFinders(ruleFinders); + } + + /** + * Return the rules factory object (or null if one has not been specified). + */ + public RulesFactory getRulesFactory() { + return rulesFactory; + } + + /** + * Set the object which is used to generate the new Rules instances created + * to hold and process the rules associated with each plugged-in class. + */ + public void setRulesFactory(RulesFactory factory) { + rulesFactory = factory; + } + + // --------------------------------------------------------- Public Methods + + /** + * This package-scope method is used by the PluginCreateRule class to + * get direct access to the rules that were dynamically added by the + * plugin. No other class should need access to this object. + */ + Rules getDecoratedRules() { + return decoratedRules; + } + + /** + * Return the list of rules registered with this object, in the order + * they were registered with this object. + *

+ * Note that Rule objects stored in parent Rules objects are not + * returned by this method. + * + * @return list of all Rule objects known to this Rules instance. + */ + public List rules() { + return decoratedRules.rules(); + } + + /** + * Register a new Rule instance matching the specified pattern. + * + * @param pattern Nesting pattern to be matched for this Rule. + * This parameter treats equally patterns that begin with and without + * a leading slash ('/'). + * @param rule Rule instance to be registered + */ + public void add(String pattern, Rule rule) { + Log log = LogUtils.getLogger(digester); + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug("add entry" + ": mapping pattern [" + pattern + "]" + + " to rule of type [" + rule.getClass().getName() + "]"); + } + + // allow patterns with a leading slash character + if (pattern.startsWith("/")) + { + pattern = pattern.substring(1); + } + + if (mountPoint != null + && !pattern.equals(mountPoint) + && !pattern.startsWith(mountPoint + "/")) { + // This can only occur if a plugin attempts to add a + // rule with a pattern that doesn't start with the + // prefix passed to the addRules method. Plugins mustn't + // add rules outside the scope of the tag they were specified + // on, so refuse this. + + // alas, can't throw exception + log.warn( + "An attempt was made to add a rule with a pattern that" + + "is not at or below the mountpoint of the current" + + " PluginRules object." + + " Rule pattern: " + pattern + + ", mountpoint: " + mountPoint + + ", rule type: " + rule.getClass().getName()); + return; + } + + decoratedRules.add(pattern, rule); + + if (rule instanceof InitializableRule) { + try { + ((InitializableRule)rule).postRegisterInit(pattern); + } catch (PluginConfigurationException e) { + // Currently, Digester doesn't handle exceptions well + // from the add method. The workaround is for the + // initialisable rule to remember that its initialisation + // failed, and to throw the exception when begin is + // called for the first time. + if (debug) { + log.debug("Rule initialisation failed", e); + } + // throw e; -- alas, can't do this + return; + } + } + + if (debug) { + log.debug("add exit" + ": mapped pattern [" + pattern + "]" + + " to rule of type [" + rule.getClass().getName() + "]"); + } + } + + /** + * Clear all rules. + */ + public void clear() { + decoratedRules.clear(); + } + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param path the path to the xml nodes to be matched. + * + * @deprecated Call match(namespaceURI,pattern) instead. + */ + @Deprecated + public List match(String path) { + return (match(null, path)); + } + + /** + * Return a List of all registered Rule instances that match the specified + * nodepath, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + *

+ * @param namespaceURI Namespace URI for which to select matching rules, + * or null to match regardless of namespace URI + * @param path the path to the xml nodes to be matched. + */ + public List match(String namespaceURI, String path) { + Log log = LogUtils.getLogger(digester); + boolean debug = log.isDebugEnabled(); + + if (debug) { + log.debug( + "Matching path [" + path + + "] on rules object " + this.toString()); + } + + List matches; + if ((mountPoint != null) && + (path.length() <= mountPoint.length())) { + if (debug) { + log.debug( + "Path [" + path + "] delegated to parent."); + } + + matches = parent.match(namespaceURI, path); + + // Note that in the case where path equals mountPoint, + // we deliberately return only the rules from the parent, + // even though this object may hold some rules matching + // this same path. See PluginCreateRule's begin, body and end + // methods for the reason. + } else { + log.debug("delegating to decorated rules."); + matches = decoratedRules.match(namespaceURI, path); + } + + return matches; + } + + /** See {@link PluginContext#setPluginClassAttribute}. */ + public void setPluginClassAttribute(String namespaceUri, + String attrName) { + pluginContext.setPluginClassAttribute(namespaceUri, attrName); + } + + /** See {@link PluginContext#setPluginIdAttribute}. */ + public void setPluginIdAttribute(String namespaceUri, + String attrName) { + pluginContext.setPluginIdAttribute(namespaceUri, attrName); + } + + /** See {@link PluginContext#getPluginClassAttrNs}. */ + public String getPluginClassAttrNs() { + return pluginContext.getPluginClassAttrNs(); + } + + /** See {@link PluginContext#getPluginClassAttr}. */ + public String getPluginClassAttr() { + return pluginContext.getPluginClassAttr(); + } + + /** See {@link PluginContext#getPluginIdAttrNs}. */ + public String getPluginIdAttrNs() { + return pluginContext.getPluginIdAttrNs(); + } + + /** See {@link PluginContext#getPluginIdAttr}. */ + public String getPluginIdAttr() { + return pluginContext.getPluginIdAttr(); + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/RuleFinder.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/RuleFinder.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/RuleFinder.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,75 @@ +/* $Id: RuleFinder.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins; + +import java.util.Properties; +import org.apache.commons.digester.Digester; + +/** + * Each concrete implementation of RuleFinder is an algorithm for + * locating a source of digester rules for a plugin. The algorithm may + * use info explicitly provided by the user as part of the plugin + * declaration, or not (in which case the concrete RuleFinder subclass + * typically has Dflt as part of its name). + *

+ * Instances of this class can also be regarded as a Factory for RuleLoaders, + * except that an instance of a RuleLoader is only created if the particular + * finder algorithm can locate a suitable source of rules given the plugin + * class and associated properties. + *

+ * This is an abstract class rather than an interface in order to make + * it possible to enhance this class in future without breaking binary + * compatibility; it is possible to add methods to an abstract class, but + * not to an interface. + * + * @since 1.6 + */ + +public abstract class RuleFinder { + + /** + * Apply the finder algorithm to attempt to locate a source of + * digester rules for the specified plugin class. + *

+ * This method is invoked when a plugin is declared by the user, either + * via an explicit use of PluginDeclarationRule, or implicitly via an + * "inline declaration" where the declaration and use are simultaneous. + *

+ * If dynamic rules for the specified plugin class are located, then + * the RuleFinder will return a RuleLoader object encapsulating those + * rules, and this object will be invoked each time the user actually + * requests an instance of the declared plugin class, to load the + * custom rules associated with that plugin instance. + *

+ * If no dynamic rules can be found, null is returned. This is not an + * error; merely an indication that this particular algorithm found + * no matches. + *

+ * The properties object holds any xml attributes the user may have + * specified on the plugin declaration in order to indicate how to locate + * the plugin rules. + *

+ * @throws PluginConfigurationException if the algorithm finds a source + * of rules, but there is something invalid about that source. + */ + + public abstract RuleLoader findLoader( + Digester d, Class pluginClass, + Properties p) throws PluginException; +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/RuleLoader.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/RuleLoader.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/RuleLoader.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,49 @@ +/* $Id: RuleLoader.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins; + +import org.apache.commons.digester.Digester; + +/** + * Interface for classes which can dynamically load custom + * plugin rules associated with a user's plugin class. + *

+ * Each plugin declaration has an associated RuleLoader instance, and that + * instance's addRules method is invoked each time the input xml specifies + * that an instance of that plugged-in class is to be created. + *

+ * This is an abstract class rather than an interface in order to make + * it possible to enhance this class in future without breaking binary + * compatibility; it is possible to add methods to an abstract class, but + * not to an interface. + * + * @since 1.6 + */ + +public abstract class RuleLoader { + + /** + * Configures the digester with custom rules for some plugged-in + * class. + *

+ * This method is invoked when the start of an xml tag is encountered + * which maps to a PluginCreateRule. Any rules added here are removed + * from the digester when the end of that xml tag is encountered. + */ + public abstract void addRules(Digester d, String path) throws PluginException; +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/RulesFactory.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/RulesFactory.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/RulesFactory.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,55 @@ +/* $Id: RulesFactory.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.Rules; + +/** + * Whenever the scope of a plugin tag is entered, the PluginRules class + * creates a new Rules instance and configures it with the appropriate + * parsing rules for the plugged-in class. + *

+ * Users of the plugins module can specify a subclass of this one to + * control the creation of that Rules object. In particular, it can + * set up default rules within the returned instance which are applicable + * to all plugged-in classes. + * + * @since 1.6 + */ + +public abstract class RulesFactory { + + /** + * Return an instance of some Rules implementation that the plugged-in + * class shall use to match its private parsing rules. + *

+ * @param d is the digester that the returned rules object will be + * associated with. + * + * @param pluginClass is the class that is to be configured using rules + * added to the returnedobject. + * + * @throws PluginException if the algorithm finds a source + * of rules, but there is something invalid about that source. + */ + + public abstract Rules newRules(Digester d, Class pluginClass) + throws PluginException; +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,23 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * The plugins package provides an easy mechanism whereby new + * digestion rules can be added dynamically during a digestion. + */ +package org.apache.commons.digester.plugins; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromClass.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromClass.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromClass.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,128 @@ +/* $Id: FinderFromClass.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.util.Properties; +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.plugins.RuleFinder; +import org.apache.commons.digester.plugins.RuleLoader; +import org.apache.commons.digester.plugins.PluginException; + +/** + * A rule-finding algorithm which expects the caller to specify a classname and + * methodname as plugin properties. + * + * @since 1.6 + */ + +public class FinderFromClass extends RuleFinder { + public static String DFLT_RULECLASS_ATTR = "ruleclass"; + public static String DFLT_METHOD_ATTR = "method"; + public static String DFLT_METHOD_NAME = "addRules"; + + private String ruleClassAttr; + private String methodAttr; + private String dfltMethodName; + + /** + * See {@link #findLoader}. + */ + public FinderFromClass() { + this(DFLT_RULECLASS_ATTR, DFLT_METHOD_ATTR, DFLT_METHOD_NAME); + } + + /** + * Create a rule-finder which invokes a user-specified method on a + * user-specified class whenever dynamic rules for a plugin need to be + * loaded. See the findRules method for more info. + * + * @param ruleClassAttr must be non-null. + * @param methodAttr may be null. + * @param dfltMethodName may be null. + */ + public FinderFromClass(String ruleClassAttr, String methodAttr, + String dfltMethodName) { + this.ruleClassAttr = ruleClassAttr; + this.methodAttr = methodAttr; + this.dfltMethodName = dfltMethodName; + } + + /** + * If there exists a property with the name matching constructor param + * ruleClassAttr, then load the specified class, locate the appropriate + * rules-adding method on that class, and return an object encapsulating + * that info. + *

+ * If there is no matching property provided, then just return null. + *

+ * The returned object (when non-null) will invoke the target method + * on the selected class whenever its addRules method is invoked. The + * target method is expected to have the following prototype: + * public static void xxxxx(Digester d, String patternPrefix); + *

+ * The target method can be specified in several ways. If this object's + * constructor was passed a non-null methodAttr parameter, and the + * properties defines a value with that key, then that is taken as the + * target method name. If there is no matching property, or the constructor + * was passed null for methodAttr, then the dfltMethodName passed to the + * constructor is used as the name of the method on the target class. And + * if that was null, then DFLT_METHOD_NAME will be used. + *

+ * When the user explicitly declares a plugin in the input xml, the + * xml attributes on the declaration tag are passed here as properties, + * so the user can select any class in the classpath (and any method on + * that class provided it has the correct prototype) as the source of + * dynamic rules for the plugged-in class. + */ + @Override + public RuleLoader findLoader(Digester digester, Class pluginClass, + Properties p) throws PluginException { + + String ruleClassName = p.getProperty(ruleClassAttr); + if (ruleClassName == null) { + // nope, user hasn't requested dynamic rules to be loaded + // from a specific class. + return null; + } + + // ok, we are in business + String methodName = null; + if (methodAttr != null) { + methodName = p.getProperty(methodAttr); + } + if (methodName == null) { + methodName = dfltMethodName; + } + if (methodName == null) { + methodName = DFLT_METHOD_NAME; + } + + Class ruleClass; + try { + // load the plugin class object + ruleClass = + digester.getClassLoader().loadClass(ruleClassName); + } catch(ClassNotFoundException cnfe) { + throw new PluginException( + "Unable to load class " + ruleClassName, cnfe); + } + + return new LoaderFromClass(ruleClass, methodName); + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromDfltClass.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromDfltClass.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromDfltClass.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,92 @@ +/* $Id: FinderFromDfltClass.java 992106 2010-09-02 20:29:25Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.util.Properties; +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.plugins.RuleFinder; +import org.apache.commons.digester.plugins.RuleLoader; +import org.apache.commons.digester.plugins.PluginException; + +/** + * A rule-finding algorithm which looks for a method with a specific name + * on a class whose name is derived from the plugin class name. + * + * @since 1.6 + */ + +public class FinderFromDfltClass extends RuleFinder { + public static String DFLT_RULECLASS_SUFFIX = "RuleInfo"; + public static String DFLT_METHOD_NAME = "addRules"; + + private String rulesClassSuffix; + private String methodName; + + /** See {@link #findLoader}. */ + public FinderFromDfltClass() { + this(DFLT_RULECLASS_SUFFIX, DFLT_METHOD_NAME); + } + + /** + * Create a rule-finder which invokes a method on a class whenever + * dynamic rules for a plugin need to be loaded. See the findRules + * method for more info. + * + * @param rulesClassSuffix must be non-null. + * @param methodName may be null. + */ + public FinderFromDfltClass(String rulesClassSuffix, String methodName) { + this.rulesClassSuffix = rulesClassSuffix; + this.methodName = methodName; + } + + /** + * If there exists a class whose name is the plugin class name + the + * suffix specified to the constructor, then load that class, locate + * the appropriate rules-adding method on that class, and return an + * object encapsulating that info. + *

+ * If there is no such class, then just return null. + *

+ * The returned object (when non-null) will invoke the target method + * on the selected class whenever its addRules method is invoked. The + * target method is expected to have the following prototype: + * public static void xxxxx(Digester d, String patternPrefix); + */ + @Override + public RuleLoader findLoader(Digester digester, Class pluginClass, Properties p) + throws PluginException { + + String rulesClassName = pluginClass.getName() + rulesClassSuffix; + + Class rulesClass = null; + try { + rulesClass = digester.getClassLoader().loadClass(rulesClassName); + } catch(ClassNotFoundException cnfe) { + // nope, no rule-info class in the classpath + return null; + } + + if (methodName == null) { + methodName = DFLT_METHOD_NAME; + } + + return new LoaderFromClass(rulesClass, methodName); + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromDfltMethod.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromDfltMethod.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromDfltMethod.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,80 @@ +/* $Id: FinderFromDfltMethod.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.util.Properties; +import java.lang.reflect.Method; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.plugins.RuleFinder; +import org.apache.commons.digester.plugins.RuleLoader; +import org.apache.commons.digester.plugins.PluginException; + +/** + * A rule-finding algorithm which looks for a method with a specific name + * on the plugin class. + * + * @since 1.6 + */ + +public class FinderFromDfltMethod extends RuleFinder { + public static String DFLT_METHOD_NAME = "addRules"; + + private String methodName; + + /** See {@link #findLoader}. */ + public FinderFromDfltMethod() { + this(DFLT_METHOD_NAME); + } + + /** + * Create a rule-finder which invokes a specific method on the plugin + * class whenever dynamic rules for a plugin need to be loaded. See the + * findRules method for more info. + * + * @param methodName must be non-null. + */ + public FinderFromDfltMethod(String methodName) { + this.methodName = methodName; + } + + /** + * If there exists on the plugin class a method with name matching the + * constructor's methodName value then locate the appropriate Method on + * the plugin class and return an object encapsulating that info. + *

+ * If there is no matching method then just return null. + *

+ * The returned object (when non-null) will invoke the target method + * on the plugin class whenever its addRules method is invoked. The + * target method is expected to have the following prototype: + * public static void xxxxx(Digester d, String patternPrefix); + */ + @Override + public RuleLoader findLoader(Digester d, Class pluginClass, Properties p) + throws PluginException { + + Method rulesMethod = LoaderFromClass.locateMethod(pluginClass, methodName); + if (rulesMethod == null) { + return null; + } + + return new LoaderFromClass(pluginClass, rulesMethod); + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromDfltResource.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromDfltResource.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromDfltResource.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,90 @@ +/* $Id: FinderFromDfltResource.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.io.InputStream; +import java.util.Properties; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.plugins.RuleFinder; +import org.apache.commons.digester.plugins.RuleLoader; +import org.apache.commons.digester.plugins.PluginException; + +/** + * A rule-finding algorithm which looks for a resource file in the classpath + * whose name is derived from the plugin class name plus a specified suffix. + *

+ * If the resource-file is found, then it is expected to define a set of + * Digester rules in xmlrules format. + * + * @since 1.6 + */ + +public class FinderFromDfltResource extends RuleFinder { + public static String DFLT_RESOURCE_SUFFIX = "RuleInfo.xml"; + + private String resourceSuffix; + + /** See {@link #findLoader}. */ + public FinderFromDfltResource() { + this(DFLT_RESOURCE_SUFFIX); + } + + /** + * Create a rule-finder which can load an xmlrules file, cache + * the rules away, and later add them as a plugin's custom rules + * when that plugin is referenced. + * + * @param resourceSuffix must be non-null. + */ + public FinderFromDfltResource(String resourceSuffix) { + this.resourceSuffix = resourceSuffix; + } + + /** + * If there exists a resource file whose name is equal to the plugin + * class name + the suffix specified in the constructor, then + * load that file, run it through the xmlrules module and return an object + * encapsulating those rules. + *

+ * If there is no such resource file, then just return null. + *

+ * The returned object (when non-null) will add the selected rules to + * the digester whenever its addRules method is invoked. + */ + @Override + public RuleLoader findLoader(Digester d, Class pluginClass, Properties p) + throws PluginException { + + String resourceName = + pluginClass.getName().replace('.', '/') + + resourceSuffix; + + InputStream is = + pluginClass.getClassLoader().getResourceAsStream( + resourceName); + + if (is == null) { + // ok, no such resource + return null; + } + + return FinderFromResource.loadRules(d, pluginClass, is, resourceName); + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromFile.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromFile.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromFile.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,106 @@ +/* $Id: FinderFromFile.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.util.Properties; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.IOException; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.plugins.RuleFinder; +import org.apache.commons.digester.plugins.RuleLoader; +import org.apache.commons.digester.plugins.PluginException; + +/** + * A rule-finding algorithm which expects the user to specify an absolute + * or relative path in the plugin declaration. + *

+ * The file is expected to contain Digester rules in xmlrules format. + * + * @since 1.6 + */ + +public class FinderFromFile extends RuleFinder { + /** + * Xml attribute that needs to be present on a plugin declaration + * in order to specify the file to load rules from. + */ + public static String DFLT_FILENAME_ATTR = "file"; + + /** See {@link #findLoader}. */ + private String filenameAttr; + + /** See {@link #findLoader}. */ + public FinderFromFile() { + this(DFLT_FILENAME_ATTR); + } + + /** See {@link #findLoader}. */ + public FinderFromFile(String filenameAttr) { + this.filenameAttr = filenameAttr; + } + + /** + * If there exists a property with the name specified in the constructor, + * then load that file, run it through the xmlrules module and return an + * object encapsulating those rules. + *

+ * If there is no matching property provided, then just return null. + *

+ * The returned object (when non-null) will add the selected rules to + * the digester whenever its addRules method is invoked. + */ + @Override + public RuleLoader findLoader(Digester d, Class pluginClass, Properties p) + throws PluginException { + + String rulesFileName = p.getProperty(filenameAttr); + if (rulesFileName == null) { + // nope, user hasn't requested dynamic rules to be loaded + // from a specific file. + return null; + } + + InputStream is = null; + try { + is = new FileInputStream(rulesFileName); + } catch(IOException ioe) { + throw new PluginException( + "Unable to process file [" + rulesFileName + "]", ioe); + } + + try { + RuleLoader loader = new LoaderFromStream(is); + return loader; + } catch(Exception e) { + throw new PluginException( + "Unable to load xmlrules from file [" + + rulesFileName + "]", e); + } finally { + try { + is.close(); + } catch(java.io.IOException ioe) { + throw new PluginException( + "Unable to close stream for file [" + + rulesFileName + "]", ioe); + } + } + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromMethod.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromMethod.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromMethod.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,79 @@ +/* $Id: FinderFromMethod.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.util.Properties; +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.plugins.RuleFinder; +import org.apache.commons.digester.plugins.RuleLoader; +import org.apache.commons.digester.plugins.PluginException; + +/** + * A rule-finding algorithm which expects the caller to specify a methodname + * as a plugin property, where the method exists on the plugin class. + * + * @since 1.6 + */ + +public class FinderFromMethod extends RuleFinder { + /** + * Xml attribute that needs to be present on a plugin declaration + * in order to specify the method to load rules from. + */ + public static String DFLT_METHOD_ATTR = "method"; + + /** See {@link #findLoader}. */ + private String methodAttr; + + /** Constructor. */ + public FinderFromMethod() { + this(DFLT_METHOD_ATTR); + } + + /** See {@link #findLoader}. */ + public FinderFromMethod(String methodAttr) { + this.methodAttr = methodAttr; + } + + /** + * If there exists a property with the name matching constructor param + * methodAttr, then locate the appropriate Method on the plugin class + * and return an object encapsulating that info. + *

+ * If there is no matching property provided, then just return null. + *

+ * The returned object (when non-null) will invoke the target method + * on the plugin class whenever its addRules method is invoked. The + * target method is expected to have the following prototype: + * public static void xxxxx(Digester d, String patternPrefix); + */ + @Override + public RuleLoader findLoader(Digester d, Class pluginClass, Properties p) + throws PluginException { + + String methodName = p.getProperty(methodAttr); + if (methodName == null) { + // nope, user hasn't requested dynamic rules to be loaded + // from a specific class. + return null; + } + + return new LoaderFromClass(pluginClass, methodName); + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromResource.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromResource.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderFromResource.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,122 @@ +/* $Id: FinderFromResource.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.util.Properties; +import java.io.InputStream; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.plugins.RuleFinder; +import org.apache.commons.digester.plugins.RuleLoader; +import org.apache.commons.digester.plugins.PluginException; + +/** + * A rule-finding algorithm which expects the user to specify a resource + * name (ie a file in the classpath). The file is expected to contain Digester + * rules in xmlrules format. + * + * @since 1.6 + */ + +public class FinderFromResource extends RuleFinder { + /** + * Name of xml attribute on the plugin declaration which is used + * to configure rule-loading for that declaration. + */ + public static String DFLT_RESOURCE_ATTR = "resource"; + + /** See {@link #findLoader}. */ + private String resourceAttr; + + /** Constructor. */ + public FinderFromResource() { + this(DFLT_RESOURCE_ATTR); + } + + /** See {@link #findLoader}. */ + public FinderFromResource(String resourceAttr) { + this.resourceAttr = resourceAttr; + } + + /** + * If there exists a property with the name matching constructor param + * resourceAttr, then load that file, run it through the xmlrules + * module and return an object encapsulating those rules. + *

+ * If there is no matching property provided, then just return null. + *

+ * The returned object (when non-null) will add the selected rules to + * the digester whenever its addRules method is invoked. + */ + @Override + public RuleLoader findLoader(Digester d, Class pluginClass, Properties p) + throws PluginException { + + String resourceName = p.getProperty(resourceAttr); + if (resourceName == null) { + // nope, user hasn't requested dynamic rules to be loaded + // from a specific file. + return null; + } + + InputStream is = + pluginClass.getClassLoader().getResourceAsStream( + resourceName); + + if (is == null) { + throw new PluginException( + "Resource " + resourceName + " not found."); + } + + return loadRules(d, pluginClass, is, resourceName); + } + + /** + * Open the specified resource file (ie a file in the classpath, + * including being within a jar in the classpath), run it through + * the xmlrules module and return an object encapsulating those rules. + * + * @param d is the digester into which rules will eventually be loaded. + * @param pluginClass is the class whose xml params the rules are parsing. + * @param is is where the xmlrules will be read from, and must be non-null. + * @param resourceName is a string describing the source of the xmlrules, + * for use in generating error messages. + */ + public static RuleLoader loadRules(Digester d, Class pluginClass, + InputStream is, String resourceName) + throws PluginException { + + try { + RuleLoader loader = new LoaderFromStream(is); + return loader; + } catch(Exception e) { + throw new PluginException( + "Unable to load xmlrules from resource [" + + resourceName + "]", e); + } finally { + try { + is.close(); + } catch(java.io.IOException ioe) { + throw new PluginException( + "Unable to close stream for resource [" + + resourceName + "]", ioe); + } + } + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderSetProperties.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderSetProperties.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/FinderSetProperties.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,98 @@ +/* $Id: FinderSetProperties.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.util.Properties; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.plugins.RuleFinder; +import org.apache.commons.digester.plugins.RuleLoader; + +/** + * A rule-finding algorithm which expects the user to specify whether + * "automatic property setting" is desired. If this class discovers that + * this is in fact the case for a declaration, then a RuleLoader is returned + * which, when invoked, adds a single SetPropertiesRule instance to the + * digester. + *

+ * This allows ordinary JavaBean classes to be used as plugins, and have + * xml attributes be mapped to bean properties of the same name, without + * any custom plugin rules being created for them. + *

+ * This RuleFinder is typically used as the last RuleFinder, so that + * automatic property setting only occurs if there is no other source of + * custom rules available. + * + * @since 1.6 + */ + +public class FinderSetProperties extends RuleFinder { + public static String DFLT_PROPS_ATTR = "setprops"; + public static String DFLT_FALSEVAL = "false"; + + private String propsAttr; + private String falseval; + + /** See {@link #findLoader}. */ + public FinderSetProperties() { + this(DFLT_PROPS_ATTR, DFLT_FALSEVAL); + } + + /** + * Create a rule-finder which will arrange for a SetPropertiesRule to + * be defined for each instance of a plugin, so that xml attributes + * map to bean properties. + *

+ * Param falseval will commonly be the string "false" for config files + * written in English. + * + * @param propsAttr must be non-null. + * @param falseval must be non-null. + */ + public FinderSetProperties(String propsAttr, String falseval) { + this.propsAttr = propsAttr; + this.falseval = falseval; + } + + /** + * Returns a RuleLoader unless the properties contain an entry + * with the name matching constructor param propsAttr, and the value + * matching what is in falseval. + *

+ * If no custom source of rules for a plugin is found, then the user + * almost always wants xml attributes to map to java bean properties, + * so this is the default behaviour unless the user explicitly indicates + * that they do not want a SetPropertiesRule to be provided for + * the plugged-in class. + *

+ * The returned object (when non-null) will add a SetPropertiesRule to + * the digester whenever its addRules method is invoked. + */ + @Override + public RuleLoader findLoader(Digester d, Class pluginClass, Properties p) { + String state = p.getProperty(propsAttr); + if ((state != null) && state.equals(falseval)) { + // user has explicitly disabled automatic setting of properties. + // this is not expected to be common, but allowed. + return null; + } + + return new LoaderSetProperties(); + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/LoaderFromClass.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/LoaderFromClass.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/LoaderFromClass.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,103 @@ +/* $Id: LoaderFromClass.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.lang.reflect.Method; + +import org.apache.commons.digester.Digester; +import org.apache.commons.beanutils.MethodUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.digester.plugins.RuleLoader; +import org.apache.commons.digester.plugins.PluginException; + +/** + * A RuleLoader which invokes a static method on a target class, leaving that + * method to actually instantiate and add new rules to a Digester instance. + * + * @since 1.6 + */ + +public class LoaderFromClass extends RuleLoader { + + private Class rulesClass; + private Method rulesMethod; + + /** Constructor. */ + public LoaderFromClass(Class rulesClass, Method rulesMethod) { + this.rulesClass = rulesClass; + this.rulesMethod = rulesMethod; + } + + /** Constructor. */ + public LoaderFromClass(Class rulesClass, String methodName) + throws PluginException { + + Method method = locateMethod(rulesClass, methodName); + + if (method == null) { + throw new PluginException( + "rule class " + rulesClass.getName() + + " does not have method " + methodName + + " or that method has an invalid signature."); + } + + this.rulesClass = rulesClass; + this.rulesMethod = method; + } + + /** + * Just invoke the target method. + */ + @Override + public void addRules(Digester d, String path) throws PluginException { + Log log = d.getLogger(); + boolean debug = log.isDebugEnabled(); + if (debug) { + log.debug( + "LoaderFromClass loading rules for plugin at path [" + + path + "]"); + } + + try { + Object[] params = {d, path}; + rulesMethod.invoke(null, params); + } catch (Exception e) { + throw new PluginException( + "Unable to invoke rules method " + rulesMethod + + " on rules class " + rulesClass, e); + } + } + + /** + * Find a method on the specified class whose name matches methodName, + * and whose signature is: + * public static void foo(Digester d, String patternPrefix);. + * + * @return null if no such method exists. + */ + public static Method locateMethod(Class rulesClass, String methodName) + throws PluginException { + + Class[] paramSpec = { Digester.class, String.class }; + Method rulesMethod = MethodUtils.getAccessibleMethod( + rulesClass, methodName, paramSpec); + + return rulesMethod; + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/LoaderFromStream.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/LoaderFromStream.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/LoaderFromStream.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,93 @@ +/* $Id: LoaderFromStream.java 992107 2010-09-02 20:31:00Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import org.xml.sax.InputSource; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.plugins.RuleLoader; +import org.apache.commons.digester.plugins.PluginException; +import org.apache.commons.digester.xmlrules.FromXmlRuleSet; +import org.apache.commons.logging.Log; + +/** + * A rule-finding algorithm which loads an xmlplugins-format file. + *

+ * Note that the "include" feature of xmlrules is not supported. + * + * @since 1.6 + */ + +public class LoaderFromStream extends RuleLoader { + + private byte[] input; + + /** See {@link #load}. */ + public LoaderFromStream(InputStream s) throws Exception { + load(s); + } + + /** + * The contents of the input stream are loaded into memory, and + * cached for later use. + *

+ * The caller is responsible for closing the input stream after this + * method has returned. + */ + private void load(InputStream s) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[256]; + for(;;) { + int i = s.read(buf); + if (i == -1) + break; + baos.write(buf, 0, i); + } + input = baos.toByteArray(); + } + + /** + * Add the rules previously loaded from the input stream into the + * specified digester. + */ + @Override + public void addRules(Digester d, String path) throws PluginException { + Log log = d.getLogger(); + boolean debug = log.isDebugEnabled(); + if (debug) { + log.debug( + "LoaderFromStream: loading rules for plugin at path [" + + path + "]"); + } + + // Note that this input-source doesn't have any idea of its + // system id, so it has no way of resolving relative URLs + // such as the "include" feature of xmlrules. This is ok, + // because that doesn't work well with our approach of + // caching the input data in memory anyway. + + InputSource source = new InputSource(new ByteArrayInputStream(input)); + FromXmlRuleSet ruleSet = new FromXmlRuleSet(source); + ruleSet.addRuleInstances(d, path); + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/LoaderSetProperties.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/LoaderSetProperties.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/LoaderSetProperties.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,54 @@ +/* $Id: LoaderSetProperties.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.digester.plugins.strategies; + +import org.apache.commons.digester.Digester; +import org.apache.commons.logging.Log; +import org.apache.commons.digester.plugins.RuleLoader; + +/** + * A RuleLoader which creates a single SetPropertiesRule and adds it to the + * digester when its addRules() method is invoked. + *

+ * This loader ensures that any xml attributes on the plugin tag get + * mapped to equivalent properties on a javabean. This allows JavaBean + * classes to be used as plugins without any requirement to create custom + * plugin rules. + * + * @since 1.6 + */ + +public class LoaderSetProperties extends RuleLoader { + + /** + * Just add a SetPropertiesRule at the specified path. + */ + @Override + public void addRules(Digester digester, String path) { + Log log = digester.getLogger(); + boolean debug = log.isDebugEnabled(); + if (debug) { + log.debug( + "LoaderSetProperties loading rules for plugin at path [" + + path + "]"); + } + + digester.addSetProperties(path); + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/plugins/strategies/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,23 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * The plugins.strategies package contains "rule-finding" strategy + * classes, and their associated "helper" loader classes. + */ +package org.apache.commons.digester.plugins.strategies; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/MultiVariableExpander.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/MultiVariableExpander.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/MultiVariableExpander.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,116 @@ +/* $Id: MultiVariableExpander.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester.substitution; + +import java.util.Map; +import java.util.ArrayList; + +/** + *

Expands variable references from multiple sources.

+ * + * @since 1.6 + */ + +public class MultiVariableExpander implements VariableExpander { + private int nEntries = 0; + private ArrayList markers = new ArrayList(2); + private ArrayList> sources = new ArrayList>(2); + + public MultiVariableExpander() { + } + + public void addSource(String marker, Map source) { + ++nEntries; + markers.add(marker); + sources.add(source); + } + + /* + * Expands any variable declarations using any of the known + * variable marker strings. + * + * @throws IllegalArgumentException if the input param references + * a variable which is not known to the specified source. + */ + public String expand(String param) { + for(int i=0; i + * Commonly, the variable marker is "$", in which case variables + * are indicated by ${key} in the string. + *

+ * Returns the string after performing all substitutions. + *

+ * If no substitutions were made, the input string object is + * returned (not a copy). + * + * @throws IllegalArgumentException if the input param references + * a variable which is not known to the specified source. + */ + public String expand(String str, String marker, Map source) { + String startMark = marker + "{"; + int markLen = startMark.length(); + + int index = 0; + for(;;) + { + index = str.indexOf(startMark, index); + if (index == -1) + { + return str; + } + + int startIndex = index + markLen; + if (startIndex > str.length()) + { + throw new IllegalArgumentException( + "var expression starts at end of string"); + } + + int endIndex = str.indexOf("}", index + markLen); + if (endIndex == -1) + { + throw new IllegalArgumentException( + "var expression starts but does not end"); + } + + String key = str.substring(index+markLen, endIndex); + Object value = source.get(key); + if (value == null) { + throw new IllegalArgumentException( + "parameter [" + key + "] is not defined."); + } + String varValue = value.toString(); + + str = str.substring(0, index) + varValue + str.substring(endIndex+1); + index += varValue.length(); + } + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/VariableAttributes.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/VariableAttributes.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/VariableAttributes.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,140 @@ +/* $Id: VariableAttributes.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.substitution; + +import org.xml.sax.Attributes; + +import java.util.ArrayList; + + +/** + *

Wrapper for an org.xml.sax.Attributes object which expands any + * "variables" referenced in the attribute value via ${foo} or similar. + * This is only done when something actually asks for the attribute value, + * thereby imposing no performance penalty if the attribute is not used.

+ * + * @since 1.6 + */ + +public class VariableAttributes implements Attributes { + + // list of mapped attributes. + private ArrayList values = new ArrayList(10); + + private Attributes attrs; + private VariableExpander expander; + + // ------------------- Public Methods + + /** + * Specify which attributes class this object is a proxy for. + */ + public void init(Attributes attrs, VariableExpander expander) { + this.attrs = attrs; + this.expander = expander; + + // I hope this doesn't release the memory for this array; for + // efficiency, this should just mark the array as being size 0. + values.clear(); + } + + public String getValue(int index) { + if (index >= values.size()) { + // Expand the values array with null elements, so the later + // call to set(index, s) works ok. + // + // Unfortunately, there is no easy way to set the size of + // an arraylist; we must repeatedly add null elements to it.. + values.ensureCapacity(index+1); + for(int i = values.size(); i<= index; ++i) { + values.add(null); + } + } + + String s = values.get(index); + + if (s == null) { + // we have never been asked for this value before. + // get the real attribute value and perform substitution + // on it. + s = attrs.getValue(index); + if (s != null) { + s = expander.expand(s); + values.set(index, s); + } + } + + return s; + } + + public String getValue(String qname) { + int index = attrs.getIndex(qname); + if (index == -1) { + return null; + } + return getValue(index); + } + + public String getValue(String uri, String localname) { + int index = attrs.getIndex(uri, localname); + if (index == -1) { + return null; + } + return getValue(index); + } + + // plain proxy methods follow : nothing interesting :-) + public int getIndex(String qname) { + return attrs.getIndex(qname); + } + + public int getIndex(String uri, String localpart) { + return attrs.getIndex(uri, localpart); + } + + public int getLength() { + return attrs.getLength(); + } + + public String getLocalName(int index) { + return attrs.getLocalName(index); + } + + public String getQName(int index) { + return attrs.getQName(index); + } + + public String getType(int index) { + return attrs.getType(index); + } + + public String getType(String qname) { + return attrs.getType(qname); + } + + public String getType(String uri, String localname) { + return attrs.getType(uri, localname); + } + + public String getURI(int index) { + return attrs.getURI(index); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/VariableExpander.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/VariableExpander.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/VariableExpander.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,38 @@ +/* $Id: VariableExpander.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.substitution; + +/** + *

An Interface describing a class capable of expanding strings which + * may contain variable references. The exact syntax of the "reference", + * and the mechanism for determining the corresponding value to be used + * is up to the concrete implementation.

+ * + * @since 1.6 + */ +public interface VariableExpander { + /** + * Return the input string with any variables replaced by their + * corresponding value. If there are no variables in the string, + * then the input parameter is returned unaltered. + */ + public String expand(String param); +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/VariableSubstitutor.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/VariableSubstitutor.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/VariableSubstitutor.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,108 @@ +/* $Id: VariableSubstitutor.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.digester.substitution; + +import org.apache.commons.digester.Substitutor; + +import org.xml.sax.Attributes; + +/** + * Substitutor implementation that support variable replacement + * for both attributes and body text. + * The actual expansion of variables into text is delegated to {@link VariableExpander} + * implementations. + * Supports setting an expander just for body text or just for attributes. + * Also supported is setting no expanders for body text and for attributes. + * + * @since 1.6 + */ +public class VariableSubstitutor extends Substitutor { + + /** + * The expander to be used to expand variables in the attributes. + * Null when no expansion should be performed. + */ + private VariableExpander attributesExpander; + + /** + * Attributes implementation that (lazily) performs variable substitution. + * Will be lazily created when needed then reused. + */ + private VariableAttributes variableAttributes; + + /** + * The expander to be used to expand variables in the body text. + * Null when no expansion should be performed. + */ + private VariableExpander bodyTextExpander; + + /** + * Constructs a Substitutor which uses the same VariableExpander for both + * body text and attibutes. + * @param expander VariableExpander implementation, + * null if no substitutions are to be performed + */ + public VariableSubstitutor(VariableExpander expander) { + this(expander, expander); + } + + /** + * Constructs a Substitutor. + * @param attributesExpander VariableExpander implementation to be used for attributes, + * null if no attribute substitutions are to be performed + * @param bodyTextExpander VariableExpander implementation to be used for bodyTextExpander, + * null if no attribute substitutions are to be performed + */ + public VariableSubstitutor(VariableExpander attributesExpander, VariableExpander bodyTextExpander) { + this.attributesExpander = attributesExpander; + this.bodyTextExpander = bodyTextExpander; + variableAttributes = new VariableAttributes(); + } + + /** + * Substitutes the attributes (before they are passed to the + * Rule implementations's) + */ + @Override + public Attributes substitute(Attributes attributes) { + Attributes results = attributes; + if (attributesExpander != null) { + variableAttributes.init(attributes, attributesExpander); + results = variableAttributes; + } + return results; + } + + /** + * Substitutes for the body text. + * This method may substitute values into the body text of the + * elements that Digester parses. + * + * @param bodyText the body text (as passed to Digester) + * @return the body text to be passed to the Rule implementations + */ + @Override + public String substitute(String bodyText) { + String result = bodyText; + if (bodyTextExpander != null) { + result = bodyTextExpander.expand(bodyText); + } + return result; + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/substitution/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,23 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * The substitution provides for manipulation of xml attributes and + * element body text before the data is processed by any Rule objects. + */ +package org.apache.commons.digester.substitution; Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/CircularIncludeException.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/CircularIncludeException.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/CircularIncludeException.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,42 @@ +/* $Id: CircularIncludeException.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.xmlrules; + + +/** + * Thrown when parsing XML into Digester rules, if a circular inclusion occurred + * in the xml digester rules files. + * + * @since 1.2 + */ + +public class CircularIncludeException extends XmlLoadException { + + private static final long serialVersionUID = 1L; + + /** + * @param fileName the name of the XML file suspected of causing the + * circular inclusion + */ + public CircularIncludeException(String fileName) { + super("Circular file inclusion detected for file: " + fileName); + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterLoader.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterLoader.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterLoader.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,252 @@ +/* $Id: DigesterLoader.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.xmlrules; + + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.net.URL; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.RuleSet; + +import org.xml.sax.SAXException; +import org.xml.sax.InputSource; + + +/** + * This class manages the creation of Digester instances from XML digester + * rules files. + * + * @since 1.2 + */ + +public class DigesterLoader { + + /** + * Creates a new digester and initializes it from the specified InputSource + * @param rulesSource load the xml rules from this InputSource + * @return a new Digester initialized with the rules + */ + public static Digester createDigester(InputSource rulesSource) { + RuleSet ruleSet = new FromXmlRuleSet(rulesSource); + Digester digester = new Digester(); + digester.addRuleSet(ruleSet); + return digester; + } + + /** + * Creates a new digester and initializes it from the specified InputSource. + * This constructor allows the digester to be used to load the rules to be specified. + * This allows properties to be configured on the Digester instance before it is used. + * + * @param rulesSource load the xml rules from this InputSource + * @param rulesDigester digester to load the specified XML file. + * @return a new Digester initialized with the rules + */ + public static Digester createDigester(InputSource rulesSource, Digester rulesDigester) { + RuleSet ruleSet = new FromXmlRuleSet(rulesSource, rulesDigester); + Digester digester = new Digester(); + digester.addRuleSet(ruleSet); + return digester; + } + + /** + * Creates a new digester and initializes it from the specified XML file + * @param rulesXml URL to the XML file defining the digester rules + * @return a new Digester initialized with the rules + */ + public static Digester createDigester(URL rulesXml) { + RuleSet ruleSet = new FromXmlRuleSet(rulesXml); + Digester digester = new Digester(); + digester.addRuleSet(ruleSet); + return digester; + } + + /** + * Creates a new digester and initializes it from the specified XML file. + * This constructor allows specifing a rulesDigester to do the XML file + * loading; thus no matter the XML files is packed into a jar, a war, or a + * ear, the rulesDigester can always find the XML files with properly set + * ClassLoader. + * + * @param rulesXml URL to the XML file defining the digester rules + * @param rulesDigester digester to load the specified XML file. + * @return a new Digester initialized with the rules + */ + public static Digester createDigester(URL rulesXml, Digester rulesDigester) { + RuleSet ruleSet = new FromXmlRuleSet(rulesXml, rulesDigester); + Digester digester = new Digester(); + digester.addRuleSet(ruleSet); + return digester; + } + + /** + * Given the digester rules XML file, a class loader, and an XML input file, + * this method parses the input file into Java objects. The class loader + * is used by the digester to create the Java objects. + * @param digesterRules URL to the XML document defining the digester rules + * @param classLoader the ClassLoader to register with the digester + * @param fileURL URL to the XML file to parse into Java objects + * @return an Object which is the root of the network of Java objects + * created by digesting fileURL + */ + public static Object load(URL digesterRules, ClassLoader classLoader, + URL fileURL) throws IOException, SAXException, DigesterLoadingException { + return load(digesterRules, classLoader, fileURL.openStream()); + } + + /** + * Given the digester rules XML file, a class loader, and an input stream, + * this method parses the input into Java objects. The class loader + * is used by the digester to create the Java objects. + * @param digesterRules URL to the XML document defining the digester rules + * @param classLoader the ClassLoader to register with the digester + * @param input InputStream over the XML file to parse into Java objects + * @return an Object which is the root of the network of Java objects + * created by digesting fileURL + */ + public static Object load(URL digesterRules, ClassLoader classLoader, + InputStream input) throws IOException, SAXException, DigesterLoadingException { + Digester digester = createDigester(digesterRules); + digester.setClassLoader(classLoader); + try { + return digester.parse(input); + } catch (XmlLoadException ex) { + // This is a runtime exception that can be thrown by + // FromXmlRuleSet#addRuleInstances, which is called by the Digester + // before it parses the file. + throw new DigesterLoadingException(ex.getMessage(), ex); + } + } + + /** + * Given the digester rules XML file, a class loader, and an input stream, + * this method parses the input into Java objects. The class loader + * is used by the digester to create the Java objects. + * @param digesterRules URL to the XML document defining the digester rules + * @param classLoader the ClassLoader to register with the digester + * @param reader Reader over the XML file to parse into Java objects + * @return an Object which is the root of the network of Java objects + * created by digesting fileURL + */ + public static Object load( + URL digesterRules, + ClassLoader classLoader, + Reader reader) + throws + IOException, + SAXException, + DigesterLoadingException { + Digester digester = createDigester(digesterRules); + digester.setClassLoader(classLoader); + try { + return digester.parse(reader); + } catch (XmlLoadException ex) { + // This is a runtime exception that can be thrown by + // FromXmlRuleSet#addRuleInstances, which is called by the Digester + // before it parses the file. + throw new DigesterLoadingException(ex.getMessage(), ex); + } + } + + + /** + * Given the digester rules XML file, a class loader, and an XML input file, + * this method parses the input file into Java objects. The class loader + * is used by the digester to create the Java objects. + * @param digesterRules URL to the XML document defining the digester rules + * @param classLoader the ClassLoader to register with the digester + * @param fileURL URL to the XML file to parse into Java objects + * @param rootObject an Object to push onto the digester's stack, prior + * to parsing the input + * @return an Object which is the root of the network of Java objects. + * Usually, this will be the same object as rootObject + * created by digesting fileURL + */ + public static Object load(URL digesterRules, ClassLoader classLoader, + URL fileURL, Object rootObject) throws IOException, SAXException, + DigesterLoadingException { + return load(digesterRules, classLoader, fileURL.openStream(), rootObject); + } + + /** + * Given the digester rules XML file, a class loader, and an input stream, + * this method parses the input into Java objects. The class loader + * is used by the digester to create the Java objects. + * @param digesterRules URL to the XML document defining the digester rules + * @param classLoader the ClassLoader to register with the digester + * @param input InputStream over the XML file to parse into Java objects + * @param rootObject an Object to push onto the digester's stack, prior + * to parsing the input + * @return an Object which is the root of the network of Java objects + * created by digesting fileURL + */ + public static Object load(URL digesterRules, ClassLoader classLoader, + InputStream input, Object rootObject) throws IOException, SAXException, + DigesterLoadingException { + Digester digester = createDigester(digesterRules); + digester.setClassLoader(classLoader); + digester.push(rootObject); + try { + return digester.parse(input); + } catch (XmlLoadException ex) { + // This is a runtime exception that can be thrown by + // FromXmlRuleSet#addRuleInstances, which is called by the Digester + // before it parses the file. + throw new DigesterLoadingException(ex.getMessage(), ex); + } + } + + /** + * Given the digester rules XML file, a class loader, and an input stream, + * this method parses the input into Java objects. The class loader + * is used by the digester to create the Java objects. + * @param digesterRules URL to the XML document defining the digester rules + * @param classLoader the ClassLoader to register with the digester + * @param input Reader over the XML file to parse into Java objects + * @param rootObject an Object to push onto the digester's stack, prior + * to parsing the input + * @return an Object which is the root of the network of Java objects + * created by digesting fileURL + */ + public static Object load( + URL digesterRules, + ClassLoader classLoader, + Reader input, + Object rootObject) + throws + IOException, + SAXException, + DigesterLoadingException { + Digester digester = createDigester(digesterRules); + digester.setClassLoader(classLoader); + digester.push(rootObject); + try { + return digester.parse(input); + } catch (XmlLoadException ex) { + // This is a runtime exception that can be thrown by + // FromXmlRuleSet#addRuleInstances, which is called by the Digester + // before it parses the file. + throw new DigesterLoadingException(ex.getMessage(), ex); + } + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterLoadingException.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterLoadingException.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterLoadingException.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,68 @@ +/* $Id: DigesterLoadingException.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.xmlrules; + + +/** + * Thrown when an error occurs while parsing XML into Digester rules. + * + * @since 1.2 + */ + +public class DigesterLoadingException extends Exception { + + private static final long serialVersionUID = 1L; + private Throwable cause = null; + + /** + * @param msg a String detailing the reason for the exception + */ + public DigesterLoadingException(String msg) { + super(msg); + } + + /** + * @param cause underlying exception that caused this to be thrown + */ + public DigesterLoadingException(Throwable cause) { + this(cause.getMessage()); + this.cause = cause; + } + + /** + * @param msg a String detailing the reason for the exception + * @param cause underlying exception that caused this to be thrown + */ + public DigesterLoadingException(String msg, Throwable cause) { + this(msg); + this.cause = cause; + } + + /** + * Return the cause of this exception (if any) as specified in the + * exception constructor. + * + * @since 1.8 + */ + @Override + public Throwable getCause() { + return cause; + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterRuleParser.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterRuleParser.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterRuleParser.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,872 @@ +/* $Id: DigesterRuleParser.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.xmlrules; + + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Stack; +import java.util.StringTokenizer; + +import org.apache.commons.beanutils.ConvertUtils; +import org.apache.commons.digester.AbstractObjectCreationFactory; +import org.apache.commons.digester.BeanPropertySetterRule; +import org.apache.commons.digester.CallMethodRule; +import org.apache.commons.digester.CallParamRule; +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.FactoryCreateRule; +import org.apache.commons.digester.NodeCreateRule; +import org.apache.commons.digester.ObjectCreateRule; +import org.apache.commons.digester.ObjectParamRule; +import org.apache.commons.digester.Rule; +import org.apache.commons.digester.RuleSetBase; +import org.apache.commons.digester.Rules; +import org.apache.commons.digester.SetNestedPropertiesRule; +import org.apache.commons.digester.SetNextRule; +import org.apache.commons.digester.SetPropertiesRule; +import org.apache.commons.digester.SetPropertyRule; +import org.apache.commons.digester.SetRootRule; +import org.apache.commons.digester.SetTopRule; +import org.w3c.dom.Node; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + + +/** + * This is a RuleSet that parses XML into Digester rules, and then + * adds those rules to a 'target' Digester. + * + * @since 1.2 + */ + +public class DigesterRuleParser extends RuleSetBase { + + public static final String DIGESTER_PUBLIC_ID = "-//Jakarta Apache //DTD digester-rules XML V1.0//EN"; + + /** + * path to the DTD + */ + private String digesterDtdUrl; + + /** + * This is the digester to which we are adding the rules that we parse + * from the Rules XML document. + */ + protected Digester targetDigester; + + /** See {@link #setBasePath}. */ + protected String basePath = ""; + + /** + * A stack whose toString method returns a '/'-separated concatenation + * of all the elements in the stack. + */ + protected class PatternStack extends Stack { + + private static final long serialVersionUID = 1L; + + @Override + public String toString() { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < size(); i++) { + String elem = get(i).toString(); + if (elem.length() > 0) { + if (str.length() > 0) { + str.append('/'); + } + str.append(elem); + } + } + return str.toString(); + } + } + + /** + * A stack used to maintain the current pattern. The Rules XML document + * type allows nesting of patterns. If an element defines a matching + * pattern, the resulting pattern is a concatenation of that pattern with + * all the ancestor elements' patterns. Hence the need for a stack. + */ + protected PatternStack patternStack; + + /** + * Used to detect circular includes + */ + private Set includedFiles = new HashSet(); + + /** + * Constructs a DigesterRuleParser. This object will be inoperable + * until the target digester is set, via setTarget(Digester) + */ + public DigesterRuleParser() { + patternStack = new PatternStack(); + } + + /** + * Constructs a rule set for converting XML digester rule descriptions + * into Rule objects, and adding them to the given Digester + * @param targetDigester the Digester to add the rules to + */ + public DigesterRuleParser(Digester targetDigester) { + this.targetDigester = targetDigester; + patternStack = new PatternStack(); + } + + /** + * Constructs a rule set for parsing an XML digester rule file that + * has been included within an outer XML digester rule file. In this + * case, we must pass the pattern stack and the target digester + * to the rule set, as well as the list of files that have already + * been included, for cycle detection. + * @param targetDigester the Digester to add the rules to + * @param stack Stack containing the prefix pattern string to be prepended + * to any pattern parsed by this rule set. + */ + private DigesterRuleParser(Digester targetDigester, + PatternStack stack, Set includedFiles) { + this.targetDigester = targetDigester; + patternStack = stack; + this.includedFiles = includedFiles; + } + + /** + * Sets the digester into which to add the parsed rules + * @param d the Digester to add the rules to + */ + public void setTarget(Digester d) { + targetDigester = d; + } + + /** + * Set a base pattern beneath which all the rules loaded by this + * object will be registered. If this string is not empty, and does + * not end in a "/", then one will be added. + * + * @since 1.6 + */ + public void setBasePath(String path) { + if (path == null) { + basePath = ""; + } + else if ((path.length() > 0) && !path.endsWith("/")) { + basePath = path + "/"; + } else { + basePath = path; + } + } + + /** + * Sets the location of the digester rules DTD. This is the DTD used + * to validate the rules XML file. + */ + public void setDigesterRulesDTD(String dtdURL) { + digesterDtdUrl = dtdURL; + } + + /** + * Returns the location of the DTD used to validate the digester rules + * XML document. + */ + protected String getDigesterRulesDTD() { + //ClassLoader classLoader = getClass().getClassLoader(); + //URL url = classLoader.getResource(DIGESTER_DTD_PATH); + //return url.toString(); + return digesterDtdUrl; + } + + /** + * Adds a rule the the target digester. After a rule has been created by + * parsing the XML, it is added to the digester by calling this method. + * Typically, this method is called via reflection, when executing + * a SetNextRule, from the Digester that is parsing the rules XML. + * @param rule a Rule to add to the target digester. + */ + public void add(Rule rule) { + targetDigester.addRule( + basePath + patternStack.toString(), rule); + } + + + /** + * Add to the given digester the set of Rule instances used to parse an XML + * document defining Digester rules. When the digester parses an XML file, + * it will add the resulting rules & patterns to the 'target digester' + * that was passed in this RuleSet's constructor.

+ * If you extend this class to support additional rules, your implementation + * should of this method should call this implementation first: i.e. + * super.addRuleInstances(digester); + */ + @Override + public void addRuleInstances(Digester digester) { + final String ruleClassName = Rule.class.getName(); + digester.register(DIGESTER_PUBLIC_ID, getDigesterRulesDTD()); + + digester.addRule("*/pattern", new PatternRule("value")); + + digester.addRule("*/include", new IncludeRule()); + + digester.addFactoryCreate("*/bean-property-setter-rule", new BeanPropertySetterRuleFactory()); + digester.addRule("*/bean-property-setter-rule", new PatternRule("pattern")); + digester.addSetNext("*/bean-property-setter-rule", "add", ruleClassName); + + digester.addFactoryCreate("*/call-method-rule", new CallMethodRuleFactory()); + digester.addRule("*/call-method-rule", new PatternRule("pattern")); + digester.addSetNext("*/call-method-rule", "add", ruleClassName); + + digester.addFactoryCreate("*/object-param-rule", new ObjectParamRuleFactory()); + digester.addRule("*/object-param-rule", new PatternRule("pattern")); + digester.addSetNext("*/object-param-rule", "add", ruleClassName); + + digester.addFactoryCreate("*/call-param-rule", new CallParamRuleFactory()); + digester.addRule("*/call-param-rule", new PatternRule("pattern")); + digester.addSetNext("*/call-param-rule", "add", ruleClassName); + + digester.addFactoryCreate("*/factory-create-rule", new FactoryCreateRuleFactory()); + digester.addRule("*/factory-create-rule", new PatternRule("pattern")); + digester.addSetNext("*/factory-create-rule", "add", ruleClassName); + + digester.addFactoryCreate("*/object-create-rule", new ObjectCreateRuleFactory()); + digester.addRule("*/object-create-rule", new PatternRule("pattern")); + digester.addSetNext("*/object-create-rule", "add", ruleClassName); + + digester.addFactoryCreate("*/node-create-rule", new NodeCreateRuleFactory()); + digester.addRule("*/node-create-rule", new PatternRule("pattern")); + digester.addSetNext("*/node-create-rule", "add", ruleClassName); + + digester.addFactoryCreate("*/set-properties-rule", new SetPropertiesRuleFactory()); + digester.addRule("*/set-properties-rule", new PatternRule("pattern")); + digester.addSetNext("*/set-properties-rule", "add", ruleClassName); + + digester.addRule("*/set-properties-rule/alias", new SetPropertiesAliasRule()); + + digester.addFactoryCreate("*/set-property-rule", new SetPropertyRuleFactory()); + digester.addRule("*/set-property-rule", new PatternRule("pattern")); + digester.addSetNext("*/set-property-rule", "add", ruleClassName); + + digester.addFactoryCreate("*/set-nested-properties-rule", new SetNestedPropertiesRuleFactory()); + digester.addRule("*/set-nested-properties-rule", new PatternRule("pattern")); + digester.addSetNext("*/set-nested-properties-rule", "add", ruleClassName); + + digester.addRule("*/set-nested-properties-rule/alias", new SetNestedPropertiesAliasRule()); + + digester.addFactoryCreate("*/set-top-rule", new SetTopRuleFactory()); + digester.addRule("*/set-top-rule", new PatternRule("pattern")); + digester.addSetNext("*/set-top-rule", "add", ruleClassName); + + digester.addFactoryCreate("*/set-next-rule", new SetNextRuleFactory()); + digester.addRule("*/set-next-rule", new PatternRule("pattern")); + digester.addSetNext("*/set-next-rule", "add", ruleClassName); + digester.addFactoryCreate("*/set-root-rule", new SetRootRuleFactory()); + digester.addRule("*/set-root-rule", new PatternRule("pattern")); + digester.addSetNext("*/set-root-rule", "add", ruleClassName); + } + + + /** + * A rule for extracting the pattern matching strings from the rules XML. + * In the digester-rules document type, a pattern can either be declared + * in the 'value' attribute of a element (in which case the pattern + * applies to all rules elements contained within the element), + * or it can be declared in the optional 'pattern' attribute of a rule + * element. + */ + private class PatternRule extends Rule { + + private String attrName; + private String pattern = null; + + /** + * @param attrName The name of the attribute containing the pattern + */ + public PatternRule(String attrName) { + super(); + this.attrName = attrName; + } + + /** + * If a pattern is defined for the attribute, push it onto the + * pattern stack. + */ + @Override + public void begin(Attributes attributes) { + pattern = attributes.getValue(attrName); + if (pattern != null) { + patternStack.push(pattern); + } + } + + /** + * If there was a pattern for this element, pop it off the pattern + * stack. + */ + @Override + public void end() { + if (pattern != null) { + patternStack.pop(); + } + } + } + + /** + * A rule for including one rules XML file within another. Included files + * behave as if they are 'macro-expanded' within the includer. This means + * that the values of the pattern stack are prefixed to every pattern + * in the included rules.

This rule will detect 'circular' includes, + * which would result in infinite recursion. It throws a + * CircularIncludeException when a cycle is detected, which will terminate + * the parse. + */ + private class IncludeRule extends Rule { + public IncludeRule() { + super(); + } + + /** + * To include a rules xml file, we instantiate another Digester, and + * another DigesterRulesRuleSet. We pass the + * pattern stack and the target Digester to the new rule set, and + * tell the Digester to parse the file. + */ + @Override + public void begin(Attributes attributes) throws Exception { + // The path attribute gives the URI to another digester rules xml file + String fileName = attributes.getValue("path"); + if (fileName != null && fileName.length() > 0) { + includeXMLRules(fileName); + } + + // The class attribute gives the name of a class that implements + // the DigesterRulesSource interface + String className = attributes.getValue("class"); + if (className != null && className.length() > 0) { + includeProgrammaticRules(className); + } + } + + /** + * Creates another DigesterRuleParser, and uses it to extract the rules + * out of the give XML file. The contents of the current pattern stack + * will be prepended to all of the pattern strings parsed from the file. + */ + private void includeXMLRules(String fileName) + throws IOException, SAXException, CircularIncludeException { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + cl = DigesterRuleParser.this.getClass().getClassLoader(); + } + URL fileURL = cl.getResource(fileName); + if (fileURL == null) { + throw new FileNotFoundException("File \"" + fileName + "\" not found."); + } + fileName = fileURL.toExternalForm(); + if (includedFiles.add(fileName) == false) { + // circular include detected + throw new CircularIncludeException(fileName); + } + // parse the included xml file + DigesterRuleParser includedSet = + new DigesterRuleParser(targetDigester, patternStack, includedFiles); + includedSet.setDigesterRulesDTD(getDigesterRulesDTD()); + Digester digester = new Digester(); + digester.addRuleSet(includedSet); + digester.push(DigesterRuleParser.this); + digester.parse(fileName); + includedFiles.remove(fileName); + } + + /** + * Creates an instance of the indicated class. The class must implement + * the DigesterRulesSource interface. Passes the target digester to + * that instance. The DigesterRulesSource instance is supposed to add + * rules into the digester. The contents of the current pattern stack + * will be automatically prepended to all of the pattern strings added + * by the DigesterRulesSource instance. + */ + private void includeProgrammaticRules(String className) + throws ClassNotFoundException, ClassCastException, + InstantiationException, IllegalAccessException { + + Class cls = Class.forName(className); + DigesterRulesSource rulesSource = (DigesterRulesSource) cls.newInstance(); + + // wrap the digester's Rules object, to prepend pattern + Rules digesterRules = targetDigester.getRules(); + Rules prefixWrapper = + new RulesPrefixAdapter(patternStack.toString(), digesterRules); + + targetDigester.setRules(prefixWrapper); + try { + rulesSource.getRules(targetDigester); + } finally { + // Put the unwrapped rules back + targetDigester.setRules(digesterRules); + } + } + } + + + /** + * Wraps a Rules object. Delegates all the Rules interface methods + * to the underlying Rules object. Overrides the add method to prepend + * a prefix to the pattern string. + */ + private class RulesPrefixAdapter implements Rules { + + private Rules delegate; + private String prefix; + + /** + * @param patternPrefix the pattern string to prepend to the pattern + * passed to the add method. + * @param rules The wrapped Rules object. All of this class's methods + * pass through to this object. + */ + public RulesPrefixAdapter(String patternPrefix, Rules rules) { + prefix = patternPrefix; + delegate = rules; + } + + /** + * Register a new Rule instance matching a pattern which is constructed + * by concatenating the pattern prefix with the given pattern. + */ + public void add(String pattern, Rule rule) { + StringBuffer buffer = new StringBuffer(); + buffer.append(prefix); + if (!pattern.startsWith("/")) { + buffer.append('/'); + } + buffer.append(pattern); + delegate.add(buffer.toString(), rule); + } + + /** + * This method passes through to the underlying Rules object. + */ + public void clear() { + delegate.clear(); + } + + /** + * This method passes through to the underlying Rules object. + */ + public Digester getDigester() { + return delegate.getDigester(); + } + + /** + * This method passes through to the underlying Rules object. + */ + public String getNamespaceURI() { + return delegate.getNamespaceURI(); + } + + /** + * @deprecated Call match(namespaceURI,pattern) instead. + */ + @Deprecated + public List match(String pattern) { + return delegate.match(pattern); + } + + /** + * This method passes through to the underlying Rules object. + */ + public List match(String namespaceURI, String pattern) { + return delegate.match(namespaceURI, pattern); + } + + /** + * This method passes through to the underlying Rules object. + */ + public List rules() { + return delegate.rules(); + } + + /** + * This method passes through to the underlying Rules object. + */ + public void setDigester(Digester digester) { + delegate.setDigester(digester); + } + + /** + * This method passes through to the underlying Rules object. + */ + public void setNamespaceURI(String namespaceURI) { + delegate.setNamespaceURI(namespaceURI); + } + } + + + /////////////////////////////////////////////////////////////////////// + // Classes beyond this point are ObjectCreationFactory implementations, + // used to create Rule objects and initialize them from SAX attributes. + /////////////////////////////////////////////////////////////////////// + + /** + * Factory for creating a BeanPropertySetterRule. + */ + private class BeanPropertySetterRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) throws Exception { + Rule beanPropertySetterRule = null; + String propertyname = attributes.getValue("propertyname"); + + if (propertyname == null) { + // call the setter method corresponding to the element name. + beanPropertySetterRule = new BeanPropertySetterRule(); + } else { + beanPropertySetterRule = new BeanPropertySetterRule(propertyname); + } + + return beanPropertySetterRule; + } + + } + + /** + * Factory for creating a CallMethodRule. + */ + protected class CallMethodRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) { + Rule callMethodRule = null; + String methodName = attributes.getValue("methodname"); + + // Select which element is to be the target. Default to zero, + // ie the top object on the stack. + int targetOffset = 0; + String targetOffsetStr = attributes.getValue("targetoffset"); + if (targetOffsetStr != null) { + targetOffset = Integer.parseInt(targetOffsetStr); + } + + if (attributes.getValue("paramcount") == null) { + // call against empty method + callMethodRule = new CallMethodRule(targetOffset, methodName); + + } else { + int paramCount = Integer.parseInt(attributes.getValue("paramcount")); + + String paramTypesAttr = attributes.getValue("paramtypes"); + if (paramTypesAttr == null || paramTypesAttr.length() == 0) { + callMethodRule = new CallMethodRule(targetOffset, methodName, paramCount); + } else { + String[] paramTypes = getParamTypes(paramTypesAttr); + callMethodRule = new CallMethodRule( + targetOffset, methodName, paramCount, paramTypes); + } + } + return callMethodRule; + } + + /** + * Process the comma separated list of paramTypes + * into an array of String class names + */ + private String[] getParamTypes(String paramTypes) { + String[] paramTypesArray; + if( paramTypes != null ) { + ArrayList paramTypesList = new ArrayList(); + StringTokenizer tokens = new StringTokenizer( + paramTypes, " \t\n\r,"); + while (tokens.hasMoreTokens()) { + paramTypesList.add(tokens.nextToken()); + } + paramTypesArray = paramTypesList.toArray(new String[0]); + } else { + paramTypesArray = new String[0]; + } + return paramTypesArray; + } + } + + /** + * Factory for creating a CallParamRule. + */ + protected class CallParamRuleFactory extends AbstractObjectCreationFactory { + + @Override + public Object createObject(Attributes attributes) { + // create callparamrule + int paramIndex = Integer.parseInt(attributes.getValue("paramnumber")); + String attributeName = attributes.getValue("attrname"); + String fromStack = attributes.getValue("from-stack"); + String stackIndex = attributes.getValue("stack-index"); + Rule callParamRule = null; + + if (attributeName == null) { + if (stackIndex != null) { + callParamRule = new CallParamRule( + paramIndex, Integer.parseInt(stackIndex)); + } else if (fromStack != null) { + callParamRule = new CallParamRule( + paramIndex, Boolean.valueOf(fromStack).booleanValue()); + } else { + callParamRule = new CallParamRule(paramIndex); + } + } else { + if (fromStack == null) { + callParamRule = new CallParamRule(paramIndex, attributeName); + } else { + // specifying both from-stack and attribute name is not allowed + throw new RuntimeException( + "Attributes from-stack and attrname cannot both be present."); + } + } + return callParamRule; + } + } + + /** + * Factory for creating a ObjectParamRule + */ + protected class ObjectParamRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) throws Exception { + // create callparamrule + int paramIndex = Integer.parseInt(attributes.getValue("paramnumber")); + String attributeName = attributes.getValue("attrname"); + String type = attributes.getValue("type"); + String value = attributes.getValue("value"); + + Rule objectParamRule = null; + + // type name is requried + if (type == null) { + throw new RuntimeException("Attribute 'type' is required."); + } + + // create object instance + Object param = null; + Class clazz = Class.forName(type); + if (value == null) { + param = clazz.newInstance(); + } else { + param = ConvertUtils.convert(value, clazz); + } + + if (attributeName == null) { + objectParamRule = new ObjectParamRule(paramIndex, param); + } else { + objectParamRule = new ObjectParamRule(paramIndex, attributeName, param); + } + return objectParamRule; + } + } + + /** + * Factory for creating a NodeCreateRule + */ + protected class NodeCreateRuleFactory extends AbstractObjectCreationFactory { + + @Override + public Object createObject(Attributes attributes) throws Exception { + + String nodeType = attributes.getValue("type"); + if (nodeType == null || "".equals(nodeType)) { + + // uses Node.ELEMENT_NODE + return new NodeCreateRule(); + } else if ("element".equals(nodeType)) { + + return new NodeCreateRule(Node.ELEMENT_NODE); + } else if ("fragment".equals(nodeType)) { + + return new NodeCreateRule(Node.DOCUMENT_FRAGMENT_NODE); + } else { + + throw new RuntimeException( + "Unrecognized node type: " + + nodeType + + ". This attribute is optional or can have a value of element|fragment."); + } + } + } + + /** + * Factory for creating a FactoryCreateRule + */ + protected class FactoryCreateRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) { + String className = attributes.getValue("classname"); + String attrName = attributes.getValue("attrname"); + boolean ignoreExceptions = + "true".equalsIgnoreCase(attributes.getValue("ignore-exceptions")); + return (attrName == null || attrName.length() == 0) ? + new FactoryCreateRule( className, ignoreExceptions) : + new FactoryCreateRule( className, attrName, ignoreExceptions); + } + } + + /** + * Factory for creating a ObjectCreateRule + */ + protected class ObjectCreateRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) { + String className = attributes.getValue("classname"); + String attrName = attributes.getValue("attrname"); + return (attrName == null || attrName.length() == 0) ? + new ObjectCreateRule( className) : + new ObjectCreateRule( className, attrName); + } + } + + /** + * Factory for creating a SetPropertiesRule + */ + protected class SetPropertiesRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) { + return new SetPropertiesRule(); + } + } + + /** + * Factory for creating a SetPropertyRule + */ + protected class SetPropertyRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) { + String name = attributes.getValue("name"); + String value = attributes.getValue("value"); + return new SetPropertyRule( name, value); + } + } + + /** + * Factory for creating a SetNestedPropertiesRule + */ + protected class SetNestedPropertiesRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) { + boolean allowUnknownChildElements = + "true".equalsIgnoreCase(attributes.getValue("allow-unknown-child-elements")); + SetNestedPropertiesRule snpr = new SetNestedPropertiesRule(); + snpr.setAllowUnknownChildElements( allowUnknownChildElements ); + return snpr; + } + } + + /** + * Factory for creating a SetTopRuleFactory + */ + protected class SetTopRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) { + String methodName = attributes.getValue("methodname"); + String paramType = attributes.getValue("paramtype"); + return (paramType == null || paramType.length() == 0) ? + new SetTopRule( methodName) : + new SetTopRule( methodName, paramType); + } + } + + /** + * Factory for creating a SetNextRuleFactory + */ + protected class SetNextRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) { + String methodName = attributes.getValue("methodname"); + String paramType = attributes.getValue("paramtype"); + return (paramType == null || paramType.length() == 0) ? + new SetNextRule( methodName) : + new SetNextRule( methodName, paramType); + } + } + + /** + * Factory for creating a SetRootRuleFactory + */ + protected class SetRootRuleFactory extends AbstractObjectCreationFactory { + @Override + public Object createObject(Attributes attributes) { + String methodName = attributes.getValue("methodname"); + String paramType = attributes.getValue("paramtype"); + return (paramType == null || paramType.length() == 0) ? + new SetRootRule( methodName) : + new SetRootRule( methodName, paramType); + } + } + + /** + * A rule for adding a attribute-property alias to the custom alias mappings of + * the containing SetPropertiesRule rule. + */ + protected class SetPropertiesAliasRule extends Rule { + + /** + *

Base constructor.

+ */ + public SetPropertiesAliasRule() { + super(); + } + + /** + * Add the alias to the SetPropertiesRule object created by the + * enclosing tag. + */ + @Override + public void begin(Attributes attributes) { + String attrName = attributes.getValue("attr-name"); + String propName = attributes.getValue("prop-name"); + + SetPropertiesRule rule = (SetPropertiesRule) digester.peek(); + rule.addAlias(attrName, propName); + } + } + + /** + * A rule for adding a attribute-property alias to the custom alias mappings of + * the containing SetNestedPropertiesRule rule. + */ + protected class SetNestedPropertiesAliasRule extends Rule { + + /** + *

Base constructor.

+ */ + public SetNestedPropertiesAliasRule() { + super(); + } + + /** + * Add the alias to the SetNestedPropertiesRule object created by the + * enclosing tag. + */ + @Override + public void begin(Attributes attributes) { + String attrName = attributes.getValue("attr-name"); + String propName = attributes.getValue("prop-name"); + + SetNestedPropertiesRule rule = (SetNestedPropertiesRule) digester.peek(); + rule.addAlias(attrName, propName); + } + } + +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterRulesSource.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterRulesSource.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/DigesterRulesSource.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,42 @@ +/* $Id: DigesterRulesSource.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.xmlrules; + + +import org.apache.commons.digester.Digester; + + +/** + * Interface for classes that initialize a Digester Rules object with + * Digester Rules. + * + * @since 1.2 + */ + +public interface DigesterRulesSource { + + /** + * Creates and adds Digester Rules to a given Rules object + * @param digester the Digester to add the new Rule objects to + */ + void getRules(Digester digester); + +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/FromXmlRuleSet.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/FromXmlRuleSet.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/FromXmlRuleSet.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,223 @@ +/* $Id: FromXmlRuleSet.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.xmlrules; + + +import java.net.URL; + +import org.apache.commons.digester.Digester; +import org.apache.commons.digester.RuleSetBase; + +import org.xml.sax.InputSource; + +/** + * A Digester rule set where the rules come from an XML file. + * + * @since 1.2 + */ +public class FromXmlRuleSet extends RuleSetBase { + + public static final String DIGESTER_DTD_PATH = "org/apache/commons/digester/xmlrules/digester-rules.dtd"; + + /** + * The file containing the Digester rules, in XML. + */ + private XMLRulesLoader rulesLoader; + + /** + * The rule set for parsing the Digester rules + */ + private DigesterRuleParser parser; + + /** + * The digester for loading the rules xml. + */ + private Digester rulesDigester; + + /** + * Constructs a FromXmlRuleSet using the default DigesterRuleParser and + * rulesDigester. + * @param rulesXml the path to the XML document defining the Digester rules + */ + public FromXmlRuleSet(URL rulesXml) { + this(rulesXml, new DigesterRuleParser(), new Digester()); + } + + /** + * Constructs a FromXmlRuleSet using the default DigesterRuleParser and + * a ruleDigester for loading the rules xml. + * @param rulesXml the path to the XML document defining the Digester rules + * @param rulesDigester the digester to read the rules xml. + */ + public FromXmlRuleSet(URL rulesXml, Digester rulesDigester) { + this(rulesXml, new DigesterRuleParser(), rulesDigester); + } + + /** + * @param rulesXml the path to the XML document defining the Digester rules + * @param parser an instance of DigesterRuleParser, for parsing the rules from XML + */ + public FromXmlRuleSet(URL rulesXml, DigesterRuleParser parser) { + this(rulesXml, parser, new Digester()); + } + + /** + * @param rulesXml the path to the XML document defining the Digester rules + * @param parser an instance of DigesterRuleParser, for parsing the rules from XML + * @param rulesDigester the digester used to load the Xml rules. + */ + public FromXmlRuleSet(URL rulesXml, DigesterRuleParser parser, Digester rulesDigester) { + init(new URLXMLRulesLoader(rulesXml), parser, rulesDigester); + } + + /** + * Constructs a FromXmlRuleSet using the default DigesterRuleParser and + * rulesDigester. + * @param inputSource load the xml rules from this InputSource + */ + public FromXmlRuleSet(InputSource inputSource) { + this(inputSource, new DigesterRuleParser(), new Digester()); + } + + /** + * Constructs a FromXmlRuleSet using the default DigesterRuleParser and + * a ruleDigester for loading the rules xml. + * @param inputSource load the xml rules from this InputSource + * @param rulesDigester the digester to read the rules xml. + */ + public FromXmlRuleSet(InputSource inputSource, Digester rulesDigester) { + this(inputSource, new DigesterRuleParser(), rulesDigester); + } + + /** + * @param inputSource load the xml rules from this InputSource + * @param parser an instance of DigesterRuleParser, for parsing the rules from XML + */ + public FromXmlRuleSet(InputSource inputSource, DigesterRuleParser parser) { + this(inputSource, parser, new Digester()); + } + + /** + * @param inputSource load the xml rules from this InputSource + * @param parser an instance of DigesterRuleParser, for parsing the rules from XML + * @param rulesDigester the digester used to load the Xml rules. + */ + public FromXmlRuleSet(InputSource inputSource, DigesterRuleParser parser, Digester rulesDigester) { + init(new InputSourceXMLRulesLoader(inputSource), parser, rulesDigester); + } + + /** + * Base constructor + */ + private void init(XMLRulesLoader rulesLoader, DigesterRuleParser parser, Digester rulesDigester) { + this.rulesLoader = rulesLoader; + this.parser = parser; + this.rulesDigester = rulesDigester; + } + + /** + * Adds to the digester the set of Rule instances defined in the + * XML file for this rule set. + * @see org.apache.commons.digester.RuleSetBase + */ + @Override + public void addRuleInstances(org.apache.commons.digester.Digester digester) throws XmlLoadException { + addRuleInstances(digester, null); + } + + /** + * Adds to the digester the set of Rule instances defined in the + * XML file for this rule set. + *

+ * Note that this method doesn't have a matching one on the DigesterLoader + * class, because it is not expected to be widely used, and DigesterLoader's + * load method is already heavily overloaded. + * + * @param digester is the digester that rules will be added to. + * @param basePath is a path that will be prefixed to every + * pattern string defined in the xmlrules input file. + * + * @see org.apache.commons.digester.RuleSetBase + * @since 1.6 + */ + public void addRuleInstances( + org.apache.commons.digester.Digester digester, + String basePath) + throws XmlLoadException { + + URL dtdURL = getClass().getClassLoader().getResource(DIGESTER_DTD_PATH); + if (dtdURL == null) { + throw new XmlLoadException("Cannot find resource \"" + + DIGESTER_DTD_PATH + "\""); + } + parser.setDigesterRulesDTD(dtdURL.toString()); + parser.setTarget(digester); + parser.setBasePath(basePath); + + rulesDigester.addRuleSet(parser); + rulesDigester.push(parser); + + rulesLoader.loadRules(); + } + + /** + * Worker class encapsulates loading mechanisms. + * Private until some reason is found to make it public. + */ + private abstract static class XMLRulesLoader { + /** Load rules now */ + public abstract void loadRules() throws XmlLoadException; + } + + /** Loads XMLRules from an URL */ + private class URLXMLRulesLoader extends XMLRulesLoader { + private URL url; + public URLXMLRulesLoader(URL url) { + this.url = url; + } + + @Override + public void loadRules() throws XmlLoadException { + try { + rulesDigester.parse(url.openStream()); + } catch (Exception ex) { + throw new XmlLoadException(ex); + } + } + } + + /** Loads XMLRules from an InputSource */ + private class InputSourceXMLRulesLoader extends XMLRulesLoader { + private InputSource inputSource; + public InputSourceXMLRulesLoader(InputSource inputSource) { + this.inputSource = inputSource; + } + + @Override + public void loadRules() throws XmlLoadException { + try { + rulesDigester.parse(inputSource); + } catch (Exception ex) { + throw new XmlLoadException(ex); + } + } + } +} + Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/XmlLoadException.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/XmlLoadException.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/XmlLoadException.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,58 @@ +/* $Id: XmlLoadException.java 992060 2010-09-02 19:09:47Z simonetripodi $ + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.commons.digester.xmlrules; + + +/** + * Thrown when an error occurs while parsing XML into Digester rules. + * + * @since 1.2 + */ +public class XmlLoadException extends RuntimeException { + + private static final long serialVersionUID = 1L; + private Throwable cause = null; + + /** + * @param cause underlying exception that caused this to be thrown + */ + public XmlLoadException(Throwable cause) { + this(cause.getMessage()); + this.cause = cause; + } + + public XmlLoadException(String msg) { + super(msg); + } + + public XmlLoadException(String msg, Throwable cause) { + this(msg); + this.cause = cause; + } + + /** + * Returns the cause of this throwable or null if the cause is + * nonexistent or unknown. + */ + @Override + public Throwable getCause() { + return cause; + } +} Index: 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/package-info.java =================================================================== diff -u --- 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/package-info.java (revision 0) +++ 3rdParty_sources/commons-digester/org/apache/commons/digester/xmlrules/package-info.java (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -0,0 +1,24 @@ +/* $Id: package-info.java 991743 2010-09-01 22:44:15Z simonetripodi $ + * + * 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. + */ + +/** + * The Digester package lets you configure an XML -> Java object mapping module, + * which triggers certain actions called rules whenever a particular pattern of + * nested XML elements is recognized. + */ +package org.apache.commons.digester.xmlrules; Index: 3rdParty_sources/versions.txt =================================================================== diff -u -r3c74b053b74047179fa7515d236817b875af4cb9 -rae060b7e61e715d667e47c7ee61f04fa2f2a0fbc --- 3rdParty_sources/versions.txt (.../versions.txt) (revision 3c74b053b74047179fa7515d236817b875af4cb9) +++ 3rdParty_sources/versions.txt (.../versions.txt) (revision ae060b7e61e715d667e47c7ee61f04fa2f2a0fbc) @@ -15,6 +15,8 @@ Apache POI 3.16 +Commons Digester 2.1 + Commons Lang 2.6 Commons IO 2.4