1 /*
2 * Scope: a generic MVC framework.
3 * Copyright (c) 2000-2002, The Scope team
4 * All rights reserved.
5 *
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * Neither the name "Scope" nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 *
36 * $Id: BeansActionManager.java,v 1.8 2002/09/12 10:51:03 ludovicc Exp $
37 */
38 package org.scopemvc.model.beans;
39
40
41 import java.beans.MethodDescriptor;
42 import java.lang.reflect.InvocationTargetException;
43 import java.lang.reflect.Method;
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46 import org.scopemvc.core.ActionManager;
47 import org.scopemvc.core.ModelAction;
48 import org.scopemvc.util.Debug;
49
50 /***
51 * <P>
52 *
53 * BeansActionManager is a {@link org.scopemvc.core.ActionManager} that handles
54 * the actions (invokable methods) of JavaBean model objects. </P>
55 *
56 * @author <A HREF="mailto:smeyfroi@users.sourceforge.net">Steve Meyfroidt</A>
57 * @created 05 September 2002
58 * @version $Revision: 1.8 $ $Date: 2002/09/12 10:51:03 $
59 */
60 public class BeansActionManager extends ActionManager {
61
62 private static final Log LOG = LogFactory.getLog(BeansActionManager.class);
63
64
65 /***
66 * Utility method to determine if a given parameter class array matches the
67 * supplied prototype class array
68 *
69 * @param inPrototypeClasses the prototype that is used in the comparison
70 * @param inParameterClasses these are the parameter classes that must be
71 * validated against the prototype
72 * @return whether the parameter classes match the prototype
73 */
74 protected static boolean matchesPrototype(Class[] inPrototypeClasses, Class[] inParameterClasses) {
75 if (LOG.isDebugEnabled()) {
76 LOG.debug("matchesPrototype: prototype classes: " + inPrototypeClasses + ", parameter classes: " + inParameterClasses);
77 if (inPrototypeClasses != null) {
78 LOG.debug("matchesPrototype: prototype classes: " + java.util.Arrays.asList(inPrototypeClasses));
79 }
80 if (inParameterClasses != null) {
81 LOG.debug("matchesPrototype: parameter classes: " + java.util.Arrays.asList(inParameterClasses));
82 }
83 }
84
85 if (inPrototypeClasses == null || inParameterClasses == null || inPrototypeClasses.length == 0 || inParameterClasses.length == 0) {
86 // Equivalent if both are zero length or null
87 if (LOG.isDebugEnabled()) {
88 LOG.debug("matchesPrototype: nulls or 0 lengths");
89 }
90 return (inPrototypeClasses == null || inPrototypeClasses.length == 0) && (inParameterClasses == null || inParameterClasses.length == 0);
91 } else if (inPrototypeClasses.length == inParameterClasses.length) {
92 if (LOG.isDebugEnabled()) {
93 LOG.debug("matchesPrototype: lengths: " + inPrototypeClasses.length + ", " + inParameterClasses.length);
94 }
95
96 for (int i = 0; i < inPrototypeClasses.length; ++i) {
97 if (!matchesItem(inPrototypeClasses[i], inParameterClasses[i])) {
98 return false;
99 }
100 }
101 return true;
102 } else {
103 // different lengths
104 return false;
105 }
106 }
107
108
109 /***
110 * Utility method to determine if a given class matches another class,
111 * taking into account primitive<->class mapping and inheritance.
112 *
113 * @param inPrototypeClass TODO: Describe the Parameter
114 * @param inParameterClass TODO: Describe the Parameter
115 * @return TODO: Describe the Return Value
116 */
117 protected static boolean matchesItem(Class inPrototypeClass, Class inParameterClass) {
118 if (LOG.isDebugEnabled()) {
119 LOG.debug("matchesItem: prototype class: " + inPrototypeClass + ", parameter class: " + inPrototypeClass);
120 }
121
122 if (inPrototypeClass.isAssignableFrom(inParameterClass)) {
123 return true;
124 }
125
126 if (inPrototypeClass.isPrimitive()) {
127 if ((inPrototypeClass.equals(int.class) && inParameterClass.equals(Integer.class)) ||
128 (inPrototypeClass.equals(long.class) && inParameterClass.equals(Long.class)) ||
129 (inPrototypeClass.equals(short.class) && inParameterClass.equals(Short.class)) ||
130 (inPrototypeClass.equals(float.class) && inParameterClass.equals(Float.class)) ||
131 (inPrototypeClass.equals(double.class) && inParameterClass.equals(Double.class)) ||
132 (inPrototypeClass.equals(char.class) && inParameterClass.equals(Character.class)) ||
133 (inPrototypeClass.equals(byte.class) && inParameterClass.equals(Byte.class))
134 ) {
135 return true;
136 }
137 }
138 return false;
139 }
140
141
142 /***
143 * Execute the ModelAction with the given parameters
144 *
145 * @param inModel The model used for executing the ModelAction
146 * @param inAction The action (method) to execute
147 * @param inParameters The parameters of the method
148 * @return The result of the ModelAction method
149 * @throws Exception if the execution of the ModelAction failed for any
150 * reason
151 */
152 public Object doAction(Object inModel, ModelAction inAction, Object[] inParameters) throws Exception {
153 if (inModel == null) {
154 throw new IllegalArgumentException("Can't doAction on a null model.");
155 }
156 if (inAction == null) {
157 throw new IllegalArgumentException("Can't doAction with a null action.");
158 }
159
160 Method method = getMethod(inModel, inAction);
161 if (method == null) {
162 throw new IllegalArgumentException("Cannot do action: " + inAction + " on model: " + inModel);
163 }
164
165 try {
166 return method.invoke(inModel, inParameters);
167 } catch (InvocationTargetException e) {
168 if (LOG.isDebugEnabled()) {
169 LOG.debug("doAction:" + e);
170 }
171 if (e.getTargetException() instanceof Exception) {
172 throw (Exception) e.getTargetException();
173 }
174 throw e;
175 // throw new ModelException(inModel, "doAction on: " + inModel + ": " + e);
176 } catch (Exception e1) {
177 if (LOG.isDebugEnabled()) {
178 LOG.debug("doAction:" + e1);
179 }
180 throw e1;
181 }
182 }
183
184
185 /***
186 * Returns true if the ModelAction can be executed on the model object. <br>
187 * If the model implements {@link DynamicInvokable}, then check that the
188 * ModelAction can be invoked by calling the {@link
189 * DynamicInvokable#isActionInvokable isActionInvokable()} method on the
190 * model.
191 *
192 * @param inModel The model used for executing the ModelAction
193 * @param inAction The action (method) to execute
194 * @return true if the ModelAction can be executed on the model
195 */
196 public boolean canDoAction(Object inModel, ModelAction inAction) {
197 if (inModel instanceof DynamicInvokable) {
198 return ((DynamicInvokable) inModel).isActionInvokable(inAction);
199 }
200 return (getMethod(inModel, inAction) != null);
201 }
202
203
204 /***
205 * Find a Method matching the prototype in the passed ModelAction for the
206 * passed model object, using the BeanInfo to introspect the model as a
207 * JavaBean.
208 *
209 * @param inAction find a Method that matches the prototype described in
210 * this ModelAction.
211 * @param inModel The model used for executing the ModelAction
212 * @return a Method matching the ModelAction for the passed model or null if
213 * no match.
214 */
215 protected Method getMethod(Object inModel, ModelAction inAction) {
216 if (LOG.isDebugEnabled()) {
217 LOG.debug("getMethod: " + inAction);
218 }
219 if (inModel == null) {
220 throw new IllegalArgumentException("Can't getMethod on a null model.");
221 }
222 if (inAction == null) {
223 throw new IllegalArgumentException("Can't getMethod with a null action.");
224 }
225
226 MethodDescriptor[] descriptors = BeanInfos.getBeanInfo(inModel.getClass()).getMethodDescriptors();
227 if (Debug.ON) {
228 Debug.assertTrue(descriptors != null);
229 }
230
231 for (int i = 0; i < descriptors.length; ++i) {
232 MethodDescriptor desc = descriptors[i];
233 if (Debug.ON) {
234 Debug.assertTrue(desc != null);
235 }
236
237 if (desc.getName().equals(inAction.getMethodName())) {
238 if (matchesPrototype(desc.getMethod().getParameterTypes(), inAction.getParameterClasses())) {
239 return desc.getMethod();
240 }
241 }
242 }
243 return null;
244 }
245 }
This page was automatically generated by Maven