001: package com.silvermindsoftware.hitch.handlers.component;
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.ReadOnly;
020: import com.silvermindsoftware.hitch.reflect.ClassManager;
021:
022: import java.lang.reflect.Method;
023: import java.lang.reflect.InvocationTargetException;
024: import java.lang.reflect.Field;
025: import java.util.Map;
026: import java.util.HashMap;
027: import java.beans.Introspector;
028: import java.beans.IntrospectionException;
029: import java.beans.PropertyDescriptor;
030:
031: abstract public class AbstractComponentHandler<ComponentType, ModelType, UIType>
032: implements ComponentHandler<ComponentType, ModelType, UIType> {
033:
034: private final Map<Class, Method> componentGetter = new HashMap<Class, Method>();
035: private final Map<Class, Method> componentSetter = new HashMap<Class, Method>();
036:
037: // private String getterName = null;
038: // private String setterName = null;
039: private Map<String, Method> getterMethodMap = new HashMap<String, Method>();
040: private Map<String, Field> fieldMap = new HashMap<String, Field>();
041:
042: // retrieves the getter field method for reading values from the component field
043: public Method getComponentGetter(ComponentType component) {
044:
045: Class componentClass = component.getClass();
046: Method method;
047:
048: if (this .componentGetter.containsKey(component.getClass())) {
049: method = componentGetter.get(component.getClass());
050: } else {
051: try {
052: method = ClassManager.getClassInfo(componentClass)
053: .getGetterMethod(getGetterName());
054: componentGetter.put(component.getClass(), method);
055: } catch (NoSuchMethodException e) {
056: throw new IllegalStateException("Method "
057: + getGetterName() + " not found on component "
058: + componentClass.getName());
059: }
060: }
061:
062: return method;
063: }
064:
065: // retrievesthe setter field method for setting values on the component field
066: public Method getComponentSetter(ComponentType component) {
067: Class componentClass = component.getClass();
068: Method method;
069:
070: if (this .componentSetter.containsKey(component.getClass())) {
071: method = componentSetter.get(component.getClass());
072: } else {
073: try {
074:
075: method = ClassManager
076: .getClassInfo(componentClass)
077: .getSetterMethod(
078: getSetterName(),
079: new Class[] { getSetterParameterType() });
080:
081: componentSetter.put(component.getClass(), method);
082:
083: } catch (NoSuchMethodException e) {
084: throw new IllegalStateException("Method "
085: + getSetterName() + " not found on component "
086: + componentClass.getName());
087: }
088: }
089:
090: return method;
091: }
092:
093: public boolean isPopulateHandleable(ComponentType component,
094: ModelType modelPropertyValue) {
095: return true;
096: }
097:
098: public boolean isUpdateHandleable(ComponentType component) {
099: return true;
100: }
101:
102: @SuppressWarnings("unchecked")
103: public UIType preProcessPopulate(ComponentType component,
104: ModelType modelPropertyValue) {
105: return (UIType) modelPropertyValue;
106: }
107:
108: @SuppressWarnings("unchecked")
109: public ModelType preProcessUpdate(ComponentType component,
110: UIType modelPropertyValue) {
111: return (ModelType) modelPropertyValue;
112: }
113:
114: public void postProcessPopulate(ComponentType component) {
115: }
116:
117: public void postProcessUpdate(ComponentType component) {
118: }
119:
120: abstract protected Class getSetterParameterType();
121:
122: abstract protected String getGetterName();
123:
124: abstract protected String getSetterName();
125:
126: public boolean getDefaultReadOnly() {
127: return false;
128: }
129:
130: protected Object getPropertyValue(Object object, String propertyName) {
131: Object retVal = null;
132: Method getterMethod = null;
133: boolean foundGetter;
134: boolean foundValueField = false;
135:
136: //if propertyName then reflect on object
137: if (propertyName != null) {
138:
139: Class modelClass = object.getClass();
140: String lookupKey = modelClass.getName() + propertyName;
141: // attempt to find method in getterMap
142: if (getterMethodMap.containsKey(lookupKey)) {
143: try {
144: retVal = getterMethodMap.get(lookupKey).invoke(
145: object);
146: } catch (IllegalAccessException e) {
147: // this shouldn't happen
148: throw new IllegalStateException(
149: "*** THIS SHOULD NEVER HAPPEN ***"
150: + e.getMessage(), e);
151: } catch (InvocationTargetException e) {
152: throw new IllegalStateException(e.getMessage(), e);
153: }
154: } else if (fieldMap.containsKey(lookupKey)) {
155: Field field = fieldMap.get(lookupKey);
156: try {
157: retVal = field.get(object);
158: } catch (IllegalAccessException e) {
159: // this should never happen
160: throw new IllegalStateException(
161: "*** THIS SHOULD NEVER HAPPEN ***"
162: + e.getMessage(), e);
163: }
164: } else {
165: try {
166: getterMethod = ClassManager
167: .getClassInfo(modelClass)
168: .getGetterMethod(
169: new StringBuilder()
170: .append("get")
171: .append(
172: propertyName
173: .substring(
174: 0,
175: 1)
176: .toUpperCase())
177: .append(
178: propertyName
179: .substring(1))
180: .toString());
181: foundGetter = true;
182: } catch (NoSuchMethodException e) {
183: // method does not exist
184: foundGetter = false;
185: }
186:
187: Field valueField = null;
188:
189: if (foundGetter) {
190: // use getter if it exists
191: try {
192: retVal = getterMethod.invoke(object);
193: getterMethodMap.put(lookupKey, getterMethod);
194: } catch (IllegalAccessException e) {
195: // if there is an access exception then set the getter to NOT found
196: // and lookup the field
197: foundGetter = false;
198:
199: try {
200: valueField = ClassManager.getClassInfo(
201: modelClass).getField(propertyName);
202: valueField.setAccessible(true);
203: foundValueField = true;
204: } catch (NoSuchFieldException e1) {
205: // field not found
206: foundValueField = false;
207: }
208:
209: try {
210: if (valueField != null) {
211: retVal = valueField.get(object);
212: }
213: fieldMap.put(lookupKey, valueField);
214: } catch (IllegalAccessException e1) {
215: // value field not acessible: this shouldn't happen
216: // since we make it accessible
217: throw new IllegalStateException(
218: "*** THIS SHOULD NEVER HAPPEN ***"
219: + e.getMessage(), e);
220: }
221:
222: } catch (InvocationTargetException e) {
223: // this is an exception that gets thrown from the
224: // getter method itself. We want to rethrow this
225: throw new IllegalStateException(e.getMessage(),
226: e);
227: }
228: } else {
229:
230: try {
231: valueField = ClassManager.getClassInfo(
232: modelClass).getField(propertyName);
233: valueField.setAccessible(true);
234: foundValueField = true;
235: } catch (NoSuchFieldException e) {
236: // field not found
237: foundValueField = false;
238: }
239:
240: try {
241: if (valueField != null) {
242: retVal = valueField.get(object);
243: }
244: fieldMap.put(lookupKey, valueField);
245: } catch (IllegalAccessException e) {
246: // value field not acessible: this shouldn't happen
247: // since we make it accessible
248: throw new IllegalStateException(
249: "*** THIS SHOULD NEVER HAPPEN ***"
250: + e.getMessage(), e);
251: }
252:
253: }
254:
255: if (!foundGetter && !foundValueField) {
256: throw new IllegalStateException(
257: "Getter and field for property "
258: + propertyName
259: + " not found for object "
260: + modelClass.getName());
261: }
262:
263: }
264:
265: } else {
266: //otherwise return object
267: retVal = object;
268: }
269:
270: return retVal;
271: }
272:
273: protected boolean isBaseType(Object modelPropertyValue) {
274:
275: Class modelFieldClass = modelPropertyValue.getClass();
276:
277: boolean retVal = false;
278: if (modelFieldClass == String.class) {
279: retVal = true;
280: } else if (modelFieldClass == byte.class) {
281: retVal = true;
282: } else if (modelFieldClass == short.class) {
283: retVal = true;
284: } else if (modelFieldClass == int.class) {
285: retVal = true;
286: } else if (modelFieldClass == long.class) {
287: retVal = true;
288: } else if (modelFieldClass == float.class) {
289: retVal = true;
290: } else if (modelFieldClass == double.class) {
291: retVal = true;
292: } else if (modelFieldClass == boolean.class) {
293: retVal = true;
294: } else if (modelFieldClass == char.class) {
295: retVal = true;
296: } else if (modelPropertyValue instanceof Byte) {
297: retVal = true;
298: } else if (modelPropertyValue instanceof Short) {
299: retVal = true;
300: } else if (modelPropertyValue instanceof Integer) {
301: retVal = true;
302: } else if (modelPropertyValue instanceof Long) {
303: retVal = true;
304: } else if (modelPropertyValue instanceof Float) {
305: retVal = true;
306: } else if (modelPropertyValue instanceof Double) {
307: retVal = true;
308: } else if (modelPropertyValue instanceof Boolean) {
309: retVal = true;
310: } else if (modelPropertyValue instanceof Character) {
311: retVal = true;
312: }
313:
314: return retVal;
315: }
316: }
|