skitching 2004/03/27 21:51:43
Modified: digester/src/java/org/apache/commons/digester/plugins Tag:
DIGESTER_PLUGIN_REFACTORING_BRANCH Declaration.java
Log:
* store declaration attributes provided by the user as a Properties object
rather than explicit Object attributes. This allows the set of
attributes to be open-ended, and removes use of hard-wired English
attribute names.
* use new RuleFinder/RuleLoader interfaces to find "pluggable" algorithms
for finding/loading dynamic plugin rules rather than hard-coding the
algorithms in this class.
* move rule finding/loading algorithms to separate classes in the
strategies subpackage.
Revision Changes Path
No revision
No revision
1.11.2.1 +87 -271
jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/Declaration.java
Index: Declaration.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/Declaration.java,v
retrieving revision 1.11
retrieving revision 1.11.2.1
diff -u -r1.11 -r1.11.2.1
--- Declaration.java 29 Feb 2004 02:22:15 -0000 1.11
+++ Declaration.java 28 Mar 2004 05:51:43 -0000 1.11.2.1
@@ -15,27 +15,19 @@
*/
package org.apache.commons.digester.plugins;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
import java.io.IOException;
-import java.lang.reflect.Method;
+import java.util.Properties;
+import java.util.List;
-import org.apache.commons.beanutils.MethodUtils;
-import org.apache.commons.digester.Digester;
import org.apache.commons.logging.Log;
+import org.apache.commons.digester.Digester;
/**
- * Simple structure to store the set of attributes that can be present on
- * a plugin declaration.
+ * 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.
*/
public class Declaration {
-
- /**
- * The name of the method looked for on the plugin class and any
- * specific rule class.
- */
- public final static String DFLT_RULE_METHOD_NAME = "addRules";
/** The class of the object to be instantiated. */
private Class pluginClass;
@@ -46,89 +38,66 @@
/** See [EMAIL PROTECTED] #setId}. */
private String id;
- /** See [EMAIL PROTECTED] #setRuleMethod}. */
- private String ruleMethodName = DFLT_RULE_METHOD_NAME;
-
- /** See [EMAIL PROTECTED] #setRuleClass}. */
- private Class ruleClass;
-
- /** See [EMAIL PROTECTED] #setRuleResource}. */
- private String ruleResource;
-
- /** See [EMAIL PROTECTED] #setRuleFile}. */
- private File ruleFile;
+ /** See [EMAIL PROTECTED] #setProperties}. */
+ private Properties properties = new Properties();
- /** See [EMAIL PROTECTED] #setAutoSetProperties}. */
- private boolean autoSetProperties = true;
-
/** See [EMAIL PROTECTED] #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();
}
/**
- * Constructor.
+ * 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(String pluginClassName) {
- this.pluginClassName = pluginClassName;
+ public Declaration(Class pluginClass, RuleLoader ruleLoader) {
+ this.pluginClass = pluginClass;
+ this.pluginClassName = pluginClass.getName();
+ this.ruleLoader = ruleLoader;
}
//---------------------- properties -----------------------------------
/**
- * The id of the object defined in a plugin declaration.
+ * 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;
}
- /**
- * Sets the name of a method which defines custom rules. May be null.
- */
- public void setRuleMethod(String ruleMethodName) {
- this.ruleMethodName = ruleMethodName;
- }
-
- /**
- * The name of a class containing a method which defines custom rules
- * for the plugin class. May be null.
- */
- public void setRuleClass(Class ruleClass) {
- this.ruleClass = ruleClass;
- }
-
- /**
- * The name of a resource file in the classpath containg xmlrules
- * specifications of custom rules for the plugin class. May be null.
- */
- public void setRuleResource(String ruleResource) {
- this.ruleResource = ruleResource;
- }
-
- /**
- * The name of a file containg xmlrules specifications of custom rules
- * for the plugin class. May be null.
- */
- public void setRuleFile(File ruleFile) {
- this.ruleFile = ruleFile;
- }
-
- /** See [EMAIL PROTECTED] #autoSetProperties}. */
- public void setAutoSetProperties(boolean autoSetProperties) {
- this.autoSetProperties = autoSetProperties;
- }
-
/**
- * Return the id associated with this declaration.
+ * Return the id associated with this declaration. For plugins
+ * declared "inline", null will be returned.
*
* @return The id value. May be null.
*/
@@ -136,6 +105,23 @@
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.
*
@@ -145,36 +131,13 @@
return pluginClass;
}
- /**
- * return class which specifies custom rules for this plugin.
- *
- * @return The ruleClass value. May be null.
- */
- public Class getRuleClass() {
- return ruleClass;
- }
-
- /**
- * Indicates whether plugins which do <i>not</i> implement custom rules
- * should have a SetProperties rule automatically associated with the
- * parent tag. In almost all cases this is desirable, so autoSetProperties
- * defaults to true. If for some reason you are plugging in a class
- * without custom rules and you do not want xml attributes to be mapped
- * to bean properties, you can pass <i>false</i> here to disable this.
- *
- * @return true if SetPropertiesRule is automatically applied.
- */
- public boolean autoSetProperties() {
- return autoSetProperties;
- }
-
//---------------------- methods -----------------------------------
/**
* Must be called exactly once, and must be called before any call
* to the configure method.
*/
- public void init(Digester digester) throws PluginWrappedException {
+ public void init(Digester digester, PluginManager pm) throws PluginException {
Log log = digester.getLogger();
boolean debug = log.isDebugEnabled();
if (debug) {
@@ -191,10 +154,35 @@
pluginClass =
digester.getClassLoader().loadClass(pluginClassName);
} catch(ClassNotFoundException cnfe) {
- throw new PluginWrappedException(
+ 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;
}
@@ -202,49 +190,13 @@
* Attempt to load custom rules for the target class at the specified
* pattern.
* <p>
- * <ol>
- * <li>If there is an explicit File, load from that file.</li>
- * <li>If there is an explicit Resource, load from that resource.</li>
- * <li>If there is an explicit RuleClass, load from that class.</li>
- * <li>If there is an explicit RuleMethod, load from that method.</li>
- * <li>If there is a default method, load from that method.</li>
- * <li>If there is a default RuleInfo class, load from that class.</li>
- * <li>If there is a default resource, load from that resource.</li>
- * </ol>
- * <p>
- * When loading from a File or Resource (a file in the classpath), the
- * contents of the file are expected to be xml in xmlrules format.
- * <p>
- * When loading from a RuleClass, that class is expected to have a
- * method with the signature <code>public static void addRules(Digester,
- * String)</code>.
- * <p>
- * When loading from a specified Method on the plugin class, that method
- * is expected to have signature <code> public static void xxx(Digester,
- * String)</code> where xxx is the specified method name.
- * <p>
- * When loading from the default method on the plugin class, the method
- * is expected to have signature <code>public static void addRules(Digester,
- * String)</code>.
- * <p>
- * When looking for a default RuleInfo class, the plugin class name has
- * the suffix "RuleInfo" applied to it. If there exists a class of that
- * name, then that class is expected to have an addRules method on it.
- * <p>
- * When looking for a default resource file, the plugin class name has
- * the suffix "RuleInfo.xml" applied to it. If there exists a resource
- * file of that name, then that file is expected to contain xmlrules
- * format rules.
- * <p>
- * The first source of rules found is used, and searching stops.
- * <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.
*/
public void configure(Digester digester, String pattern)
- throws PluginWrappedException {
+ throws PluginException {
Log log = digester.getLogger();
boolean debug = log.isDebugEnabled();
if (debug) {
@@ -254,160 +206,24 @@
if (!initialized) {
throw new PluginAssertionFailure("Not initialized.");
}
-
- // load from explicit file
- if (ruleFile != null) {
- InputStream is = null;
- try {
- is = new FileInputStream(ruleFile);
- } catch(IOException ioe) {
- throw new PluginWrappedException(
- "Unable to process file [" + ruleFile + "]", ioe);
- }
- loadRulesFromStream(is, digester, pattern);
- return;
- }
-
- // load from explicit resource in classpath
- if (ruleResource != null) {
- InputStream is =
- pluginClass.getClassLoader().getResourceAsStream(
- ruleResource);
- if (is != null) {
- loadRulesFromStream(is, digester, pattern);
- return;
- }
- }
-
- // load via method on explicit Rule Class
- if (ruleClass != null) {
- loadRulesFromClass(ruleClass, digester, pattern);
- return;
- }
-
- // load via method on plugin class
- {
- Class[] paramSpec = { Digester.class, String.class };
- Method ruleMethod = MethodUtils.getAccessibleMethod(
- pluginClass, ruleMethodName, paramSpec);
- if (ruleMethod != null)
- {
- try {
- Object[] params = {digester, pattern};
- Object none = ruleMethod.invoke(null, params);
- } catch (Exception e) {
- throw new PluginWrappedException(
- "Unable to configure class [" + pluginClass + "]" +
- " using method [" + ruleMethodName + "]", e);
- }
- return;
- }
- }
-
- // look for rule class
- {
- if (debug) {
- log.debug("plugin class type:" + pluginClass.getName());
- }
- String ruleClassName = pluginClass.getName() + "RuleInfo";
-
- Class ruleClass;
- try {
- ruleClass = digester.getClassLoader().loadClass(ruleClassName);
- } catch(ClassNotFoundException cnfe) {
- ruleClass = null;
- }
- if (ruleClass != null) {
- loadRulesFromClass(ruleClass, digester, pattern);
- return;
- }
- }
-
- // look for resource
- {
- String resourceName =
- pluginClass.getClass().getName().replace('.', '/') +
- "RuleInfo.xml";
- InputStream is =
- pluginClass.getClassLoader().getResourceAsStream(
- resourceName);
- if (is != null) {
- loadRulesFromStream(is, digester, pattern);
- return;
- }
- }
-
- // try autoSetProperties
- if (autoSetProperties) {
- if (debug) {
- log.debug("adding autoset for pattern [" + pattern + "]");
- }
- digester.addSetProperties(pattern);
+ if (ruleLoader != null) {
+ ruleLoader.addRules(digester, pattern);
}
}
/**
- * Load custom rules from a specified stream of xml data.
- */
- private void loadRulesFromStream(InputStream is, Digester digester,
- String pattern)
- throws PluginWrappedException {
- try
- {
- throw new PluginAssertionFailure(
- "Load from stream not yet supported.");
- }
- finally {
- try {
- is.close();
- } catch(IOException ioe) {
- Log log = digester.getLogger();
- log.warn("Unable to close stream after reading rules", ioe);
- }
- }
- }
-
- /**
- * Load custom rules from a specified class.
- */
- private void loadRulesFromClass(Class ruleClass, Digester digester,
- String pattern)
- throws PluginWrappedException {
- Class[] paramSpec = { Digester.class, String.class };
- Method ruleMethod = MethodUtils.getAccessibleMethod(
- ruleClass, ruleMethodName, paramSpec);
- if (ruleMethod == null) {
- throw new PluginWrappedException(
- "rule class specified, but rules method not found on it.");
- }
- try {
- Object[] params = {digester, pattern};
- Object none = ruleMethod.invoke(null, params);
- } catch (Exception e) {
- throw new PluginWrappedException(
- "Unable to configure class [" + pluginClass + "]" +
- " using rule class [" + ruleClass + "]" +
- " method [" + ruleMethodName + "]", e);
- }
- }
-
- /**
* Returns true if the declarations are equivalent. Perhaps this would be
* better as overriding equals, but then I should really override hash as
* well and I can't be bothered.
- *
+ *
* @param d the Declaration object to be compared to this object.
* @return true if the specified object has the same options as this one.
*/
public boolean isEquivalent(Declaration d) {
if (different(id, d.id)) return false;
if (pluginClass != d.pluginClass) return false;
- if (different(ruleMethodName, d.ruleMethodName)) return false;
- if (ruleClass != d.ruleClass) return false;
- if (different(ruleResource, d.ruleResource)) return false;
- if (different(ruleFile, d.ruleFile)) return false;
- if (autoSetProperties != d.autoSetProperties) return false;
+ if (!properties.equals(d.properties)) return false;
// all significant fields match; these declarations are identical.
return true;
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]