Save This Page
Home » commons-digester-1.8-src » org.apache.commons » digester » [javadoc | source]
    1   /* $Id: SetNextRule.java 471661 2006-11-06 08:09:25Z skitching $
    2    *
    3    * Licensed to the Apache Software Foundation (ASF) under one or more
    4    * contributor license agreements.  See the NOTICE file distributed with
    5    * this work for additional information regarding copyright ownership.
    6    * The ASF licenses this file to You under the Apache License, Version 2.0
    7    * (the "License"); you may not use this file except in compliance with
    8    * the License.  You may obtain a copy of the License at
    9    * 
   10    *      http://www.apache.org/licenses/LICENSE-2.0
   11    * 
   12    * Unless required by applicable law or agreed to in writing, software
   13    * distributed under the License is distributed on an "AS IS" BASIS,
   14    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15    * See the License for the specific language governing permissions and
   16    * limitations under the License.
   17    */ 
   18   
   19   
   20   package org.apache.commons.digester;
   21   
   22   
   23   import org.apache.commons.beanutils.MethodUtils;
   24   
   25   
   26   /**
   27    * <p>Rule implementation that calls a method on the (top-1) (parent)
   28    * object, passing the top object (child) as an argument.  It is
   29    * commonly used to establish parent-child relationships.</p>
   30    *
   31    * <p>This rule now supports more flexible method matching by default.
   32    * It is possible that this may break (some) code 
   33    * written against release 1.1.1 or earlier.
   34    * See {@link #isExactMatch()} for more details.</p> 
   35    *
   36    * <p>Note that while CallMethodRule uses commons-beanutils' data-conversion
   37    * functionality (ConvertUtils class) to convert parameter values into
   38    * the appropriate type for the parameter to the called method, this
   39    * rule does not. Needing to use ConvertUtils functionality when building
   40    * parent-child relationships is expected to be very rare; however if you 
   41    * do need this then instead of using this rule, create a CallMethodRule
   42    * specifying targetOffset of 1 in the constructor.</p>
   43    */
   44   
   45   public class SetNextRule extends Rule {
   46   
   47   
   48       // ----------------------------------------------------------- Constructors
   49   
   50   
   51       /**
   52        * Construct a "set next" rule with the specified method name.  The
   53        * method's argument type is assumed to be the class of the
   54        * child object.
   55        *
   56        * @param digester The associated Digester
   57        * @param methodName Method name of the parent method to call
   58        *
   59        * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
   60        * Use {@link #SetNextRule(String methodName)} instead.
   61        */
   62       public SetNextRule(Digester digester, String methodName) {
   63   
   64           this(methodName);
   65   
   66       }
   67   
   68   
   69       /**
   70        * Construct a "set next" rule with the specified method name.
   71        *
   72        * @param digester The associated Digester
   73        * @param methodName Method name of the parent method to call
   74        * @param paramType Java class of the parent method's argument
   75        *  (if you wish to use a primitive type, specify the corresonding
   76        *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
   77        *  for a <code>boolean</code> parameter)
   78        *
   79        * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
   80        * Use {@link #SetNextRule(String methodName,String paramType)} instead.
   81        */
   82       public SetNextRule(Digester digester, String methodName,
   83                          String paramType) {
   84   
   85           this(methodName, paramType);
   86   
   87       }
   88   
   89       /**
   90        * Construct a "set next" rule with the specified method name.  The
   91        * method's argument type is assumed to be the class of the
   92        * child object.
   93        *
   94        * @param methodName Method name of the parent method to call
   95        */
   96       public SetNextRule(String methodName) {
   97   
   98           this(methodName, null);
   99   
  100       }
  101   
  102   
  103       /**
  104        * Construct a "set next" rule with the specified method name.
  105        *
  106        * @param methodName Method name of the parent method to call
  107        * @param paramType Java class of the parent method's argument
  108        *  (if you wish to use a primitive type, specify the corresonding
  109        *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
  110        *  for a <code>boolean</code> parameter)
  111        */
  112       public SetNextRule(String methodName,
  113                          String paramType) {
  114   
  115           this.methodName = methodName;
  116           this.paramType = paramType;
  117   
  118       }
  119   
  120   
  121       // ----------------------------------------------------- Instance Variables
  122   
  123   
  124       /**
  125        * The method name to call on the parent object.
  126        */
  127       protected String methodName = null;
  128   
  129   
  130       /**
  131        * The Java class name of the parameter type expected by the method.
  132        */
  133       protected String paramType = null;
  134   
  135       /**
  136        * Should we use exact matching. Default is no.
  137        */
  138       protected boolean useExactMatch = false;
  139   
  140       // --------------------------------------------------------- Public Methods
  141   
  142   
  143       /**
  144        * <p>Is exact matching being used.</p>
  145        *
  146        * <p>This rule uses <code>org.apache.commons.beanutils.MethodUtils</code> 
  147        * to introspect the relevent objects so that the right method can be called.
  148        * Originally, <code>MethodUtils.invokeExactMethod</code> was used.
  149        * This matches methods very strictly 
  150        * and so may not find a matching method when one exists.
  151        * This is still the behaviour when exact matching is enabled.</p>
  152        *
  153        * <p>When exact matching is disabled, <code>MethodUtils.invokeMethod</code> is used.
  154        * This method finds more methods but is less precise when there are several methods 
  155        * with correct signatures.
  156        * So, if you want to choose an exact signature you might need to enable this property.</p>
  157        *
  158        * <p>The default setting is to disable exact matches.</p>
  159        *
  160        * @return true iff exact matching is enabled
  161        * @since Digester Release 1.1.1
  162        */
  163       public boolean isExactMatch() {
  164       
  165           return useExactMatch;
  166       }
  167       
  168       /**
  169        * <p>Set whether exact matching is enabled.</p>
  170        *
  171        * <p>See {@link #isExactMatch()}.</p>
  172        *
  173        * @param useExactMatch should this rule use exact method matching
  174        * @since Digester Release 1.1.1
  175        */    
  176       public void setExactMatch(boolean useExactMatch) {
  177   
  178           this.useExactMatch = useExactMatch;
  179       }
  180   
  181       /**
  182        * Process the end of this element.
  183        */
  184       public void end() throws Exception {
  185   
  186           // Identify the objects to be used
  187           Object child = digester.peek(0);
  188           Object parent = digester.peek(1);
  189           if (digester.log.isDebugEnabled()) {
  190               if (parent == null) {
  191                   digester.log.debug("[SetNextRule]{" + digester.match +
  192                           "} Call [NULL PARENT]." +
  193                           methodName + "(" + child + ")");
  194               } else {
  195                   digester.log.debug("[SetNextRule]{" + digester.match +
  196                           "} Call " + parent.getClass().getName() + "." +
  197                           methodName + "(" + child + ")");
  198               }
  199           }
  200   
  201           // Call the specified method
  202           Class paramTypes[] = new Class[1];
  203           if (paramType != null) {
  204               paramTypes[0] =
  205                       digester.getClassLoader().loadClass(paramType);
  206           } else {
  207               paramTypes[0] = child.getClass();
  208           }
  209           
  210           if (useExactMatch) {
  211           
  212               MethodUtils.invokeExactMethod(parent, methodName,
  213                   new Object[]{ child }, paramTypes);
  214                   
  215           } else {
  216           
  217               MethodUtils.invokeMethod(parent, methodName,
  218                   new Object[]{ child }, paramTypes);
  219           
  220           }
  221       }
  222   
  223   
  224       /**
  225        * Render a printable version of this Rule.
  226        */
  227       public String toString() {
  228   
  229           StringBuffer sb = new StringBuffer("SetNextRule[");
  230           sb.append("methodName=");
  231           sb.append(methodName);
  232           sb.append(", paramType=");
  233           sb.append(paramType);
  234           sb.append("]");
  235           return (sb.toString());
  236   
  237       }
  238   
  239   
  240   }

Save This Page
Home » commons-digester-1.8-src » org.apache.commons » digester » [javadoc | source]