001: package com.silvermindsoftware.hitch;
002:
003: /**
004: * Copyright 2007 Brandon Goodin
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import com.silvermindsoftware.hitch.handlers.ComponentHandlerFactory;
020: import com.silvermindsoftware.hitch.handlers.TypeHandlerFactory;
021: import com.silvermindsoftware.hitch.handlers.component.ComponentHandler;
022: import com.silvermindsoftware.hitch.handlers.type.TypeHandler;
023: import com.silvermindsoftware.hitch.handlers.type.UnknownTypeHandler;
024: import com.silvermindsoftware.hitch.meta.ComponentMeta;
025: import com.silvermindsoftware.hitch.meta.FormMeta;
026: import com.silvermindsoftware.hitch.meta.ModelMeta;
027: import com.silvermindsoftware.hitch.reflect.ClassInfo;
028: import com.silvermindsoftware.hitch.reflect.ClassManager;
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031:
032: import javax.swing.*;
033: import java.awt.*;
034: import java.lang.reflect.Field;
035: import java.lang.reflect.InvocationTargetException;
036: import java.lang.reflect.Method;
037: import java.util.Arrays;
038: import java.util.Iterator;
039: import java.util.Map;
040: import java.util.Set;
041:
042: /**
043: * This class contains all of the code used to updateModel/populateForm between
044: * Swing components and model objects (Object reflection/Type Handlers).
045: */
046: public class BinderImpl extends AbstractBinder implements Binder {
047:
048: private static final Log log = LogFactory.getLog(BinderImpl.class);
049:
050: private static final ComponentHandlerFactory COMPONENT_HANDLER_FACTORY = new ComponentHandlerFactory();
051: private static final TypeHandlerFactory TYPE_HANDLER_FACTORY = new TypeHandlerFactory();
052: private static final TypeHandler unknownTypeHandler = new UnknownTypeHandler();
053:
054: public void updateModel(Container container, String... modelId) {
055:
056: FormMeta formMeta = getFormMeta(container.getClass());
057:
058: for (Iterator<ComponentMeta> it = formMeta
059: .getComponentMetaIterator(); it.hasNext();) {
060: ComponentMeta componentMeta = it.next();
061: // check to see if update should occur for particular model objects
062: if (modelId != null && modelId.length > 0) {
063:
064: Arrays.sort(modelId);
065:
066: if (Arrays.binarySearch(modelId, componentMeta
067: .getModelId()) < 0) {
068: continue;
069: }
070: }
071:
072: // get container field
073: Field componentField = componentMeta.getComponentField();
074:
075: // get model object
076: ModelMeta modelMeta = formMeta.getModelMeta(componentMeta
077: .getModelId());
078: Field modelField = modelMeta.getModelField();
079: Object modelObject = null;
080: try {
081: modelObject = modelField.get(container);
082: } catch (IllegalAccessException e) {
083: throw new RuntimeException("IllegalAccessException: "
084: + e.getMessage()
085: + "occured while retrieving model field "
086: + modelField.getName() + " of type "
087: + modelField.getType(), e);
088: }
089:
090: // get form container
091: JComponent formComponent = null;
092: try {
093: formComponent = (JComponent) componentField
094: .get(container);
095: } catch (IllegalAccessException e) {
096: throw new RuntimeException("IllegalAccessException: "
097: + e.getMessage()
098: + "occured while retrieving component field "
099: + componentField.getName() + " of type "
100: + componentField.getType(), e);
101: }
102:
103: ComponentHandler componentHandler = getComponentHandler(
104: componentMeta, container, formComponent);
105:
106: boolean readOnly = false;
107: if (componentMeta.getReadOnly() == ReadOnly.DEFAULT) {
108: readOnly = componentHandler.getDefaultReadOnly();
109: } else if (componentMeta.getReadOnly() == ReadOnly.TRUE) {
110: readOnly = true;
111: }
112:
113: if (!readOnly) {
114:
115: if (componentHandler.isUpdateHandleable(formComponent)) {
116: Object formComponentValue = null;
117:
118: Method getter = componentHandler
119: .getComponentGetter(formComponent);
120:
121: try {
122: // convert value and get
123: formComponentValue = getter
124: .invoke(formComponent);
125: } catch (IllegalAccessException e) {
126: throw new RuntimeException(
127: "IllegalAccessException: "
128: + e.getMessage()
129: + "occured while retrieving form component value from "
130: + componentField.getName()
131: + " of type "
132: + componentField.getType()
133: + " using " + getter.getName(),
134: e);
135: } catch (InvocationTargetException e) {
136: throw new RuntimeException(
137: "InvocationTargetException: "
138: + e.getMessage()
139: + "occured while retrieving form component value from "
140: + componentField.getName()
141: + " of type "
142: + componentField.getType()
143: + " using " + getter.getName(),
144: e);
145: }
146:
147: //retrieve type handler and convert to compatible type
148:
149: if (componentMeta.isModelSetter()) {
150: try {
151: if (Map.class
152: .isAssignableFrom(componentMeta
153: .getModelType())) {
154: componentMeta
155: .getModelSetter()
156: .invoke(
157: modelObject,
158: componentMeta
159: .getModelPropertyName(),
160: convert(
161: componentHandler
162: .preProcessUpdate(
163: formComponent,
164: formComponentValue),
165: componentMeta
166: .getModelPropertyType()));
167:
168: } else {
169: componentMeta
170: .getModelSetter()
171: .invoke(
172: modelObject,
173: convert(
174: componentHandler
175: .preProcessUpdate(
176: formComponent,
177: formComponentValue),
178: componentMeta
179: .getModelPropertyType()));
180: }
181:
182: } catch (IllegalAccessException e) {
183: throw new RuntimeException(
184: "IllegalAccessException: "
185: + e.getMessage()
186: + " occurred while setting value "
187: + formComponentValue
188: + " on "
189: + modelObject
190: + " with "
191: + componentMeta
192: .getModelSetter()
193: .getName(), e);
194: } catch (InvocationTargetException e) {
195: throw new RuntimeException(
196: "RuntimeException: "
197: + e.getMessage()
198: + " occurred while setting value "
199: + formComponentValue
200: + " on "
201: + modelObject
202: + " with "
203: + componentMeta
204: .getModelSetter()
205: .getName(), e);
206: } catch (Exception e) {
207: throw new RuntimeException("Exception: "
208: + e.getMessage()
209: + " occurred while setting value "
210: + formComponentValue
211: + " on "
212: + modelObject
213: + " with "
214: + componentMeta.getModelSetter()
215: .getName(), e);
216: }
217: } else {
218: try {
219: componentMeta
220: .getModelField()
221: .set(
222: modelObject,
223: convert(
224: componentHandler
225: .preProcessUpdate(
226: formComponent,
227: formComponentValue),
228: componentMeta
229: .getModelField()
230: .getType()));
231: } catch (IllegalAccessException e) {
232: throw new RuntimeException(
233: "IllegalAccessException: "
234: + e.getMessage()
235: + " occurred while setting value "
236: + formComponentValue
237: + " on "
238: + modelObject
239: + " to field "
240: + componentMeta
241: .getModelField()
242: .getName(), e);
243: } catch (Exception e) {
244: throw new RuntimeException("Exception: "
245: + e.getMessage()
246: + " occurred while setting value "
247: + formComponentValue
248: + " on "
249: + modelObject
250: + " to field "
251: + componentMeta.getModelField()
252: .getName(), e);
253: }
254: }
255:
256: componentHandler.postProcessUpdate(formComponent);
257: }
258: }
259:
260: }
261:
262: }
263:
264: public void populateForm(Container container, String... modelId) {
265:
266: FormMeta formMeta = getFormMeta(container.getClass());
267:
268: for (Iterator<ComponentMeta> it = formMeta
269: .getComponentMetaIterator(); it.hasNext();) {
270: ComponentMeta componentMeta = it.next();
271:
272: // check to see if update should occur for particular model objects
273: if (modelId != null && modelId.length > 0) {
274:
275: Arrays.sort(modelId);
276:
277: if (Arrays.binarySearch(modelId, componentMeta
278: .getModelId()) < 0) {
279: continue;
280: }
281: }
282:
283: // get container field
284: Field componentField = componentMeta.getComponentField();
285:
286: // get model values
287: ModelMeta modelMeta = formMeta.getModelMeta(componentMeta
288: .getModelId());
289: Field modelField = modelMeta.getModelField();
290: Object modelObject = null;
291: try {
292: modelObject = modelField.get(container);
293: } catch (IllegalAccessException e) {
294: throw new RuntimeException(e.getMessage(), e);
295: }
296:
297: Object modelFieldValue = null;
298:
299: if (componentMeta.isModelGetter()) {
300: try {
301: if (Map.class.isAssignableFrom(componentMeta
302: .getModelType())) {
303: ClassInfo modelClassInfo = ClassManager
304: .getClassInfo(componentMeta
305: .getModelType());
306: Method keySetMethod = null;
307: try {
308: keySetMethod = modelClassInfo.getMethod(
309: "keySet", new Class[] {});
310: } catch (NoSuchMethodException e) {
311: log.error(e.getMessage(), e);
312: throw new RuntimeException(e.getMessage(),
313: e);
314: }
315:
316: Set<String> keySet = (Set) keySetMethod
317: .invoke(modelObject);
318:
319: for (String key : keySet) {
320: if (componentMeta.getModelPropertyName()
321: .equalsIgnoreCase(key)) {
322: modelFieldValue = componentMeta
323: .getModelGetter().invoke(
324: modelObject, key);
325: break;
326: }
327: }
328:
329: } else {
330: modelFieldValue = componentMeta
331: .getModelGetter().invoke(modelObject);
332: }
333: } catch (IllegalAccessException e) {
334: throw new RuntimeException(e.getMessage(), e);
335: } catch (InvocationTargetException e) {
336: throw new RuntimeException(e.getMessage(), e);
337: }
338: } else {
339: try {
340: modelFieldValue = componentMeta.getModelField()
341: .get(modelObject);
342: } catch (IllegalAccessException e) {
343: throw new RuntimeException(e.getMessage(), e);
344: }
345: }
346:
347: JComponent formComponent = null;
348:
349: try {
350: formComponent = (JComponent) componentField
351: .get(container);
352: } catch (IllegalAccessException e) {
353: throw new IllegalStateException(e.getMessage(), e);
354: }
355:
356: if (formComponent == null) {
357: throw new IllegalStateException("Form container named "
358: + componentField.getName() + " was not found");
359: }
360:
361: ComponentHandler componentHandler = getComponentHandler(
362: componentMeta, container, formComponent);
363:
364: if (componentHandler.isPopulateHandleable(formComponent,
365: modelFieldValue)) {
366:
367: Method setter = componentHandler
368: .getComponentSetter(formComponent);
369:
370: try {
371: ErrorContext.put("- Error occured when setting "
372: + setter.getName() + " on "
373: + componentField.getName());
374:
375: Object convertedValue = convert(componentHandler
376: .preProcessPopulate(formComponent,
377: modelFieldValue), setter
378: .getParameterTypes()[0]);
379:
380: setter.invoke(formComponent, convertedValue);
381:
382: } catch (IllegalAccessException e) {
383: throw new RuntimeException("IllegalAccessException"
384: + ErrorContext.getAsString(), e);
385: } catch (InvocationTargetException e) {
386: throw new RuntimeException(
387: "InvocationTargetException"
388: + ErrorContext.getAsString()
389: .toString(), e);
390: } finally {
391: ErrorContext.clear();
392: }
393:
394: componentHandler.postProcessPopulate(formComponent);
395: }
396: }
397: }
398:
399: private ComponentHandler getComponentHandler(
400: ComponentMeta componentMeta, Container container,
401: JComponent formComponent) {
402: ComponentHandler componentHandler;// attempt to retrieve container handler if custom is defined
403: if (componentMeta.getComponentHandler() != null) {
404: componentHandler = getCustomComponentHandler(container,
405: componentMeta);
406:
407: } else {
408:
409: componentHandler = COMPONENT_HANDLER_FACTORY
410: .getHandler(formComponent.getClass());
411: }
412: return componentHandler;
413: }
414:
415: private ComponentHandler getCustomComponentHandler(
416: Container container, ComponentMeta componentMeta) {
417: ComponentHandler componentHandler;
418: String key = container.getClass().getName()
419: + componentMeta.getComponentField().getName();
420: //if not create and popoulate properties and add to container handler
421: componentHandler = COMPONENT_HANDLER_FACTORY.getHandler(key);
422:
423: if (componentHandler == null) {
424: try {
425: if (componentMeta.getComponentHandler() == void.class) {
426: Class componentFieldClass = componentMeta
427: .getComponentField().getType();
428: componentHandler = (ComponentHandler) COMPONENT_HANDLER_FACTORY
429: .getHandlerType(componentFieldClass)
430: .newInstance();
431: } else {
432: componentHandler = (ComponentHandler) componentMeta
433: .getComponentHandler().newInstance();
434: }
435: } catch (InstantiationException e) {
436: throw new IllegalStateException(e.getMessage(), e);
437: } catch (IllegalAccessException e) {
438: throw new IllegalStateException(e.getMessage(), e);
439: }
440:
441: if (componentMeta.getHandlerValues() != null) {
442: for (String propertyValue : componentMeta
443: .getHandlerValues()) {
444: if (propertyValue.length() > 0) {
445: String[] split = propertyValue.split("=");
446: String name = split[0];
447: String value = split[1];
448: Class componentHandlerClass = componentHandler
449: .getClass();
450: try {
451:
452: Method method = ClassManager
453: .getClassInfo(componentHandlerClass)
454: .getSetterMethod(
455: "set"
456: + name
457: .substring(
458: 0,
459: 1)
460: .toUpperCase()
461: + name.substring(1),
462: new Class[] { String.class });
463:
464: method.invoke(componentHandler, value);
465:
466: } catch (NoSuchMethodException e) {
467: throw new IllegalStateException(e
468: .getMessage(), e);
469: } catch (IllegalAccessException e) {
470: throw new IllegalStateException(e
471: .getMessage(), e);
472: } catch (InvocationTargetException e) {
473: throw new IllegalStateException(e
474: .getMessage(), e);
475: }
476: }
477: }
478: }
479:
480: COMPONENT_HANDLER_FACTORY.register(key, componentHandler);
481: }
482: return componentHandler;
483: }
484:
485: public void addComponentHandler(Class componentClass,
486: String fieldName, Class componentHandlerClass,
487: String... properties) {
488:
489: String componentHandlerKey = componentClass.getName()
490: + fieldName;
491:
492: ComponentHandler componentHandler;
493: try {
494: componentHandler = (ComponentHandler) componentHandlerClass
495: .newInstance();
496: } catch (InstantiationException e) {
497: throw new IllegalStateException("Failed to instantiate "
498: + componentHandlerClass.getName(), e);
499: } catch (IllegalAccessException e) {
500: throw new IllegalStateException(
501: "Could not access default constructor on "
502: + componentHandlerClass.getName(), e);
503: }
504:
505: COMPONENT_HANDLER_FACTORY.register(componentHandlerKey,
506: componentHandler);
507: }
508:
509: public Object convert(Object value, Class toType) {
510: Object retVal;
511: TypeHandler typeHandler = TYPE_HANDLER_FACTORY
512: .getHandler(toType);
513: if (typeHandler == null)
514: retVal = unknownTypeHandler.convert(value);
515: else
516: retVal = typeHandler.convert(value);
517: return retVal;
518: }
519: }
|