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: Accessor.java,v 1.11 2002/09/12 18:24:41 ludovicc Exp $
37 */
38 package org.scopemvc.model.beans;
39
40 import java.beans.IndexedPropertyDescriptor;
41 import java.beans.PropertyDescriptor;
42 import java.lang.reflect.InvocationTargetException;
43 import java.lang.reflect.Method;
44 import java.util.List;
45 import org.apache.commons.logging.Log;
46 import org.apache.commons.logging.LogFactory;
47 import org.scopemvc.core.IntIndexSelector;
48 import org.scopemvc.core.Selector;
49 import org.scopemvc.core.StringIndexSelector;
50 import org.scopemvc.util.Debug;
51
52 /***
53 * <P>
54 *
55 * Describes a single JavaBeans accessor. Since this includes indexed
56 * properties, it might represent access into an ordered Collection, consuming
57 * two Selectors: a String one to describe the Collection and an int one to
58 * fetch the member of the List; eg "customers.0" can be traversed in one step
59 * if the parent model JavaBean has a <CODE>getCustomer(int)</CODE> method. <br>
60 * Handles java.util.List and Object[] for int indexed properties. </P> <p>
61 *
62 * Make sure to call findProperty before traverseProperty.</p>
63 *
64 * @author <A HREF="mailto:smeyfroi@users.sourceforge.net">Steve Meyfroidt</A>
65 * @created 05 September 2002
66 * @version $Revision: 1.11 $ $Date: 2002/09/12 18:24:41 $
67 */
68 final class Accessor {
69
70 private static final Log LOG = LogFactory.getLog(Accessor.class);
71
72 /***
73 * Current model (changes when traverseProperty is called)
74 */
75 Object model;
76
77 /***
78 * Current selector (changes when traverseProperty is called)
79 */
80 Selector selector;
81
82 /***
83 * Original model, used for error reports
84 */
85 Object originalModel;
86
87 /***
88 * Original selector, used for error reports
89 */
90 Selector originalSelector;
91
92 /***
93 * Descriptor for the current property, either
94 * <ul>
95 * <li> IndexedPropertyDescriptor (traverse through indexed),
96 * <li> PropertyDescriptor (normal String),
97 * <li> or null (normal Integer through a List model)
98 * </ul>
99 * Populated in findProperty
100 */
101 PropertyDescriptor descriptor;
102
103 /***
104 * Populated in findProperty
105 */
106 boolean isGetterIndexed;
107
108 /***
109 * reuse this when invoking indexed properties
110 */
111 private Object[] params = new Object[1];
112
113 /***
114 * Creates a new Accessor for the Selector in the model
115 *
116 * @param inModel The model object, not null
117 * @param inSelector The Selector for a property in the model, not null
118 */
119 Accessor(Object inModel, Selector inSelector) {
120 if (inModel == null) {
121 throw new IllegalArgumentException("No model to find property for: " + selector);
122 }
123 if (inSelector == null) {
124 throw new IllegalArgumentException("No property selector defined for model: " + model);
125 }
126 originalModel = inModel;
127 originalSelector = inSelector;
128 model = inModel;
129 selector = inSelector;
130 }
131
132
133 /***
134 * Returns a string representation of this object
135 *
136 * @return a string representation of this object
137 */
138 public String toString() {
139 return "Accessor: original model(" + originalModel
140 + ") original selector(" + originalSelector
141 + ") current model(" + model
142 + ") current selector(" + selector
143 + ") descriptor(" + descriptor
144 + ") isGetterIndexed(" + isGetterIndexed + ")";
145 }
146
147
148 /***
149 * Next traversal is over the terminal property? Depends on prior call to
150 * {@link #findProperty}.
151 *
152 * @return The atTerminal value
153 */
154 boolean isAtTerminal() {
155 if (LOG.isDebugEnabled()) {
156 LOG.debug("isAtTerminal: " + model + ", " + selector + ", " + isGetterIndexed);
157 }
158
159 return (
160 selector == null
161 || (selector.getNext() == null)
162 || (isGetterIndexed && selector instanceof StringIndexSelector
163 && selector.getNext() instanceof IntIndexSelector
164 && selector.getNext().getNext() == null)
165 );
166 }
167
168
169 /***
170 * Find the next property and populate the descriptor. <br>
171 * descriptor == null if next selector is IntIndexed (ie access property
172 * through java.util.List or Object[]), else either a PropertyDescriptor or
173 * an IndexedPropertyDescriptor.
174 *
175 * @throws IllegalArgumentException if the model or the selector is null
176 * @throws NullPropertyException if the property could not be found in the
177 * model using the selector.
178 */
179 void findProperty() throws IllegalArgumentException, NullPropertyException {
180 if (LOG.isDebugEnabled()) {
181 LOG.debug("findProperty: " + model + ", " + selector);
182 }
183 if (Debug.ON) {
184 Debug.assertTrue(selector != null, "null selector");
185 }
186
187 if (model == null) {
188 Selector intermediateSelector = originalSelector.deepClone();
189 intermediateSelector.removeLast(selector);
190 throw new NullPropertyException("Null property in model: " + originalModel + " with selector: " + intermediateSelector);
191 }
192 if (selector == null) {
193 throw new IllegalArgumentException("No property selector defined for model: " + model);
194 }
195
196 if (selector instanceof IntIndexSelector) {
197 descriptor = null;
198 isGetterIndexed = false;
199 } else {
200 String property = ((StringIndexSelector) selector).getIndex();
201 descriptor = BeanInfos.getPropertyDescriptor(model.getClass(), property);
202 if (descriptor == null) {
203 throw new IllegalArgumentException("Property for selector: " + selector +
204 " could not be found in model: " + model);
205 }
206 if (descriptor instanceof IndexedPropertyDescriptor
207 && selector.getNext() instanceof IntIndexSelector
208 && ((IndexedPropertyDescriptor) descriptor).getIndexedReadMethod() != null) {
209 isGetterIndexed = true;
210 } else {
211 isGetterIndexed = false;
212 }
213 }
214 }
215
216
217 /***
218 * Burrows down through the next accessor to the next one. If the property
219 * we return is an int-indexed property (ie accessed property from
220 * java.util.List or Object[]) then the PropertyDescriptor will be null.
221 *
222 * @throws IllegalArgumentException if the model or the selector is null
223 * @throws Exception Any other exception thrown when accessing the model
224 */
225 void traverseProperty() throws IllegalArgumentException, Exception {
226 if (LOG.isDebugEnabled()) {
227 LOG.debug("traverseProperty: " + model + ", " + selector + ", " + descriptor);
228 }
229
230 try {
231 if (descriptor == null) {
232 // Traverse a List or array using int selector
233 if (Debug.ON) {
234 Debug.assertTrue(selector instanceof IntIndexSelector, "not IntIndexSelector: " + selector);
235 }
236 int index = ((IntIndexSelector) selector).getIndex();
237 if (model instanceof List) {
238 model = ((List) model).get(index);
239 } else if (model instanceof Object[]) {
240 model = ((Object[]) model)[index];
241 } else {
242 throw new IllegalArgumentException("Can't access properties using int index (expected List or Object[]): " + selector);
243 }
244 selector = selector.getNext();
245
246 } else if (isGetterIndexed) {
247 // Traverse a javabeans indexed property using the int selector from selector.getNext()
248 if (Debug.ON) {
249 Debug.assertTrue(descriptor instanceof IndexedPropertyDescriptor, "not IndexedPropertyDescriptor: " + descriptor);
250 }
251 if (Debug.ON) {
252 Debug.assertTrue(selector instanceof StringIndexSelector, "not StringIndexSelector: " + selector);
253 }
254 if (Debug.ON) {
255 Debug.assertTrue(selector.getNext() instanceof IntIndexSelector, "not IntIndexSelector: " + selector.getNext());
256 }
257 Method getter = ((IndexedPropertyDescriptor) descriptor).getIndexedReadMethod();
258 params[0] = new Integer(((IntIndexSelector) selector.getNext()).getIndex());
259 if (getter == null) {
260 throw new IllegalArgumentException("No indexed getter for: " + selector);
261 }
262 model = getter.invoke(model, params);
263 selector = selector.getNext().getNext();
264
265 } else {
266 // Traverse a property using the String selector
267 if (Debug.ON) {
268 Debug.assertTrue(selector instanceof StringIndexSelector, "not StringIndexSelector: " + selector);
269 }
270 Method getter = descriptor.getReadMethod();
271 if (getter == null) {
272 throw new IllegalArgumentException("No getter for: " + selector);
273 }
274 model = getter.invoke(model, null);
275 selector = selector.getNext();
276 }
277
278 } catch (InvocationTargetException e) {
279 if (LOG.isDebugEnabled()) {
280 LOG.debug("traverseProperty: " + selector, e);
281 }
282 if (e.getTargetException() instanceof Exception) {
283 throw (Exception) e.getTargetException();
284 }
285 throw e;
286 } catch (IllegalAccessException e1) {
287 if (LOG.isDebugEnabled()) {
288 LOG.debug("traverseProperty: no accessible getter: " + selector, e1);
289 }
290 throw e1;
291 } catch (IndexOutOfBoundsException e2) {
292 if (LOG.isDebugEnabled()) {
293 LOG.debug("traverseProperty: IndexOutOfBoundsException: " + selector, e2);
294 }
295 throw e2;
296 } catch (NullPointerException e3) {
297 if (LOG.isDebugEnabled()) {
298 LOG.debug("traverseProperty: NullPointerException: " + selector, e3);
299 }
300 throw e3;
301 }
302 }
303 }
304
This page was automatically generated by Maven