001: /* $Id: SetRootRule.java 467222 2006-10-24 03:17:11Z markt $
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: package org.apache.tomcat.util.digester;
020:
021: import org.apache.tomcat.util.IntrospectionUtils;
022:
023: /**
024: * <p>Rule implementation that calls a method on the root object on the stack,
025: * passing the top object (child) as an argument.
026: * It is important to remember that this rule acts on <code>end</code>.</p>
027: *
028: * <p>This rule now supports more flexible method matching by default.
029: * It is possible that this may break (some) code
030: * written against release 1.1.1 or earlier.
031: * See {@link #isExactMatch()} for more details.</p>
032: */
033:
034: public class SetRootRule extends Rule {
035:
036: // ----------------------------------------------------------- Constructors
037:
038: /**
039: * Construct a "set root" rule with the specified method name. The
040: * method's argument type is assumed to be the class of the
041: * child object.
042: *
043: * @param digester The associated Digester
044: * @param methodName Method name of the parent method to call
045: *
046: * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
047: * Use {@link #SetRootRule(String methodName)} instead.
048: */
049: public SetRootRule(Digester digester, String methodName) {
050:
051: this (methodName);
052:
053: }
054:
055: /**
056: * Construct a "set root" rule with the specified method name.
057: *
058: * @param digester The associated Digester
059: * @param methodName Method name of the parent method to call
060: * @param paramType Java class of the parent method's argument
061: * (if you wish to use a primitive type, specify the corresonding
062: * Java wrapper class instead, such as <code>java.lang.Boolean</code>
063: * for a <code>boolean</code> parameter)
064: *
065: * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
066: * Use {@link #SetRootRule(String methodName,String paramType)} instead.
067: */
068: public SetRootRule(Digester digester, String methodName,
069: String paramType) {
070:
071: this (methodName, paramType);
072:
073: }
074:
075: /**
076: * Construct a "set root" rule with the specified method name. The
077: * method's argument type is assumed to be the class of the
078: * child object.
079: *
080: * @param methodName Method name of the parent method to call
081: */
082: public SetRootRule(String methodName) {
083:
084: this (methodName, null);
085:
086: }
087:
088: /**
089: * Construct a "set root" rule with the specified method name.
090: *
091: * @param methodName Method name of the parent method to call
092: * @param paramType Java class of the parent method's argument
093: * (if you wish to use a primitive type, specify the corresonding
094: * Java wrapper class instead, such as <code>java.lang.Boolean</code>
095: * for a <code>boolean</code> parameter)
096: */
097: public SetRootRule(String methodName, String paramType) {
098:
099: this .methodName = methodName;
100: this .paramType = paramType;
101:
102: }
103:
104: // ----------------------------------------------------- Instance Variables
105:
106: /**
107: * The method name to call on the parent object.
108: */
109: protected String methodName = null;
110:
111: /**
112: * The Java class name of the parameter type expected by the method.
113: */
114: protected String paramType = null;
115:
116: /**
117: * Should we use exact matching. Default is no.
118: */
119: protected boolean useExactMatch = false;
120:
121: // --------------------------------------------------------- Public Methods
122:
123: /**
124: * <p>Is exact matching being used.</p>
125: *
126: * <p>This rule uses <code>org.apache.commons.beanutils.MethodUtils</code>
127: * to introspect the relevent objects so that the right method can be called.
128: * Originally, <code>MethodUtils.invokeExactMethod</code> was used.
129: * This matches methods very strictly
130: * and so may not find a matching method when one exists.
131: * This is still the behaviour when exact matching is enabled.</p>
132: *
133: * <p>When exact matching is disabled, <code>MethodUtils.invokeMethod</code> is used.
134: * This method finds more methods but is less precise when there are several methods
135: * with correct signatures.
136: * So, if you want to choose an exact signature you might need to enable this property.</p>
137: *
138: * <p>The default setting is to disable exact matches.</p>
139: *
140: * @return true iff exact matching is enabled
141: * @since Digester Release 1.1.1
142: */
143: public boolean isExactMatch() {
144:
145: return useExactMatch;
146: }
147:
148: /**
149: * <p>Set whether exact matching is enabled.</p>
150: *
151: * <p>See {@link #isExactMatch()}.</p>
152: *
153: * @param useExactMatch should this rule use exact method matching
154: * @since Digester Release 1.1.1
155: */
156: public void setExactMatch(boolean useExactMatch) {
157:
158: this .useExactMatch = useExactMatch;
159: }
160:
161: /**
162: * Process the end of this element.
163: */
164: public void end() throws Exception {
165:
166: // Identify the objects to be used
167: Object child = digester.peek(0);
168: Object parent = digester.root;
169: if (digester.log.isDebugEnabled()) {
170: if (parent == null) {
171: digester.log.debug("[SetRootRule]{" + digester.match
172: + "} Call [NULL ROOT]." + methodName + "("
173: + child + ")");
174: } else {
175: digester.log.debug("[SetRootRule]{" + digester.match
176: + "} Call " + parent.getClass().getName() + "."
177: + methodName + "(" + child + ")");
178: }
179: }
180:
181: // Call the specified method
182: IntrospectionUtils.callMethod1(parent, methodName, child,
183: paramType, digester.getClassLoader());
184:
185: }
186:
187: /**
188: * Render a printable version of this Rule.
189: */
190: public String toString() {
191:
192: StringBuffer sb = new StringBuffer("SetRootRule[");
193: sb.append("methodName=");
194: sb.append(methodName);
195: sb.append(", paramType=");
196: sb.append(paramType);
197: sb.append("]");
198: return (sb.toString());
199:
200: }
201:
202: }
|