rdonkin     2003/10/04 05:26:51

  Modified:    digester build.xml
  Added:       digester/src/java/org/apache/commons/digester/plugins
                        Declaration.java
  Log:
  Added plugins module. Submitted by Simon 
Kitching.src/java/org/apache/commons/digester/plugins/Declaration.java
  
  Revision  Changes    Path
  1.47      +13 -3     jakarta-commons/digester/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/digester/build.xml,v
  retrieving revision 1.46
  retrieving revision 1.47
  diff -u -r1.46 -r1.47
  --- build.xml 28 Sep 2003 09:41:29 -0000      1.46
  +++ build.xml 4 Oct 2003 12:26:51 -0000       1.47
  @@ -263,7 +263,8 @@
                                  test.node,
                                  test.factory,
                                  test.regex,
  -                               test.wdrules
  +                               test.wdrules,
  +                               test.plugins
                                 "
      description="Run all unit test cases">
     </target>
  @@ -412,5 +413,14 @@
         <classpath refid="test.classpath"/>
       </java>
     </target>
  - 
  +
  +  <target name="test.plugins" depends="compile.tests"
  +          description="Run Plugins tests ...">
  +    <echo message="Running Plugins tests ..."/>
  +    <java classname="${test.runner}" fork="yes"
  +        failonerror="${test.failonerror}">
  +      <arg value="org.apache.commons.digester.plugins.TestAll"/>
  +      <classpath refid="test.classpath"/>
  +    </java>
  +  </target> 
   </project>
  
  
  
  1.1                  
jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/Declaration.java
  
  Index: Declaration.java
  ===================================================================
  /*
   *  ====================================================================
   *
   *  The Apache Software License, Version 1.1
   *
   *  Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
   *  reserved.
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *  1. Redistributions of source code must retain the above copyright
   *  notice, this list of conditions and the following disclaimer.
   *
   *  2. Redistributions in binary form must reproduce the above copyright
   *  notice, this list of conditions and the following disclaimer in
   *  the documentation and/or other materials provided with the
   *  distribution.
   *
   *  3. The end-user documentation included with the redistribution, if
   *  any, must include the following acknowlegement:
   *  "This product includes software developed by the
   *  Apache Software Foundation (http://www.apache.org/)."
   *  Alternately, this acknowlegement may appear in the software itself,
   *  if and wherever such third-party acknowlegements normally appear.
   *
   *  4. The names "The Jakarta Project", "Commons", and "Apache Software
   *  Foundation" must not be used to endorse or promote products derived
   *  from this software without prior written permission. For written
   *  permission, please contact [EMAIL PROTECTED]
   *
   *  5. Products derived from this software may not be called "Apache"
   *  nor may "Apache" appear in their names without prior written
   *  permission of the Apache Group.
   *
   *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   *  DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   *  ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   *  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   *  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   *  SUCH DAMAGE.
   *  ====================================================================
   *
   *  This software consists of voluntary contributions made by many
   *  individuals on behalf of the Apache Software Foundation.  For more
   *  information on the Apache Software Foundation, please see
   *  <http://www.apache.org/>.
   *
   */
  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 org.apache.commons.beanutils.MethodUtils;
  import org.apache.commons.digester.Digester;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  
  /**
   * Simple structure to store the set of attributes that can be present on 
   * a plugin declaration.
   * 
   * @author Simon Kitching
   */
  public class Declaration {
      private static Log log = LogFactory.getLog(Declaration.class);
  
      /** 
       * 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_;
  
      /** The name of the class of the object to be instantiated. */
      private String pluginClassName_;
      
      /** 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] #setAutoSetProperties}. */
      private boolean autoSetProperties_ = true;
  
      /** See [EMAIL PROTECTED] #init}. */
      private boolean initialised_ = false;
      
      //---------------------- constructors ----------------------------------
  
      /**
       * Constructor.
       */
      public Declaration(Class pluginClass) {
          pluginClass_ = pluginClass;
          pluginClassName_ = pluginClass_.getName();
      }
      
      /**
       * Constructor.
       */
      public Declaration(String pluginClassName) 
      throws ClassNotFoundException {
          pluginClassName_ = pluginClassName;
      }
      
      //---------------------- properties -----------------------------------
  
      /** 
       * The id of the object defined in a plugin declaration.
       * For plugins declared "in-line", the id is null.
       */
      public void setId(String id) {
          id_ = id;
      }
      
      /** 
       * Sets the name of a method which defines custom rules. May be null. 
       */
      public void setRuleMethod(String ruleMethodName) {
          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) {
          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) {
          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) {
          ruleFile_ = ruleFile;
      }
      
      /** See [EMAIL PROTECTED] #autoSetProperties}. */
      public void setAutoSetProperties(boolean autoSetProperties) {
          autoSetProperties_ = autoSetProperties;
      }
      
      /**
       * Return the id associated with this declaration.
       * 
       * @return The id value. May be null.
       */
      public String getId() {
          return id_;
      }
  
      /**
       * Return plugin class associated with this declaration.
       * 
       * @return The pluginClass.
       */
      public Class getPluginClass() {
          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 {
          log.debug("init being called!");
          
          if (initialised_) {
              throw new PluginAssertionError("Init called multiple times.");
          }
  
          if ((pluginClass_ == null) && (pluginClassName_ != null)) {
              try {
                  // load the plugin class object
                  pluginClass_ = 
                      digester.getClassLoader().loadClass(pluginClassName_);
              }
              catch(ClassNotFoundException cnfe) {
                  throw new PluginWrappedException(
                      "Unable to load class " + pluginClassName_, cnfe);
              }
          }
          initialised_ = true;        
      }
      
      /**
       * 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 {
          log.debug("configure being called!");
          
          if (!initialised_) {
              throw new PluginAssertionError("Not initialised.");
          }
          
          // 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 (log.isDebugEnabled()) {
                  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 (log.isDebugEnabled()) {
                  log.debug("adding autoset for pattern [" + pattern + "]");
              }
              digester.addSetProperties(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 PluginAssertionError(
                  "Load from stream not yet supported.");
          }
          finally {
              try {
                  is.close();
              }
              catch(IOException ioe) {
                  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;
  
          // all significant fields match; these declarations are identical.
          return true;
      }
      
      /**
       * Returns true if the two objects are both null or both equal.
       */
      private static boolean different(Object o1, Object o2) {
          if (o1 == null) {
              return o1 == null;
          }
          
          return o1.equals(o2);
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to