1 /***
2 * AccessorOperator.java
3 *
4 * $Author: mballesteros $
5 * $Date: 2003/11/28 19:18:03 $
6 * $Revision: 1.1 $
7 */
8 package net.sf.jec;
9
10 import java.lang.reflect.InvocationTargetException;
11 import java.lang.reflect.Method;
12 import java.util.Map;
13
14 import net.sf.jec.util.XMLHelper;
15
16 import org.apache.commons.beanutils.PropertyUtils;
17 import org.w3c.dom.Element;
18
19 /***
20 * This operator returns/sets a property of the context object. The actual
21 * "property" definition depends on the context object class:
22 * <ul>
23 * <li>For a Map, a property is just an entry, being the property name the key
24 * and the property value the associated key value.</li>
25 * <li>For a bean, a property is anything acccessible through a getter/setter
26 * methods</li>
27 * <li>For a DOM element, a property is a named child and its value the child's
28 * content</li>
29 * </ul>
30 *
31 * @author mballesteros
32 */
33 public class AccessorOperator extends InvertibleOperator {
34
35 private String field;
36 private Getter getter;
37 private Setter setter;
38 private boolean throwExceptions;
39
40 /***
41 * Creates a new AccessorOperator that will try to get and set the
42 * <code>field</code> property of the context
43 *
44 * @param field The field that will be accessed
45 * @param throwExceptions
46 */
47 public AccessorOperator(String field, boolean throwExceptions) {
48 super();
49 this.field = field;
50 this.throwExceptions = throwExceptions;
51 }
52
53 /***
54 * Creates a new AccessorOperator that will try to get and set the
55 * <code>field</code> property of the context
56 *
57 * @param field The field that will be accessed
58 * @param nestedOp The nested operator
59 * @param throwExceptions
60 */
61 public AccessorOperator(
62 String field,
63 Operator nestedOp,
64 boolean throwExceptions) {
65 super(nestedOp);
66 this.field = field;
67 this.throwExceptions = throwExceptions;
68 }
69
70 /***
71 * Returns a function representation String for this operator
72 *
73 * @return A String representation in a Function like style
74 */
75 public String toFunctionString() {
76 return "Accessor('"
77 + field
78 + "'"
79 + (nestedOp == null ? "" : ", " + nestedOp)
80 + ")";
81 }
82
83 /***
84 * Returns an expression String representation for this operator
85 * @return A String representation in an expression like style
86 */
87 public String toExpressionString() {
88 return (nestedOp == null ? "" : nestedOp + ".") + field;
89 }
90
91 /***
92 * Returns the associated value to the given context and root context
93 * @param rootCtx The root context, needed for operators that require
94 * expression evaluation from root point. Example: Indexer operators
95 * @param ctx The current context where the operator will work over
96 * @return The direct mapping of this operator on the given context
97 * @throws EvaluationException Thrown if there's an evaluation problem
98 */
99 protected Object directMap(Object rootCtx, Object ctx)
100 throws EvaluationException {
101 if (getter == null)
102 getter = getGetter(ctx, field);
103 return getter.getField(ctx, field);
104 }
105
106 /***
107 * Sets the given value if this operator is at the end of the operator chain
108 * or just resolves the context object and passes it to the next operator in
109 * the chain.
110 * @param rootCtx The root context, needed for operators that require
111 * expression evaluation from root point. Example: Indexer operators
112 * @param ctx The current context where the operator will work over
113 * @param value The value to set.
114 * @throws EvaluationException Thrown if there's an evaluation problem
115 */
116 protected void inverseMap(Object rootCtx, Object ctx, Object value)
117 throws EvaluationException {
118 if (setter == null)
119 setter = getSetter(ctx, field, value);
120 setter.setField(ctx, field, value);
121 }
122
123 //=========================================================================
124 // Helper classes...
125 //=========================================================================
126 interface Getter {
127 public Object getField(Object ctx, String field)
128 throws EvaluationException;
129 }
130
131 interface Setter {
132 public void setField(Object ctx, String field, Object value)
133 throws EvaluationException;
134 }
135
136 //=========================================================================
137 // GETTERS
138 Getter getGetter(Object obj, String fieldname) throws EvaluationException {
139 if (obj instanceof Map) {
140 return new MapGetter();
141 } else if (obj instanceof Element) {
142 return new ElementGetter();
143 } else {
144 Method getter;
145 try {
146 getter =
147 PropertyUtils.getReadMethod(
148 PropertyUtils.getPropertyDescriptor(obj, fieldname));
149 return new AccessorOperator.BeanGetter(getter);
150 } catch (IllegalAccessException e) {
151 // Do nothing
152 } catch (InvocationTargetException e) {
153 // Do nothing
154 } catch (NoSuchMethodException e) {
155 // Do nothing
156 }
157 if (throwExceptions) {
158 throw new EvaluationException(
159 "Cannot find getter for property '"
160 + fieldname
161 + "' in class: "
162 + obj.getClass().getName());
163 } else {
164 return new NullGetter();
165 }
166 }
167 }
168
169 class NullGetter implements Getter {
170 public Object getField(Object ctx, String field)
171 throws EvaluationException {
172 return null;
173 }
174 }
175
176 class MapGetter implements Getter {
177 public Object getField(Object ctx, String field)
178 throws EvaluationException {
179 return ((Map) ctx).get(field);
180 }
181 }
182
183 class ElementGetter implements Getter {
184 public Object getField(Object ctx, String field)
185 throws EvaluationException {
186 if (field.charAt(0) == '@') {
187 return ((Element) ctx).getAttribute(field.substring(1));
188 } else {
189 if (field.equals("_text")) {
190 return XMLHelper.getText((Element) ctx);
191 } else {
192 return XMLHelper.getChild((Element) ctx, field);
193 }
194 }
195 }
196 }
197
198 class BeanGetter implements Getter {
199 private Method method;
200 public BeanGetter(Method method) {
201 this.method = method;
202 }
203 public Object getField(Object ctx, String field)
204 throws EvaluationException {
205 try {
206 return ObjectConverter.normalize(method.invoke(ctx, null));
207 } catch (Exception e) {
208 if (throwExceptions)
209 throw new EvaluationException(
210 "Error invokating method: " + e.getMessage());
211 else
212 return null;
213 }
214 }
215 }
216
217 //=========================================================================
218 // SETTERS
219 Setter getSetter(Object obj, String fieldname, Object fieldvalue)
220 throws EvaluationException {
221 if (obj instanceof Map) {
222 return new HashMapSetter();
223 } else if (obj instanceof Element) {
224 return new ElementSetter();
225 } else {
226 Method setter;
227 try {
228 setter =
229 PropertyUtils.getWriteMethod(
230 PropertyUtils.getPropertyDescriptor(obj, fieldname));
231 return new AccessorOperator.BeanSetter(setter);
232 } catch (IllegalAccessException e) {} catch (InvocationTargetException e) {} catch (NoSuchMethodException e) {}
233 if (throwExceptions) {
234 throw new EvaluationException(
235 "Cannot find setter for property '"
236 + fieldname
237 + "' in class: "
238 + obj.getClass().getName());
239 } else {
240 return null;
241 }
242 }
243 }
244
245 class HashMapSetter implements Setter {
246 public void setField(Object ctx, String field, Object value)
247 throws EvaluationException {
248 ((Map) ctx).put(field, value);
249 }
250 }
251
252 class ElementSetter implements Setter {
253 public void setField(Object ctx, String field, Object value)
254 throws EvaluationException {
255 if (field.charAt(0) == '@') {
256 ((Element) ctx).setAttribute(
257 field.substring(1),
258 value.toString());
259 } else {
260 if (field.equals("_text")) {
261 XMLHelper.setText((Element) ctx, value.toString());
262 } else {
263 XMLHelper.setChild((Element) ctx, field, value);
264 }
265 }
266 }
267 }
268
269 class BeanSetter implements Setter {
270 private Method method;
271 private Class targetClass;
272 private int conversionType;
273
274 public BeanSetter(Method method) {
275 this.method = method;
276 this.targetClass = method.getParameterTypes()[0];
277 }
278 public BeanSetter(Method method, Class targetClass) {
279 this.method = method;
280 this.targetClass = targetClass;
281 }
282
283 public void setField(Object ctx, String field, Object value)
284 throws EvaluationException {
285 try {
286 value = ObjectConverter.convert(value, targetClass);
287 method.invoke(ctx, new Object[] { value });
288 } catch (Exception e) {
289 if (throwExceptions)
290 throw new EvaluationException(
291 "Error invokating method: " + e.getMessage());
292 }
293 }
294 }
295 }
This page was automatically generated by Maven