001 /* $Id: SetTopRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 020 package org.apache.commons.digester; 021 022 023 import org.apache.commons.beanutils.MethodUtils; 024 025 026 /** 027 * <p>Rule implementation that calls a "set parent" method on the top (child) 028 * object, passing the (top-1) (parent) object as an argument.</p> 029 * 030 * <p>This rule now supports more flexible method matching by default. 031 * It is possible that this may break (some) code 032 * written against release 1.1.1 or earlier. 033 * See {@link #isExactMatch()} for more details.</p> 034 */ 035 036 public class SetTopRule extends Rule { 037 038 039 // ----------------------------------------------------------- Constructors 040 041 042 /** 043 * Construct a "set parent" rule with the specified method name. The 044 * "set parent" method's argument type is assumed to be the class of the 045 * parent object. 046 * 047 * @param digester The associated Digester 048 * @param methodName Method name of the "set parent" method to call 049 * 050 * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 051 * Use {@link #SetTopRule(String methodName)} instead. 052 */ 053 @Deprecated 054 public SetTopRule(Digester digester, String methodName) { 055 056 this(methodName); 057 058 } 059 060 061 /** 062 * Construct a "set parent" rule with the specified method name. 063 * 064 * @param digester The associated Digester 065 * @param methodName Method name of the "set parent" method to call 066 * @param paramType Java class of the "set parent" method's argument 067 * (if you wish to use a primitive type, specify the corresonding 068 * Java wrapper class instead, such as <code>java.lang.Boolean</code> 069 * for a <code>boolean</code> parameter) 070 * 071 * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 072 * Use {@link #SetTopRule(String methodName, String paramType)} instead. 073 */ 074 @Deprecated 075 public SetTopRule(Digester digester, String methodName, 076 String paramType) { 077 078 this(methodName, paramType); 079 080 } 081 082 /** 083 * Construct a "set parent" rule with the specified method name. The 084 * "set parent" method's argument type is assumed to be the class of the 085 * parent object. 086 * 087 * @param methodName Method name of the "set parent" method to call 088 */ 089 public SetTopRule(String methodName) { 090 091 this(methodName, null); 092 093 } 094 095 096 /** 097 * Construct a "set parent" rule with the specified method name. 098 * 099 * @param methodName Method name of the "set parent" method to call 100 * @param paramType Java class of the "set parent" method's argument 101 * (if you wish to use a primitive type, specify the corresonding 102 * Java wrapper class instead, such as <code>java.lang.Boolean</code> 103 * for a <code>boolean</code> parameter) 104 */ 105 public SetTopRule(String methodName, 106 String paramType) { 107 108 this.methodName = methodName; 109 this.paramType = paramType; 110 111 } 112 113 114 // ----------------------------------------------------- Instance Variables 115 116 117 /** 118 * The method name to call on the child object. 119 */ 120 protected String methodName = null; 121 122 123 /** 124 * The Java class name of the parameter type expected by the method. 125 */ 126 protected String paramType = null; 127 128 /** 129 * Should we use exact matching. Default is no. 130 */ 131 protected boolean useExactMatch = false; 132 133 134 // --------------------------------------------------------- Public Methods 135 136 /** 137 * <p>Is exact matching being used.</p> 138 * 139 * <p>This rule uses <code>org.apache.commons.beanutils.MethodUtils</code> 140 * to introspect the relevent objects so that the right method can be called. 141 * Originally, <code>MethodUtils.invokeExactMethod</code> was used. 142 * This matches methods very strictly 143 * and so may not find a matching method when one exists. 144 * This is still the behaviour when exact matching is enabled.</p> 145 * 146 * <p>When exact matching is disabled, <code>MethodUtils.invokeMethod</code> is used. 147 * This method finds more methods but is less precise when there are several methods 148 * with correct signatures. 149 * So, if you want to choose an exact signature you might need to enable this property.</p> 150 * 151 * <p>The default setting is to disable exact matches.</p> 152 * 153 * @return true iff exact matching is enabled 154 * @since Digester Release 1.1.1 155 */ 156 public boolean isExactMatch() { 157 158 return useExactMatch; 159 } 160 161 /** 162 * <p>Set whether exact matching is enabled.</p> 163 * 164 * <p>See {@link #isExactMatch()}.</p> 165 * 166 * @param useExactMatch should this rule use exact method matching 167 * @since Digester Release 1.1.1 168 */ 169 public void setExactMatch(boolean useExactMatch) { 170 171 this.useExactMatch = useExactMatch; 172 } 173 174 /** 175 * Process the end of this element. 176 */ 177 @Override 178 public void end() throws Exception { 179 180 // Identify the objects to be used 181 Object child = digester.peek(0); 182 Object parent = digester.peek(1); 183 184 if (digester.log.isDebugEnabled()) { 185 if (child == null) { 186 digester.log.debug("[SetTopRule]{" + digester.match + 187 "} Call [NULL CHILD]." + 188 methodName + "(" + parent + ")"); 189 } else { 190 digester.log.debug("[SetTopRule]{" + digester.match + 191 "} Call " + child.getClass().getName() + "." + 192 methodName + "(" + parent + ")"); 193 } 194 } 195 196 // Call the specified method 197 Class<?> paramTypes[] = new Class<?>[1]; 198 if (paramType != null) { 199 paramTypes[0] = 200 digester.getClassLoader().loadClass(paramType); 201 } else { 202 paramTypes[0] = parent.getClass(); 203 } 204 205 if (useExactMatch) { 206 207 MethodUtils.invokeExactMethod(child, methodName, 208 new Object[]{ parent }, paramTypes); 209 210 } else { 211 212 MethodUtils.invokeMethod(child, methodName, 213 new Object[]{ parent }, paramTypes); 214 215 } 216 } 217 218 219 /** 220 * Render a printable version of this Rule. 221 */ 222 @Override 223 public String toString() { 224 225 StringBuffer sb = new StringBuffer("SetTopRule["); 226 sb.append("methodName="); 227 sb.append(methodName); 228 sb.append(", paramType="); 229 sb.append(paramType); 230 sb.append("]"); 231 return (sb.toString()); 232 233 } 234 235 236 }