Source code: org/apache/hivemind/schema/rules/InvokeParentRule.java
1 // Copyright 2004, 2005 The Apache Software Foundation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package org.apache.hivemind.schema.rules;
16
17 import java.lang.reflect.Method;
18
19 import org.apache.hivemind.ApplicationRuntimeException;
20 import org.apache.hivemind.Element;
21 import org.apache.hivemind.schema.SchemaProcessor;
22
23 /**
24 * Rule used to connect a child object to its parent by invoking a method on the parent, passing the
25 * child. The child object is the top object on the stack and the parent object is the next object
26 * down on the stack. Created from the <code><invoke-parent></code> element. Generally, this
27 * is the last rule in a sequence of rules.
28 *
29 * @author Howard Lewis Ship
30 */
31 public class InvokeParentRule extends BaseRule
32 {
33 private String _methodName;
34
35 private int _depth = 1;
36
37 public InvokeParentRule()
38 {
39
40 }
41
42 public InvokeParentRule(String methodName)
43 {
44 _methodName = methodName;
45 }
46
47 /**
48 * Invokes the named method on the parent object (using reflection).
49 */
50 public void begin(SchemaProcessor processor, Element element)
51 {
52 Object child = processor.peek();
53 Class childClass = child == null ? null : child.getClass();
54 Object parent = processor.peek(_depth);
55
56 try
57 {
58 Method m = findMethod(parent, _methodName, childClass);
59
60 m.invoke(parent, new Object[]
61 { child });
62 }
63 catch (Exception ex)
64 {
65 throw new ApplicationRuntimeException(RulesMessages.errorInvokingMethod(
66 _methodName,
67 parent,
68 getLocation(),
69 ex), getLocation(), ex);
70 }
71 }
72
73 public String getMethodName()
74 {
75 return _methodName;
76 }
77
78 public void setMethodName(String string)
79 {
80 _methodName = string;
81 }
82
83 /**
84 * @since 1.1
85 */
86 public int getDepth()
87 {
88 return _depth;
89 }
90
91 /**
92 * Sets the depth of the parent object. The default is 1.
93 */
94 public void setDepth(int i)
95 {
96 _depth = i;
97 }
98
99 /**
100 * Searches for the *first* public method the has the right name, and takes a single parameter
101 * that is compatible with the parameter type.
102 *
103 * @throws NoSuchMethodException
104 * if a method can't be found
105 */
106 private Method findMethod(Object target, String name, Class parameterType)
107 throws NoSuchMethodException
108 {
109 Method[] methods = target.getClass().getMethods();
110
111 for (int i = 0; i < methods.length; i++)
112 {
113 Method m = methods[i];
114 Class[] parameterTypes = m.getParameterTypes();
115
116 if (parameterTypes.length != 1)
117 continue;
118
119 if (!m.getName().equals(name))
120 continue;
121
122 if ((parameterType != null && parameterTypes[0].isAssignableFrom(parameterType))
123 || (parameterType == null && !parameterTypes[0].isPrimitive()))
124 return m;
125 }
126
127 throw new NoSuchMethodException(name);
128 }
129 }