001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: ElementInjector.java 3716 2007-04-11 06:21:18Z gbevin $
007: */
008: package com.uwyn.rife.engine;
009:
010: import com.uwyn.rife.engine.exceptions.*;
011:
012: import com.uwyn.rife.tools.BeanPropertyProcessor;
013: import com.uwyn.rife.tools.BeanUtils;
014: import com.uwyn.rife.tools.Convert;
015: import com.uwyn.rife.tools.exceptions.BeanUtilsException;
016: import com.uwyn.rife.tools.exceptions.ConversionException;
017: import java.beans.PropertyDescriptor;
018: import java.lang.reflect.InvocationTargetException;
019: import java.lang.reflect.Method;
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.Collections;
023: import java.util.LinkedHashMap;
024: import java.util.Map;
025:
026: class ElementInjector {
027: private ElementContext mContext = null;
028: private ElementSupport mElement = null;
029: private ElementAware mElementAware = null;
030: private ElementInfo mElementInfo = null;
031:
032: private Map<String, Method> mPropertySetters = null;
033: private Map<String, Method> mIncookieSetters = null;
034: private Map<String, Method> mInputSetters = null;
035: private Map<String, Method> mInbeanSetters = null;
036: private SubmissionSettersCache mSubmissionSettersCache = null;
037:
038: ElementInjector(ElementContext context) {
039: assert context != null;
040:
041: mContext = context;
042: mElement = mContext.getElementSupport();
043: mElementAware = mElement.getElementAware();
044: mElementInfo = context.getElementInfo();
045:
046: // try to obtain the element's setter methods from the cache
047: mPropertySetters = mElementInfo.getSite()
048: .getCachedPropertySetters(mElementInfo.getId());
049: mIncookieSetters = mElementInfo.getSite()
050: .getCachedIncookieSetters(mElementInfo.getId());
051: mInputSetters = mElementInfo.getSite().getCachedInputSetters(
052: mElementInfo.getId());
053: mInbeanSetters = mElementInfo.getSite().getCachedInbeanSetters(
054: mElementInfo.getId());
055: mSubmissionSettersCache = mElementInfo.getSite()
056: .getSubmissionSettersCache(mElementInfo.getId());
057:
058: // if at least one of the setter types couldn't be obtained, re-detect them all
059: if (null == mPropertySetters || null == mIncookieSetters
060: || null == mInputSetters || null == mInbeanSetters
061: || null == mSubmissionSettersCache) {
062: try {
063: if (null == mSubmissionSettersCache) {
064: mSubmissionSettersCache = new SubmissionSettersCache();
065: }
066:
067: BeanUtils.processProperties(BeanUtils.SETTERS,
068: mElementAware.getClass(), null, null, null,
069: new ElementInjectorPropertyProcessor());
070:
071: if (null == mPropertySetters) {
072: mPropertySetters = Collections.EMPTY_MAP;
073: }
074: if (null == mIncookieSetters) {
075: mIncookieSetters = Collections.EMPTY_MAP;
076: }
077: if (null == mInputSetters) {
078: mInputSetters = Collections.EMPTY_MAP;
079: }
080: if (null == mInbeanSetters) {
081: mInbeanSetters = Collections.EMPTY_MAP;
082: }
083:
084: // store the this element's setters in the cache
085: mElementInfo.getSite().putCachedPropertySetters(
086: mElementInfo.getId(), mPropertySetters);
087: mElementInfo.getSite().putCachedIncookieSetters(
088: mElementInfo.getId(), mIncookieSetters);
089: mElementInfo.getSite().putCachedInputSetters(
090: mElementInfo.getId(), mInputSetters);
091: mElementInfo.getSite().putCachedInbeanSetters(
092: mElementInfo.getId(), mInbeanSetters);
093: mElementInfo.getSite().putSubmissionSettersCache(
094: mElementInfo.getId(), mSubmissionSettersCache);
095: } catch (BeanUtilsException e) {
096: throw new ElementInjectionException(mElementInfo
097: .getDeclarationName(),
098: mElementAware.getClass(), e);
099: }
100: }
101: }
102:
103: void performInjection(String submissionName) {
104: Submission submission = null;
105: if (submissionName != null) {
106: submission = mElementInfo.getSubmission(submissionName);
107: }
108:
109: // inject the element properties
110: for (Map.Entry<String, Method> setter : mPropertySetters
111: .entrySet()) {
112: Method write = setter.getValue();
113: Class type = write.getParameterTypes()[0];
114: try {
115: write.invoke(mElementAware, Convert.toType(mElementInfo
116: .getProperty(setter.getKey()), type));
117: } catch (Exception e) {
118: throw new PropertyInjectionException(mElementInfo
119: .getDeclarationName(),
120: mElementAware.getClass(), setter.getKey(), e);
121: }
122: }
123:
124: // inject the element parameters vars
125: if (submission != null) {
126: Map<String, Method> param_setters = mSubmissionSettersCache
127: .getCachedSubmissionparamSetters(submissionName);
128: if (param_setters != null) {
129: for (Map.Entry<String, Method> setter : param_setters
130: .entrySet()) {
131: Method write = setter.getValue();
132: Class type = write.getParameterTypes()[0];
133:
134: try {
135: if (type.isArray()) {
136: String[] values = mElement
137: .getParameterValues(setter.getKey());
138: if (values != null) {
139: write.invoke(mElementAware,
140: new Object[] { Convert.toType(
141: values, type) });
142: }
143: } else {
144: String value = mElement.getParameter(setter
145: .getKey());
146: if (value != null) {
147: write.invoke(mElementAware,
148: new Object[] { Convert.toType(
149: value, type) });
150: }
151: }
152: } catch (ConversionException e) {
153: try {
154: String[] values = submission
155: .getParameterDefaultValues(setter
156: .getKey());
157: if (values != null && type.isArray()) {
158: if (values != null) {
159: write.invoke(mElementAware,
160: new Object[] { Convert
161: .toType(values,
162: type) });
163: }
164: } else if (values != null
165: && values.length > 0) {
166: String value = values[0];
167: if (value != null) {
168: write
169: .invoke(
170: mElementAware,
171: new Object[] { Convert
172: .toType(
173: value,
174: type) });
175: }
176: } else if (!type.isPrimitive()) {
177: write.invoke(mElementAware,
178: new Object[] { null });
179: }
180: } catch (Exception e2) {
181: throw new ParameterInjectionException(
182: mElementInfo.getDeclarationName(),
183: mElementAware.getClass(),
184: submissionName, setter.getKey(), e2);
185: }
186: } catch (Exception e) {
187: throw new ParameterInjectionException(
188: mElementInfo.getDeclarationName(),
189: mElementAware.getClass(),
190: submissionName, setter.getKey(), e);
191: }
192: }
193: }
194: }
195:
196: // inject the element incookies and global cookies
197: for (Map.Entry<String, Method> setter : mIncookieSetters
198: .entrySet()) {
199: Method write = setter.getValue();
200: Class type = write.getParameterTypes()[0];
201:
202: try {
203: write
204: .invoke(mElementAware, new Object[] { Convert
205: .toType(mElement.getCookieValue(setter
206: .getKey()), type) });
207: } catch (ConversionException e) {
208: try {
209: String value = mElementInfo
210: .getIncookieDefaultValue(setter.getKey());
211: if (value != null) {
212: write.invoke(mElementAware,
213: new Object[] { Convert.toType(value,
214: type) });
215: } else if (!type.isPrimitive()) {
216: write.invoke(mElementAware,
217: new Object[] { null });
218: }
219: } catch (Exception e2) {
220: throw new IncookieInjectionException(mElementInfo
221: .getDeclarationName(), mElementAware
222: .getClass(), setter.getKey(), e2);
223: }
224: } catch (Exception e) {
225: throw new IncookieInjectionException(mElementInfo
226: .getDeclarationName(),
227: mElementAware.getClass(), setter.getKey(), e);
228: }
229: }
230:
231: // inject the element inputs and global vars
232: for (Map.Entry<String, Method> setter : mInputSetters
233: .entrySet()) {
234: Method write = setter.getValue();
235: Class type = write.getParameterTypes()[0];
236:
237: try {
238: if (type.isArray()) {
239: write.invoke(mElementAware, new Object[] { Convert
240: .toType(mElement.getInputValues(setter
241: .getKey()), type) });
242: } else {
243: write.invoke(mElementAware, new Object[] { Convert
244: .toType(mElement.getInput(setter.getKey()),
245: type) });
246: }
247: } catch (ConversionException e) {
248: try {
249: String[] values = mElementInfo
250: .getInputDefaultValues(setter.getKey());
251: if (values != null && type.isArray()) {
252: if (values != null) {
253: write.invoke(mElementAware,
254: new Object[] { Convert.toType(
255: values, type) });
256: }
257: } else if (values != null && values.length > 0) {
258: String value = values[0];
259: if (value != null) {
260: write.invoke(mElementAware,
261: new Object[] { Convert.toType(
262: value, type) });
263: }
264: } else if (!type.isPrimitive()) {
265: write.invoke(mElementAware,
266: new Object[] { null });
267: }
268: } catch (Exception e2) {
269: throw new InputInjectionException(mElementInfo
270: .getDeclarationName(), mElementAware
271: .getClass(), setter.getKey(), e2);
272: }
273: } catch (Exception e) {
274: throw new InputInjectionException(mElementInfo
275: .getDeclarationName(),
276: mElementAware.getClass(), setter.getKey(), e);
277: }
278: }
279:
280: // inject the element named inbeans
281: for (Map.Entry<String, Method> setter : mInbeanSetters
282: .entrySet()) {
283: Method write = setter.getValue();
284: Class type = write.getParameterTypes()[0];
285:
286: try {
287: write.invoke(mElementAware, new Object[] { Convert
288: .toType(mElement.getNamedInputBean(setter
289: .getKey()), type) });
290: } catch (Exception e) {
291: throw new NamedInbeanInjectionException(mElementInfo
292: .getDeclarationName(),
293: mElementAware.getClass(), setter.getKey(), e);
294: }
295: }
296:
297: // inject the element named submission beans
298: if (submission != null) {
299: Map<String, Method> bean_setters = mSubmissionSettersCache
300: .getCachedSubmissionbeanSetters(submissionName);
301: if (bean_setters != null) {
302: for (Map.Entry<String, Method> setter : bean_setters
303: .entrySet()) {
304: Method write = setter.getValue();
305: Class type = write.getParameterTypes()[0];
306:
307: try {
308: write.invoke(mElementAware,
309: new Object[] { Convert.toType(mElement
310: .getNamedSubmissionBean(
311: submissionName, setter
312: .getKey()),
313: type) });
314: } catch (Exception e) {
315: throw new NamedSubmissionBeanInjectionException(
316: mElementInfo.getDeclarationName(),
317: mElementAware.getClass(), setter
318: .getKey(), e);
319: }
320: }
321: }
322:
323: // inject the element submission file uploads
324: Map<String, Method> file_setters = mSubmissionSettersCache
325: .getCachedUploadedfileSetters(submissionName);
326: if (file_setters != null) {
327: for (Map.Entry<String, Method> setter : file_setters
328: .entrySet()) {
329: Method write = setter.getValue();
330:
331: UploadedFile file = mContext.getUploadedFile(setter
332: .getKey());
333: if (file != null) {
334: try {
335: write.invoke(mElementAware,
336: new Object[] { file });
337: } catch (Exception e) {
338: throw new UploadedSubmissionFilesInjectionException(
339: mElementInfo.getDeclarationName(),
340: mElementAware.getClass(), setter
341: .getKey(), e);
342: }
343: }
344: }
345: }
346: }
347: }
348:
349: private class ElementInjectorPropertyProcessor implements
350: BeanPropertyProcessor {
351: private Collection<String> mPropertynames;
352: private Collection<String> mNamesIncookies;
353: private Collection<String> mNamesInputs;
354: private Collection<String> mNamesInbeans;
355:
356: ElementInjectorPropertyProcessor() {
357: mPropertynames = mElementInfo.getInjectablePropertyNames();
358:
359: if (!mElementInfo.hasIncookies()
360: && !mElementInfo.hasGlobalCookies()) {
361: mNamesIncookies = null;
362: } else {
363: final Collection<String> names_globalcookies = mElementInfo
364: .getGlobalCookieNames();
365: if (names_globalcookies != null
366: && names_globalcookies.size() > 0) {
367: mNamesIncookies = new ArrayList<String>(
368: mElementInfo.getIncookieNames());
369: mNamesIncookies.addAll(names_globalcookies);
370: } else {
371: mNamesIncookies = mElementInfo.getIncookieNames();
372: }
373: }
374:
375: if (!mElementInfo.hasInputs()
376: && !mElementInfo.hasGlobalVars()) {
377: mNamesInputs = null;
378: } else {
379: Collection<String> names_globalvars = mElementInfo
380: .getGlobalVarNames();
381: if (names_globalvars != null
382: && names_globalvars.size() > 0) {
383: mNamesInputs = new ArrayList<String>(mElementInfo
384: .getInputNames());
385: mNamesInputs.addAll(names_globalvars);
386: } else {
387: mNamesInputs = mElementInfo.getInputNames();
388: }
389: }
390:
391: if (mElementInfo.hasNamedInbeans()) {
392: mNamesInbeans = mElementInfo.getNamedInbeanNames();
393: } else {
394: mNamesInbeans = null;
395: }
396: }
397:
398: public boolean gotProperty(String name,
399: PropertyDescriptor descriptor)
400: throws IllegalAccessException,
401: IllegalArgumentException, InvocationTargetException {
402: Method write = descriptor.getWriteMethod();
403: Class type = write.getParameterTypes()[0];
404:
405: // detect the element properties
406: if (mPropertynames != null && mPropertynames.contains(name)) {
407: if (null == mPropertySetters) {
408: mPropertySetters = new LinkedHashMap<String, Method>();
409: }
410: write.setAccessible(true);
411: mPropertySetters.put(name, write);
412: }
413: // detect the element incookies and global cookies
414: else if (mNamesIncookies != null
415: && mNamesIncookies.contains(name)) {
416: if (null == mIncookieSetters) {
417: mIncookieSetters = new LinkedHashMap<String, Method>();
418: }
419: write.setAccessible(true);
420: mIncookieSetters.put(name, write);
421: }
422: // detect the element inputs and global vars
423: else if (mNamesInputs != null
424: && mNamesInputs.contains(name)) {
425: if (null == mInputSetters) {
426: mInputSetters = new LinkedHashMap<String, Method>();
427: }
428: write.setAccessible(true);
429: mInputSetters.put(name, write);
430: }
431: // detect the element named inbeans
432: else if (mNamesInbeans != null
433: && mNamesInbeans.contains(name)) {
434: if (null == mInbeanSetters) {
435: mInbeanSetters = new LinkedHashMap<String, Method>();
436: }
437: write.setAccessible(true);
438: mInbeanSetters.put(name, write);
439: } else {
440: for (Submission submission : mElementInfo
441: .getSubmissions()) {
442: if (submission.containsParameter(name)) {
443: Map<String, Method> param_setters = mSubmissionSettersCache
444: .getCachedSubmissionparamSetters(submission
445: .getName());
446: if (null == param_setters) {
447: param_setters = new LinkedHashMap<String, Method>();
448: mSubmissionSettersCache
449: .putCachedSubmissionparamSetters(
450: submission.getName(),
451: param_setters);
452: }
453: write.setAccessible(true);
454: param_setters.put(name, write);
455: } else if (submission.containsNamedBean(name)) {
456: Map<String, Method> bean_setters = mSubmissionSettersCache
457: .getCachedSubmissionbeanSetters(submission
458: .getName());
459: if (null == bean_setters) {
460: bean_setters = new LinkedHashMap<String, Method>();
461: mSubmissionSettersCache
462: .putCachedSubmissionbeanSetters(
463: submission.getName(),
464: bean_setters);
465: }
466: write.setAccessible(true);
467: bean_setters.put(name, write);
468: } else if (submission.containsFile(name)
469: && UploadedFile.class
470: .isAssignableFrom(type)) {
471: Map<String, Method> file_setters = mSubmissionSettersCache
472: .getCachedUploadedfileSetters(submission
473: .getName());
474: if (null == file_setters) {
475: file_setters = new LinkedHashMap<String, Method>();
476: mSubmissionSettersCache
477: .putCachedUploadedfileSetters(
478: submission.getName(),
479: file_setters);
480: }
481: write.setAccessible(true);
482: file_setters.put(name, write);
483: }
484: }
485: }
486:
487: return true;
488: }
489: }
490: }
|