You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sk...@apache.org on 2005/02/20 01:38:00 UTC
svn commit: r154457 [1/2] - in
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins:
./ strategies/
Author: skitching
Date: Sat Feb 19 16:37:55 2005
New Revision: 154457
URL: http://svn.apache.org/viewcvs?view=rev&rev=154457
Log:
Initial port of plugins module from digester 1.x series
Added:
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/Declaration.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/LogUtils.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginAssertionFailure.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginConfiguration.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginCreateAction.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationAction.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationScope.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginException.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginInvalidInputException.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginRuleManager.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleFinder.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleLoader.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/package.html
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromClass.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltClass.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltMethod.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromMethod.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderSetProperties.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderFromClass.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderSetProperties.java (with props)
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/package.html
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/Declaration.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/Declaration.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/Declaration.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/Declaration.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,230 @@
+/* $Id$
+ *
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+import java.io.IOException;
+import java.util.Properties;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.digester2.Context;
+
+/**
+ * Represents a Class that can be instantiated by a PluginCreateAction, plus
+ * info on how to load custom digester rules for mapping xml into that
+ * plugged-in class.
+ * <p>
+ * Declaration instances are created by either:
+ * <ul>
+ * <li> PluginCreateAction from method startParse time, in the case where a
+ * plugin has a default plugin class.
+ * <li> PluginCreateAction from method begin, in the case where the input
+ * xml just declares the plugin class on the matching tag, eg
+ * [widget plugin-class="com.acme.widget" ...]
+ * <li> PluginDeclarationAction, in the case where the input xml pre-declares
+ * the plugin class, eg [plugin-declaration id="..." class=".." ..../]
+ * </ul>
+ */
+
+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.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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(Context context, PluginDeclarationScope pds)
+ throws PluginException {
+ Log log = context.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 =
+ context.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 = pds.findLoader(context, 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.
+ * <p>
+ * On return, any custom rules associated with the plugin class have
+ * been loaded into the Rules object currently associated with the
+ * specified digester object.
+ * <p>
+ * This method is called by PluginCreateAction, after ensuring that
+ * the declaration exists and has been initialised.
+ */
+
+ public void configure(Context context) throws PluginException {
+ Log log = context.getLogger();
+ boolean debug = log.isDebugEnabled();
+ if (debug) {
+ log.debug("configure being called!");
+ }
+
+ if (!initialized) {
+ throw new PluginAssertionFailure("Not initialized.");
+ }
+
+ if (ruleLoader != null) {
+ ruleLoader.addRules(context);
+ }
+ }
+}
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/Declaration.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/LogUtils.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/LogUtils.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/LogUtils.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/LogUtils.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,67 @@
+/* $Id$
+ *
+ * Copyright 2003-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+import org.apache.commons.digester2.Context;
+import org.apache.commons.logging.Log;
+
+/**
+ * Simple utility class to assist in logging.
+ * <p>
+ * This class is intended only for the use of the code in the
+ * plugins packages. No "user" code should use this package.
+ * <p>
+ * The Digester library has an interesting approach to logging:
+ * all logging should be done via the Log object stored on the
+ * context instance that the object *doing* the logging is associated
+ * with.
+ * <p>
+ * This is done because apparently some "container"-type applications
+ * such as Avalon and Tomcat need to be able to configure different logging
+ * for different <i>instances</i> of the Digester/SAXHandler class which have
+ * been loaded from the same ClassLoader [info from Craig McClanahan].
+ * All objects associated with that Digester instance should obey the
+ * reconfiguration of their owning saxhandler instance's logging. The current
+ * solution is to force all objects to output logging info via a single
+ * Log object stored on the saxhandler (and context).instance they are
+ * associated with.
+ * <p>
+ * Of course this causes problems if logging is attempted before an
+ * object <i>has</i> a valid reference to a context. The
+ * getLogging method provided here resolves this issue by returning a
+ * Log object which silently discards all logging output in this
+ * situation.
+ * <p>
+ * 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...
+ */
+
+class LogUtils {
+
+ /**
+ * Get the Log object associated with the specified context instance,
+ * or a "no-op" logging object if the context reference is null.
+ */
+ static Log getLogger(Context context) {
+ if (context == null) {
+ return new org.apache.commons.logging.impl.NoOpLog();
+ }
+
+ return context.getLogger();
+ }
+}
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/LogUtils.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginAssertionFailure.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginAssertionFailure.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginAssertionFailure.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginAssertionFailure.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,68 @@
+/* $Id$
+ *
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+/**
+ * Thrown when a bug is detected in the plugins code.
+ * <p>
+ * 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.
+ * <p>
+ * This difference in design is because throwing Error objects is not
+ * good in a container-based architecture.
+ * <p>
+ * Example:
+ * <pre>
+ * if (impossibleCondition) {
+ * throw new PluginAssertionFailure(
+ * "internal error: impossible condition is true");
+ * }
+ * </pre>
+ * <p>
+ * Note that PluginAssertionFailure should <i>not</i> 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.
+ */
+public class PluginAssertionFailure extends PluginException {
+
+ /**
+ * @param cause underlying exception that caused this to be thrown
+ */
+ public PluginAssertionFailure(Throwable cause) {
+ super(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) {
+ super(msg, cause);
+ }
+}
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginAssertionFailure.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginConfiguration.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginConfiguration.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginConfiguration.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginConfiguration.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,250 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+import java.io.IOException;
+import java.util.Properties;
+import java.util.List;
+import java.util.LinkedList;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.digester2.Digester;
+import org.apache.commons.digester2.SAXHandler;
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.plugins.strategies.*;
+
+/**
+ * Provides configuration that is per-saxhandler (or per-digester).
+ */
+
+public class PluginConfiguration {
+ private static final SAXHandler.ItemId PLUGIN_CONFIGURATION_ITEM
+ = new SAXHandler.ItemId(PluginConfiguration.class, "instance");
+
+ // the xml attribute the user uses on an xml element to specify
+ // the plugin's class
+ public final String DFLT_PLUGIN_CLASS_ATTR_NS = "";
+ 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 = "";
+ 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 PluginCreateAction instances to locate the custom
+ * rules for plugin classes.
+ */
+ private List ruleFinders;
+
+ //------------------- constructors ---------------------------------------
+
+ public static PluginConfiguration getInstance(Digester digester) {
+ return getInstance(digester.getSAXHandler());
+ }
+
+ public static PluginConfiguration getInstance(Context context) {
+ return getInstance(context.getSAXHandler());
+ }
+
+ public static PluginConfiguration getInstance(SAXHandler saxHandler) {
+ PluginConfiguration pc =
+ (PluginConfiguration) saxHandler.getItem(PLUGIN_CONFIGURATION_ITEM);
+
+ if (pc == null) {
+ pc = new PluginConfiguration();
+ saxHandler.putItem(PLUGIN_CONFIGURATION_ITEM, pc);
+ }
+
+ return pc;
+ }
+
+ //------------------- 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * Example:
+ * <pre>
+ * setPluginClassAttribute(null, "class");
+ * </pre>
+ * will allow this in the input xml:
+ * <pre>
+ * <root>
+ * <some-plugin class="com.acme.widget"> ......
+ * </pre>
+ * instead of the default syntax:
+ * <pre>
+ * <root>
+ * <some-plugin plugin-class="com.acme.widget"> ......
+ * </pre>
+ * This is particularly useful if the input xml document is not in
+ * English.
+ * <p>
+ * 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 <i>not</i>
+ * contain any kind of namespace-prefix. Note also that if you are using
+ * a non-namespace-aware parser, this parameter <i>must</i> 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.
+ * <p>
+ * Example:
+ * <pre>
+ * setPluginIdAttribute(null, "id");
+ * </pre>
+ * will allow this in the input xml:
+ * <pre>
+ * <root>
+ * <some-plugin id="widget"> ......
+ * </pre>
+ * rather than the default behaviour:
+ * <pre>
+ * <root>
+ * <some-plugin plugin-id="widget"> ......
+ * </pre>
+ * This is particularly useful if the input xml document is not in
+ * English.
+ * <p>
+ * 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 <i>not</i>
+ * contain any kind of namespace-prefix. Note also that if you are using
+ * a non-namespace-aware parser, this parameter <i>must</i> 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * The return value is never null.
+ */
+ public String getPluginIdAttr() {
+ return pluginIdAttr;
+ }
+}
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginConfiguration.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginCreateAction.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginCreateAction.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginCreateAction.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginCreateAction.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,589 @@
+/* $Id$
+ *
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.List;
+import java.io.File;
+
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.Action;
+import org.apache.commons.digester2.AbstractAction;
+import org.apache.commons.digester2.RuleManager;
+import org.apache.commons.digester2.DefaultRuleManager;
+import org.apache.commons.digester2.ParseException;
+import org.apache.commons.digester2.DigestionException;
+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.
+ */
+public class PluginCreateAction extends AbstractAction {
+
+ /**
+ * Simple data structure to store the names of the xml attributes
+ * that the xml elements which matches this action will use to
+ * tell us what class to instantiate.
+ */
+ private static class PluginAttrNames {
+ String pluginClassAttrNS = null;
+ String pluginClassAttr = null;
+ String pluginIdAttrNS = null;
+ String pluginIdAttr = null;
+ }
+
+ private final Context.ItemId PLUGIN_ATTR_NAMES
+ = new Context.ItemId(PluginCreateAction.class, "PluginAttrNames", this);
+
+ // See constructors. Note that these contain only values provided by the
+ // user. If we default to a per-digester value or to a global default,
+ // these member variables remain unaltered. This is because Actions are
+ // forbidden to change any member variables during a parse.
+ private String pluginClassAttrNS;
+ private String pluginClassAttr;
+ private String pluginIdAttrNS;
+ private String pluginIdAttr;
+
+ /** 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;
+
+ //-------------------- constructors -------------------------------------
+
+ /**
+ * Create a plugin rule where the user <i>must</i> specify a plugin-class
+ * or plugin-id.
+ *
+ * @param baseClass is the class which any specified plugin <i>must</i> be
+ * descended from.
+ */
+ public PluginCreateAction(Class baseClass) {
+ this.baseClass = baseClass;
+ }
+
+ /**
+ * Create a plugin rule where the user <i>may</i> 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 <i>must</i> 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 PluginCreateAction(Class baseClass, Class dfltPluginClass) {
+ this.baseClass = baseClass;
+ if (dfltPluginClass != null) {
+ defaultPlugin = new Declaration(dfltPluginClass);
+ }
+ }
+
+ /**
+ * Create a plugin rule where the user <i>may</i> 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 <i>must</i> 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 PluginCreateAction(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.
+ * <p>
+ * 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.
+ * <p>
+ * See {@link PluginRules#setPluginIdAttribute} for more info.
+ */
+ public void setPluginIdAttribute(String namespaceUri, String attrName) {
+ pluginIdAttrNS = namespaceUri;
+ pluginIdAttr = attrName;
+ }
+
+ //------------------- methods --------------------------------------------
+
+ /**
+ * Invoked before parsing begins on a document.
+ * <p>
+ * We ensure the default plugin class is loaded into memory, and
+ * that it does indeed implement the declared base class for this
+ * plugin point. We then ensure any custom rules for the default
+ * plugin have been located, though we don't add them to a RuleManager
+ * yet.
+ *
+ *
+ * @exception PluginConfigurationException
+ */
+ public void startParse(Context context)
+ throws PluginException {
+ // TODO: determine whether there will be problems with using
+ // wildcard patterns with a PluginCreateAction, or with adding
+ // the same instance multiple times..
+
+ Log log = LogUtils.getLogger(context);
+ boolean debug = log.isDebugEnabled();
+ if (debug) {
+ log.debug("PluginCreateAction.beginParse");
+ }
+
+ if (baseClass == null) {
+ baseClass = Object.class;
+ }
+
+ PluginDeclarationScope pds =
+ (PluginDeclarationScope) context.getItem(
+ PluginDeclarationScope.PLUGIN_DECL_SCOPE);
+
+ if (defaultPlugin != null) {
+ // check default class is valid. We can't do this until the parse
+ // begins, as we need to load the baseClass and plugin class via
+ // the classloader associated with the context.
+ if (!baseClass.isAssignableFrom(defaultPlugin.getPluginClass())) {
+ throw new PluginException(
+ "Default class [" +
+ defaultPlugin.getPluginClass().getName() +
+ "] does not inherit from [" +
+ baseClass.getName() + "].");
+ }
+
+ // initialise the plugin declaration, which means a RuleLoader
+ // will figure out where the custom rules for the default plugin
+ // class are...
+ defaultPlugin.init(context, pds);
+ }
+
+ PluginAttrNames pluginAttrNames = createPluginAttrNames(context);
+ // and now we've done all that work, cache the info in the context
+ // as instance-specific data.
+ context.putItem(PLUGIN_ATTR_NAMES, pluginAttrNames);
+ }
+
+ /**
+ * Invoked when the Digester matches this rule against an xml element.
+ * <p>
+ * A new instance of the target class is created, and pushed onto the
+ * stack. A new "private" PluginRuleManager object is then created and
+ * set as the current RuleManager object. Any custom rules associated with
+ * the plugin class are then loaded into that new RuleManager object.
+ * Finally, any custom rules that are associated with the current pattern
+ * (such as SetPropertiesAction) have their begin methods executed.
+ *
+ * @param namespace
+ * @param name
+ * @param attributes
+ *
+ * @throws ClassNotFoundException
+ * @throws PluginInvalidInputException
+ * @throws PluginConfigurationException
+ */
+ public void begin(
+ Context context,
+ String namespace, String name,
+ org.xml.sax.Attributes attributes)
+ throws ParseException {
+ String path = context.getMatchPath();
+
+ Log log = context.getLogger();
+ boolean debug = log.isDebugEnabled();
+ if (debug) {
+ log.debug("PluginCreateRule.begin" +
+ " match=[" + path + "]");
+ }
+
+ // load any custom rules associated with the plugin
+ PluginDeclarationScope pds = PluginDeclarationScope.getInstance(context);
+
+ // and get the cached info calculated at startParse time...
+ PluginAttrNames pluginAttrNames = (PluginAttrNames)
+ context.getItem(PLUGIN_ATTR_NAMES);
+
+ Declaration currDeclaration = null;
+
+ String pluginClassName = attributes.getValue(
+ pluginAttrNames.pluginClassAttrNS,
+ pluginAttrNames.pluginClassAttr);
+
+ String pluginId = attributes.getValue(
+ pluginAttrNames.pluginIdAttrNS,
+ pluginAttrNames.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 = pds.getDeclarationByClass(pluginClassName);
+
+ if (currDeclaration == null) {
+ currDeclaration = new Declaration(pluginClassName);
+ try {
+ currDeclaration.init(context, pds);
+ } catch(PluginException pwe) {
+ throw new PluginInvalidInputException(
+ pwe.getMessage(), pwe.getCause());
+ }
+ pds.addDeclaration(currDeclaration);
+ }
+ } else if (pluginId != null) {
+ currDeclaration = pds.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 " + path);
+ }
+
+ // get the class of the user plugged-in type
+ Class pluginClass = currDeclaration.getPluginClass();
+
+ // create a new RuleManager object and effectively push it onto a
+ // stack of rules objects. The stack is actually a linked list;
+ // using the PluginRuleManager constructor below causes the new
+ // instance to link to the previous head-of-stack, then calling
+ // context.setRules() makes the new instance the new head-of-stack.
+ RuleManager oldRuleManager = context.getRuleManager();
+ RuleManager delegateRuleManager = new DefaultRuleManager();
+ PluginRuleManager newRuleManager
+ = new PluginRuleManager(oldRuleManager, delegateRuleManager, path);
+ context.setRuleManager(newRuleManager);
+
+ if (debug) {
+ log.debug("PluginCreateRule.begin: installing new plugin: " +
+ "oldrules=" + oldRuleManager.toString() +
+ ", newrules=" + newRuleManager.toString());
+ }
+
+ // load up the custom rules
+ currDeclaration.configure(context);
+
+ // create an instance of the plugin class
+ try {
+ Object instance = pluginClass.newInstance();
+ context.push(instance);
+ } catch(InstantiationException ex) {
+ throw new ParseException(
+ "Unable to instantiate class [" + pluginClass.getName() + "]",
+ ex);
+ } catch(IllegalAccessException ex) {
+ throw new ParseException(
+ "Not permitted to instantiate class [" + pluginClass.getName() + "]",
+ ex);
+ }
+
+ if (debug) {
+ log.debug(
+ "PluginCreateAction.begin" +
+ " match=[" + context.getMatchPath() + "]" +
+ " 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 actions;
+ try {
+ actions = newRuleManager.getMatchingActions(path);
+ } catch(DigestionException ex) {
+ throw new ParseException(
+ "Unable to get matching actions from class "
+ + this.getClass().getName(),
+ ex);
+ }
+ fireBeginMethods(context, actions, namespace, name, attributes);
+ }
+
+ /**
+ * Process the body text of this element.
+ *
+ * @param text The body text of this element
+ */
+ public void body(Context context, String namespace, String name, String text)
+ throws ParseException {
+
+ // 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 = context.getMatchPath();
+ RuleManager newRuleManager = context.getRuleManager();
+ List actions;
+ try {
+ actions = newRuleManager.getMatchingActions(context.getMatchPath());
+ } catch(DigestionException ex) {
+ throw new ParseException(
+ "Unable to get matching actions from class "
+ + this.getClass().getName(),
+ ex);
+ }
+ fireBodyMethods(context, actions, 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
+ */
+ public void end(Context context, String namespace, String name)
+ throws ParseException {
+
+ // see body method for more info
+ String path = context.getMatchPath();
+ PluginRuleManager newRuleManager
+ = (PluginRuleManager) context.getRuleManager();
+
+ List actions;
+ try {
+ actions = newRuleManager.getMatchingActions(context.getMatchPath());
+ } catch(DigestionException ex) {
+ throw new ParseException(
+ "Unable to get matching actions from class "
+ + this.getClass().getName(),
+ ex);
+ }
+ fireEndMethods(context, actions, namespace, name);
+
+ // pop the stack of PluginRuleManager instances, which
+ // discards all custom rules associated with this plugin
+ context.setRuleManager(newRuleManager.getParent());
+
+ // and get rid of the instance of the plugin class from the
+ // digester object stack.
+ context.pop();
+ }
+
+ /**
+ * 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(
+ Context context,
+ List actions,
+ String namespace, String name,
+ org.xml.sax.Attributes list)
+ throws ParseException {
+ Log log = context.getLogger();
+ boolean debug = log.isDebugEnabled();
+ for (int i = 0; i < actions.size(); i++) {
+ try {
+ Action action = (Action) actions.get(i);
+ if (debug) {
+ log.debug(" Fire begin() for " + action);
+ }
+ action.begin(context, namespace, name, list);
+ } catch (PluginException 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(
+ Context context,
+ List actions,
+ String namespaceURI, String name,
+ String text) throws ParseException {
+
+ if (actions.size() > 0) {
+ Log log = context.getLogger();
+ boolean debug = log.isDebugEnabled();
+ for (int i = 0; i < actions.size(); i++) {
+ try {
+ Action action = (Action) actions.get(i);
+ if (debug) {
+ log.debug(" Fire body() for " + action);
+ }
+ action.body(context, namespaceURI, name, text);
+ } catch (ParseException 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(
+ Context context,
+ List actions,
+ String namespaceURI, String name)
+ throws ParseException {
+
+ // Fire "end" events for all relevant rules in reverse order
+ Log log = context.getLogger();
+ boolean debug = log.isDebugEnabled();
+ for (int i = 0; i < actions.size(); i++) {
+ int j = (actions.size() - i) - 1;
+ try {
+ Action action = (Action) actions.get(j);
+ if (debug) {
+ log.debug(" Fire end() for " + action);
+ }
+ action.end(context, namespaceURI, name);
+ } catch (ParseException e) {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Determine what xml attributews are expected to be present on the matched
+ * xml element in order to tell us which plugin class to load.
+ */
+ private PluginAttrNames createPluginAttrNames(Context context) {
+ Log log = context.getLogger();
+ boolean debug = log.isDebugEnabled();
+
+ PluginConfiguration pc = PluginConfiguration.getInstance(context);
+
+ PluginAttrNames pluginAttrNames = new PluginAttrNames();
+
+ if (pluginClassAttr == null) {
+ // the user hasn't set explicit xml attr names on this action,
+ // so fetch the per-saxhandler default values
+ pluginAttrNames.pluginClassAttrNS = pc.getPluginClassAttrNS();
+ if (pluginAttrNames.pluginClassAttrNS == null) {
+ pluginAttrNames.pluginClassAttrNS = pc.DFLT_PLUGIN_CLASS_ATTR_NS;
+ }
+
+ pluginAttrNames.pluginClassAttr = pc.getPluginClassAttr();
+ if (pluginAttrNames.pluginClassAttr == null) {
+ pluginAttrNames.pluginClassAttr = pc.DFLT_PLUGIN_CLASS_ATTR;
+ }
+
+ if (debug) {
+ log.debug(
+ "init: pluginClassAttr set to values ["
+ + "ns=" + pluginAttrNames.pluginClassAttrNS
+ + ", name=" + pluginAttrNames.pluginClassAttr + "]");
+ }
+ } else {
+ // ok, we use the values specified in setPluginClassAttribute method.
+ pluginAttrNames.pluginClassAttrNS = pluginClassAttrNS;
+ pluginAttrNames.pluginClassAttr = pluginClassAttr;
+ if (debug) {
+ log.debug(
+ "init: pluginClassAttr set to action-specific values ["
+ + "ns=" + pluginClassAttrNS
+ + ", name=" + pluginClassAttr + "]");
+ }
+ }
+
+ // what xml attributes are expected to be present on the matched
+ // xml element in order to tell us which preceding plugin declaration
+ // to use?
+ if (pluginIdAttr == null) {
+ // the user hasn't set explicit xml attr names on this rule,
+ // so fetch the default values
+ pluginAttrNames.pluginIdAttrNS = pc.getPluginIdAttrNS();
+ if (pluginAttrNames.pluginIdAttrNS == null) {
+ pluginAttrNames.pluginIdAttrNS = pc.DFLT_PLUGIN_ID_ATTR_NS;
+ }
+
+ pluginAttrNames.pluginIdAttr = pc.getPluginIdAttr();
+ if (pluginAttrNames.pluginIdAttr == null) {
+ pluginAttrNames.pluginIdAttr = pc.DFLT_PLUGIN_ID_ATTR;
+ }
+
+ if (debug) {
+ log.debug(
+ "init: pluginIdAttr set to values ["
+ + "ns=" + pluginAttrNames.pluginIdAttrNS
+ + ", name=" + pluginAttrNames.pluginIdAttr + "]");
+ }
+ } else {
+ // ok, we use the values specified in setPluginIdAttribute method.
+ pluginAttrNames.pluginIdAttrNS = pluginIdAttrNS;
+ pluginAttrNames.pluginIdAttr = pluginIdAttr;
+ if (debug) {
+ log.debug(
+ "init: pluginIdAttr set to rule-specific values ["
+ + "ns=" + pluginIdAttrNS
+ + ", name=" + pluginIdAttr + "]");
+ }
+ }
+
+ return pluginAttrNames;
+ }
+}
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginCreateAction.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationAction.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationAction.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationAction.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationAction.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,141 @@
+/* $Id$
+ *
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+import java.util.Properties;
+
+import org.apache.commons.digester2.Action;
+import org.apache.commons.digester2.AbstractAction;
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.ParseException;
+import org.apache.commons.beanutils.MethodUtils;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * A digester Action which allows the user to pre-declare a class which is to
+ * be referenced later at a plugin point by a PluginCreateAction.
+ * <p>
+ * Normally, a PluginDeclarationAction 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.
+ */
+
+public class PluginDeclarationAction extends AbstractAction {
+
+ //------------------- constructors ---------------------------------------
+
+ /** constructor */
+ public PluginDeclarationAction() {
+ }
+
+ //------------------- methods --------------------------------------------
+
+ /**
+ * Invoked upon reading a tag defining a plugin declaration. The tag
+ * must have the following mandatory attributes:
+ * <ul>
+ * <li> id </li>
+ * <li> class </li>
+ * </ul>
+ *
+ *@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
+ */
+
+ public void begin(
+ Context context,
+ String namespace, String name,
+ org.xml.sax.Attributes attributes)
+ throws ParseException {
+
+ // copy all the attribute values into a properties object so that
+ // the plugin finder strategies can access the properties later.
+ int nAttrs = attributes.getLength();
+ Properties props = new Properties();
+ for(int i=0; i<nAttrs; ++i) {
+ String key = attributes.getLocalName(i);
+ if ((key == null) || (key.length() == 0)) {
+ key = attributes.getQName(i);
+ }
+ String value = attributes.getValue(i);
+ props.setProperty(key, value);
+ }
+
+ try {
+ declarePlugin(context, props);
+ } catch(PluginInvalidInputException ex) {
+ throw new PluginInvalidInputException(
+ "Error on element [" + context.getMatchPath() +
+ "]: " + ex.getMessage());
+ }
+ }
+
+ /**
+ * Creates a Declaration object to represent this implicit or explicit
+ * declaration of a plugin, and store it away in the PluginManager object
+ * associated with the current context so it can be retrieved later when
+ * a PluginCreateAction fires.
+ * <p>
+ * Note that this (static) method is called directly from the
+ * PluginCreateAction class if an "inline declaration" is found, ie where
+ * the xml element that triggers the PluginCreateAction also provides the
+ * necessary declaration information.
+ */
+ public static void declarePlugin(Context context, Properties props)
+ throws PluginException {
+
+ Log log = context.getLogger();
+ boolean debug = log.isDebugEnabled();
+
+// PluginConfiguration pc = PluginConfiguration.getInstance(context);
+
+ String id = props.getProperty("id");
+ String pluginClassName = props.getProperty("class");
+
+ if (id == null) {
+ throw new PluginInvalidInputException(
+ "mandatory attribute id not present on plugin declaration");
+ }
+
+ if (pluginClassName == null) {
+ throw new PluginInvalidInputException(
+ "mandatory attribute class not present on plugin declaration");
+ }
+
+ Declaration newDecl = new Declaration(pluginClassName);
+ newDecl.setId(id);
+ newDecl.setProperties(props);
+
+ PluginDeclarationScope pds = PluginDeclarationScope.getInstance(context);
+
+ // Create a RuleLoader instance which is capable of adding dynamic
+ // rules for the plugged-in class to a RuleManager instance. The
+ // dynamic rules don't get added until a PluginCreateAction fires,
+ // so redeclaring a plugin multiple times is fine...
+ newDecl.init(context, pds);
+
+ // and remember it for later...
+ pds.addDeclaration(newDecl);
+ }
+}
+
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationAction.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationScope.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationScope.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationScope.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationScope.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,248 @@
+/* $Id$
+ *
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Properties;
+import java.util.Iterator;
+
+import org.apache.commons.digester2.Context;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * Provides a location to store plugin declarations.
+ * <p>
+ * Plugin declarations are created by either:
+ * <ul>
+ * <li> PluginCreateAction from method startParse time, in the case where a
+ * plugin has a default plugin class.
+ * <li> PluginCreateAction from method begin, in the case where the input
+ * xml just declares the plugin class on the matching tag, eg
+ * [widget plugin-class="com.acme.widget" ...]
+ * <li> PluginDeclarationAction, in the case where the input xml pre-declares
+ * the plugin class, eg [plugin-declaration id="..." class=".." ..../]
+ * </ul>
+ * <p>
+ * When plugin declarations are encountered in the input xml, they
+ * should "shadow" (temporarily override) declarations made within
+ * parent elements. And when the element within which the declaration
+ * occurred ends, all information about those declarations should be
+ * discarded, causing:
+ * <ol>
+ * <li>any references to those declarations after they have gone out
+ * of scope to be errors, and
+ * <li>any declarations previously "shadowed" to be "unshadowed"
+ * </ol>
+ * <p>
+ * This is implemented by having a stack of instances of this class. When
+ * declarations occur in a new scope, a new instance of this class is pushed
+ * onto the corresponding stack. Lookups for declarations are always performed
+ * on the top object on the stack, so the most "recent" declarations are seen.
+ * If a declaration is not found on the top object, it delegates the lookup to
+ * the previous object, etc. And when a declaration scope ends, the stack is
+ * popped, thereby discarding the out-of-scope plugin declarations.
+ * <p>
+ * Note that there is a problem with the current implementation of declaration
+ * scoping. The problem is not in this class, but in the code which decides
+ * when to push and pop new instances of this class. Simply, declaration scopes
+ * should last until the end of the parent xml element containing the
+ * declaration (not the end of the declaration element itself) - but Digester
+ * doesn't provide any hooks to allow detection of the end of the parent
+ * element. The current solution, therefore, is to regard a scope as starting
+ * when a PluginCreateAction fires. This does at least separate the scope of
+ * declarations within a plugin from those "above" the plugin point which is
+ * the most important issue.
+ * <p>
+ * At some future time, if digester provides the facility to perform actions
+ * associated with "the parent tag", then the PluginDeclarationScope stack
+ * can be decoupled from the firing of PluginCreateRule instances.
+ */
+
+public class PluginDeclarationScope {
+
+ public static final Context.ItemId PLUGIN_DECL_SCOPE
+ = new Context.ItemId(PluginDeclarationScope.class, "PluginDecls");
+
+ /** 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 PluginDeclarationScope parent;
+
+ // ---------------------------------------------------------------------
+ // Static Methods
+ // ---------------------------------------------------------------------
+
+ /**
+ * Extract the current (top) PluginDeclarationScope object from the
+ * provided context. If one hasn't been created yet, then do so.
+ * <p>
+ * This is similar to a singleton method, except that there is a
+ * PluginDeclarationScope per context.
+ * <p>
+ * Note that instead of using a "scratch stack" in the context, we
+ * just use a "scratch item" which returns the most-recent
+ * PluginDeclarationScope. As each of these objects contains a reference
+ * to its "parent" scope, this is effectively a linked-list-stack.
+ */
+ public static PluginDeclarationScope getInstance(Context context) {
+ PluginDeclarationScope pds =
+ (PluginDeclarationScope) context.getItem(PLUGIN_DECL_SCOPE);
+ if (pds == null) {
+ pds = new PluginDeclarationScope();
+ context.putItem(PLUGIN_DECL_SCOPE, pds);
+ }
+
+ return pds;
+ }
+
+ //------------------- constructors ---------------------------------------
+
+ /** Construct a "root" PluginDeclarationScope, ie one with no parent. */
+ public PluginDeclarationScope() {
+ }
+
+ /**
+ * Construct a "child" PluginDeclarationScope. 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.
+ * <p>
+ * @param parent must be non-null.
+ */
+ public PluginDeclarationScope(PluginDeclarationScope parent) {
+ this.parent = parent;
+ }
+
+ //------------------- methods --------------------------------------------
+
+ /**
+ * Add the declaration to the set of known declarations.
+ * <p>
+ * 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 =
+ (Declaration) 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 = (Declaration) 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).
+ * <p>
+ * If no source of custom rules can be found, null is returned.
+ */
+ public RuleLoader findLoader(
+ Context context, 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(context);
+ boolean debug = log.isDebugEnabled();
+ log.debug("scanning ruleFinders to locate loader..");
+
+ PluginConfiguration pluginConfig =
+ PluginConfiguration.getInstance(context.getSAXHandler());
+
+ List ruleFinders = pluginConfig.getRuleFinders();
+ RuleLoader ruleLoader = null;
+ try {
+ for(Iterator i = ruleFinders.iterator();
+ i.hasNext() && ruleLoader == null; ) {
+
+ RuleFinder finder = (RuleFinder) i.next();
+ if (debug) {
+ log.debug("checking finder of type " + finder.getClass().getName());
+ }
+ ruleLoader = finder.findLoader(context, 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;
+ }
+}
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginDeclarationScope.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginException.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginException.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginException.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginException.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,49 @@
+/* $Id$
+ *
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+import org.apache.commons.digester2.ParseException;
+
+/**
+ * Thrown when some plugin-related error has occurred, and none of the
+ * other exception types are appropriate.
+ */
+
+public class PluginException extends ParseException {
+ /**
+ * @param cause underlying exception that caused this to be thrown
+ */
+ public PluginException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * @param msg describes the reason this exception is being thrown.
+ */
+ public PluginException(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 PluginException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginException.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginInvalidInputException.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginInvalidInputException.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginInvalidInputException.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginInvalidInputException.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,46 @@
+/* $Id$
+ *
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+/**
+ * Thrown when an error occurs due to bad data in the file being parsed.
+ */
+public class PluginInvalidInputException extends PluginException {
+
+ /**
+ * @param cause underlying exception that caused this to be thrown
+ */
+ public PluginInvalidInputException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * @param msg describes the reason this exception is being thrown.
+ */
+ public PluginInvalidInputException(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 PluginInvalidInputException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginInvalidInputException.java
------------------------------------------------------------------------------
svn:keywords = Id
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginRuleManager.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginRuleManager.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginRuleManager.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginRuleManager.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,285 @@
+/* $Id$
+ *
+ * Copyright 2003-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.digester2.plugins;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.Comparator;
+
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.Action;
+import org.apache.commons.digester2.RuleManager;
+import org.apache.commons.digester2.AbstractRuleManager;
+import org.apache.commons.digester2.DigestionException;
+import org.apache.commons.digester2.InvalidRuleException;
+import org.apache.commons.logging.Log;
+
+/**
+ * A custom digester RuleManager which contains its own rules, but can also
+ * return rules from a "parent" RuleManager.
+ * <p>
+ * Plugged-in classes have custom parsing rules associated with them. These
+ * rules need to be added to the existing set of rules during the scope of
+ * the plugged-in class, and then discarded when the plugged-in class goes
+ * out of scope.
+ * <p>
+ * In order to implement this behaviour, the following occurs when a
+ * PluginCreateAction's begin method fires:
+ * <ul>
+ * <li>An instance of this class is created
+ * <li>Any custom rules associated with the plugged-in class are added to the
+ * new instance PluginRuleManager instance
+ * <li>The new PluginRuleManager instance is made the "current" RuleManager.
+ * </li>
+ * <p>
+ * As the SAXHandler continues parsing of the xml within the plugged-in class,
+ * any calls it makes to the current RuleManager cause the custom rules to be
+ * returned.
+ * <p>
+ * When the PluginCreateAction's end method fires, the previous RuleManager
+ * is restored, effectively discarding those custom rules that are no longer
+ * relevant.
+ * <p>
+ * Rather than implement RuleManager functionality directly, this class
+ * holds a reference to a "real" rulemanager, and just forwards any calls
+ * to that delegate. This avoids having to implement full RuleManager
+ * functionality here. More importantly, it allows an instance of this
+ * class to support various RuleManager matching behaviours, simply by having
+ * the delegate rulemanager be of the appropriate class.
+ */
+
+public class PluginRuleManager extends AbstractRuleManager {
+
+ /**
+ * The rulemanager implementation that holds rules defined before the
+ * PluginRuleManager was created. This object might be a PluginRuleManager
+ * itself, in which case it has a parentRuleManager, etc. Eventually the
+ * chain will lead back to the original rule manager associated with the
+ * SAXHandler.
+ */
+ private RuleManager parentRuleManager;
+
+ /**
+ * The rulemanager implementation that we are "enhancing" with plugins
+ * functionality, as per the Decorator pattern. This is never a
+ * PluginRuleManager, but rather an instance that implements whatever
+ * matching behaviour the plugged-in class wants for its custom rules.
+ */
+ private RuleManager delegateRuleManager;
+
+ /**
+ * The path below which this rulemanager object has responsibility.
+ * For paths shorter than or equal the mountpoint, the parent's
+ * match is called.
+ */
+ private String mountPoint;
+
+ // -------------------------------------------------------------
+ // Constructor
+ // -------------------------------------------------------------
+
+ /**
+ * Constructs an instance with the specified parent RuleManager.
+ * <p>
+ * One of these is created each time a PluginCreateAction's begin method
+ * fires, in order to manage the custom rules associated with whatever
+ * concrete plugin class the user has specified.
+ *
+ * @param parent must be non-null, and is expected to be the value returned
+ * by context.getRuleManager().
+ *
+ * @param delegate must be non-null, and is expected to be some new object
+ * which implements RuleManager, eg a DefaultRuleManager.
+ *
+ * @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 context.getMatchPath().
+ */
+ PluginRuleManager(
+ RuleManager parent,
+ RuleManager delegate,
+ String mountPoint)
+ throws PluginException {
+ this.parentRuleManager = parent;
+ this.delegateRuleManager = delegate;
+ this.mountPoint = mountPoint;
+ }
+
+ // ---------------------------------------------------------
+ // Properties
+ // ---------------------------------------------------------
+
+ /**
+ * Return the rulemanager that was current before this one took over.
+ */
+ public RuleManager getParent() {
+ return parentRuleManager;
+ }
+
+ // ---------------------------------------------------------
+ // AbstractRuleManager methods
+ // ---------------------------------------------------------
+
+ /**
+ * Always throws UnsupportedOperationException; there should never be
+ * any reason to copy one of these objects.
+ */
+ public RuleManager copy() {
+ // this method should never be called
+ throw new UnsupportedOperationException(
+ "PluginRuleManager.copy is not supported.");
+ }
+
+ /**
+ * Invokes the startParse method on any rules that have been added
+ * specifically to this RuleManager.
+ * <p>
+ * This method should be called after custom rules have been added to
+ * this object, so that the actions get the expected lifecycle called.
+ */
+ public void startParse(Context context) throws DigestionException {
+ delegateRuleManager.startParse(context);
+
+ // We deliberately don't call parent.startParse, as the actions within
+ // that rulemanager should already have had their startParse methods
+ // invoked.
+ }
+
+ /**
+ * Invokes the finishParse method on any rules that have been added
+ * specifically to this RuleManager.
+ * <p>
+ * This method should be called just before this instance is discarded,
+ * so that the actions get the expected lifecycle called. The endParse
+ * method is <i>not</i> invoked on the parent RuleManager, as the actions
+ * stored within it are still in use; their endParse methods will be
+ * called later.
+ */
+ public void finishParse(Context context) throws DigestionException {
+ delegateRuleManager.finishParse(context);
+
+ // We deliberately don't call parent.startParse, as the actions within
+ // that rulemanager should already have had their startParse methods
+ // invoked.
+ }
+
+ /** See {@link RuleManager#addFallbackAction}. */
+ public void addFallbackAction(Action action) {
+ delegateRuleManager.addFallbackAction(action);
+ }
+
+ /** See {@link RuleManager#addFallbackActions}. */
+ public void addFallbackActions(List actions) {
+ delegateRuleManager.addFallbackActions(actions);
+ }
+
+ /** See {@link RuleManager#addMandatoryAction}. */
+ public void addMandatoryAction(Action action) {
+ delegateRuleManager.addMandatoryAction(action);
+ }
+
+ /** See {@link RuleManager#addMandatoryActions}. */
+ public void addMandatoryActions(List actions) {
+ delegateRuleManager.addMandatoryActions(actions);
+ }
+
+ /** See {@link RuleManager#addNamespace}. */
+ public void addNamespace(String prefix, String uri) {
+ delegateRuleManager.addNamespace(prefix, uri);
+ }
+
+ /**
+ * Add a custom rule.
+ * <p>
+ * If the pattern starts with a forward-slash then the current mountpoint
+ * is automatically prepended to the pattern so that custom rules can add
+ * absolute patterns without caring where they are mounted within the
+ * input document.
+ * <p>
+ * If the pattern is null, then the pattern is set to the current mountpoint,
+ * so that actions can be triggered on the same element which caused the
+ * plugin class to be created, without needing to know the mountpoint
+ * from the code that adds the custom rule.
+ * <p>
+ * Note that this does hard-wire an assumption that the concrete
+ * RuleManager this instance is delegating to accepts the "canonical path"
+ * as a valid pattern prefix, and treats paths starting with a leading
+ * slash as absolute.
+ *
+ * See {@link RuleManager#addRule}.
+ */
+ public void addRule(String pattern, Action action)
+ throws InvalidRuleException {
+ if (pattern == null) {
+ pattern = mountPoint;
+ } else if (pattern.startsWith("/")) {
+ pattern = mountPoint + pattern;
+ }
+ delegateRuleManager.addRule(pattern, action);
+ }
+
+ /**
+ * This method always throws an exception. It is not obvious whether this
+ * method should return just the actions registered with it, or include
+ * the actions registered with the parent rulemanager too. And in any case
+ * it is not expected that this method will ever need to be invoked on a
+ * instance of this class, so it's safer to disallow this operation.
+ */
+ public List getActions() {
+ throw new UnsupportedOperationException(
+ "PluginRuleManager.getActions is not supported");
+ }
+
+ /**
+ * If the path specified is below the mount-point for this rulemanager,
+ * then only actions that were added to this rulemanager are returned,
+ * as the custom rules for a plugged-in class is expected to be
+ * "stand-alone".
+ * <p>
+ * In other words, once a plugin has been entered, only custom rules
+ * associated with that action are returned, even if the parent rulemanager
+ * has some matching rules. This includes fallback and mandatory actions.
+ * <p>
+ *
+ * @param path is a string of form
+ * <pre>/{namespace}elementName/{namespace}elementName"</pre>
+ * identifying the path from the root of the input document to the element
+ * for which the caller wants the set of matching Action objects. If an
+ * element has no namespace, then the {} part is omitted.
+ */
+ public List getMatchingActions(String path) throws DigestionException {
+ // As we don't have access to a context object here, we have to do
+ // the following which effectively disables logging. Damn, we need a
+ // better approach to logging...
+ Log log = LogUtils.getLogger(null);
+ boolean debug = log.isDebugEnabled();
+
+ if (debug) {
+ log.debug(
+ "Matching path [" + path +
+ "] on rulemanager object " + this.toString());
+ }
+
+ return delegateRuleManager.getMatchingActions(path);
+ }
+}
Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/PluginRuleManager.java
------------------------------------------------------------------------------
svn:keywords = Id
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org