001: package com.completex.objective.components.persistency.mapper.impl;
002:
003: import com.completex.objective.components.log.Log;
004: import com.completex.objective.components.persistency.OdalRuntimePersistencyException;
005: import com.completex.objective.components.persistency.mapper.*;
006: import com.completex.objective.components.persistency.type.TracingCollection;
007: import com.completex.objective.tools.generators.NameHelper;
008:
009: import java.beans.BeanInfo;
010: import java.beans.IntrospectionException;
011: import java.beans.Introspector;
012: import java.beans.PropertyDescriptor;
013: import java.lang.reflect.InvocationTargetException;
014: import java.lang.reflect.Method;
015: import java.util.Collection;
016: import java.util.HashMap;
017: import java.util.HashSet;
018: import java.util.Iterator;
019: import java.util.LinkedHashSet;
020:
021: /**
022: * @author Gennady Krizhevsky
023: */
024: public abstract class BasicDynamicMapperImpl implements
025: ParentValueHandler, MapperRegistry {
026:
027: private Log logger = Log.NULL_LOGGER;
028:
029: // private HashMap directMap = new HashMap(); /* HashMap<Class poClass, Class beanClass> */
030: // private HashMap inversedMap = new HashMap(); /* HashMap<Class beanClass, Class poClass> */
031:
032: private HashMap mappingHandlers = new HashMap();
033: private HashMap valueHandlers = new HashMap();
034:
035: private boolean notOverwriteWithNulls;
036:
037: private Mapper mapper;
038:
039: private MapperRegistryImpl mapperRegistry = new MapperRegistryImpl();
040:
041: protected BasicDynamicMapperImpl(Mapper mapper) {
042: this .mapper = mapper;
043: }
044:
045: public void map(Class poClass, Class beanClass) {
046: mapperRegistry.map(poClass, beanClass);
047: }
048:
049: protected void remap(Class poClass, Class beanClass) {
050: mapperRegistry.remap(poClass, beanClass);
051: }
052:
053: public void registerMappingHandler(Class poClass, Class beanClass,
054: MappingHandler mappingHandler) {
055: if (mappingHandler != null) {
056: mappingHandlers.put(new MappingHandler.Key(beanClass,
057: poClass), mappingHandler);
058: }
059: }
060:
061: public void registerValueHandler(String valuePath,
062: ValueHandler valueHandler) {
063: MapperKey key = new MapperKey(valuePath);
064: valueHandlers.put(key, valueHandler);
065: }
066:
067: public MappingHandler getMappingHandler(Class beanClass,
068: Class poClass) {
069: return (MappingHandler) mappingHandlers
070: .get(new MappingHandler.Key(beanClass, poClass));
071: }
072:
073: public ValueHandler getValueHandler(String valuePath) {
074: MapperKey key = new MapperKey(valuePath);
075: return (ValueHandler) valueHandlers.get(key);
076: }
077:
078: public Class getDirectBeanClass(Class poClass) {
079: return mapperRegistry.getDirectBeanClass(poClass);
080: }
081:
082: public Class getInversetBeanClass(Class poClass) {
083: return mapperRegistry.getInversetBeanClass(poClass);
084: }
085:
086: public boolean mappingExists(Class poClass, Class beanClass) {
087: return mapperRegistry.mappingExists(poClass, beanClass);
088: }
089:
090: protected Class getBeanClassSafe(Class poClass) {
091: Class beanClass = getDirectBeanClass(poClass);
092: if (beanClass == null) {
093: throw new OdalMappingRuntimeException(
094: "Cannot find mapped bean class by PersistentObject class "
095: + poClass);
096: }
097: return beanClass;
098: }
099:
100: public final Object convert(Object po, boolean forModification) {
101: return convert(null, po, forModification);
102: }
103:
104: protected final Object convert(String valuePath, Object po,
105: boolean forModification) {
106: if (po == null) {
107: return null;
108: }
109: Object preConvertedPo = doPreConvert(valuePath, po,
110: forModification);
111: Object bean = doConvert(valuePath, preConvertedPo,
112: forModification);
113: bean = doPostConvert(valuePath, preConvertedPo, bean,
114: forModification);
115: return bean;
116: }
117:
118: protected Object doPreConvert(String valuePath, Object po,
119: boolean forModification) {
120: return po;
121: }
122:
123: protected Object doPostConvert(String valuePath, Object po,
124: Object bean, boolean forModification) {
125: return bean;
126: }
127:
128: protected Object doConvert(String valuePath, Object clonedPo,
129: boolean forModification) {
130: RequestContext context = new RequestContext();
131: return toBean0(valuePath, clonedPo, context, forModification);
132: }
133:
134: protected Object toBean0(String valuePath, Object po,
135: RequestContext context, boolean forModification) {
136: Class poClass = po.getClass();
137: Class beanClass = getBeanClassSafe(poClass);
138:
139: MappingHandler mappingHandler = getMappingHandler(beanClass,
140: poClass);
141:
142: BeanInfo poInfo = null;
143: BeanInfo beanInfo = null;
144: if (mappingHandler == null) {
145: try {
146: poInfo = Introspector.getBeanInfo(poClass);
147: beanInfo = Introspector.getBeanInfo(beanClass);
148: } catch (IntrospectionException e) {
149: throw new OdalMappingRuntimeException(e);
150: }
151: }
152:
153: Object bean = objectNewInstance(beanClass, po, forModification);
154:
155: if (mappingHandler == null) {
156: return doConvertToBean(valuePath, poInfo, beanInfo, po,
157: bean, context, forModification);
158: } else {
159: return mappingHandler.convert(valuePath, context);
160: }
161: }
162:
163: protected Object doConvertToBean(String valuePath, BeanInfo poInfo,
164: BeanInfo beanInfo, Object po, Object bean,
165: RequestContext context, boolean forModification) {
166: PropertyDescriptor[] poDescriptors = poInfo
167: .getPropertyDescriptors();
168: PropertyDescriptor[] beanDescriptors = beanInfo
169: .getPropertyDescriptors();
170: for (int i = 0; i < poDescriptors.length; i++) {
171: PropertyDescriptor poDescriptor = null;
172: String name = null;
173: String childValuePath = null;
174: try {
175: poDescriptor = poDescriptors[i];
176: name = poDescriptor.getName();
177: if (!"class".equals(name)) {
178: childValuePath = addValuePath(valuePath, po,
179: poDescriptor.getName());
180: if ("com.completex.objective.components.persistency.test.oracle.gen.bean.TestMasterBean#slaves"
181: .equals(childValuePath)) {
182: int k = 0;
183: }
184:
185: context.setParentBean(bean);
186: assignValueCtl(childValuePath, context, bean,
187: beanDescriptors, po, poDescriptor,
188: forModification);
189: }
190: } catch (Exception e) {
191: throw new OdalMappingRuntimeException(
192: "Cannot doConvertToBean: poDescriptor: " + name
193: + "; childValuePath = "
194: + childValuePath, e);
195: }
196: }
197: return bean;
198: }
199:
200: protected void assignValueCtl(String childValuePath,
201: RequestContext context, Object currentBean,
202: PropertyDescriptor[] currentBeanDescriptors,
203: Object currentPo, PropertyDescriptor currentPoDescriptor,
204: boolean forModification) {
205: getLogger().debug(
206: "assignValue: childValuePath = " + childValuePath);
207:
208: boolean found;
209: ValueHandler valueHandler = getValueHandler(childValuePath);
210: if (valueHandler != null) {
211: valueHandler.assignValue(childValuePath, context,
212: currentBean, currentBeanDescriptors, currentPo,
213: currentPoDescriptor, this , forModification);
214: found = true;
215: } else {
216: found = assignValue(childValuePath, context, currentBean,
217: currentBeanDescriptors, currentPo,
218: currentPoDescriptor, forModification);
219: }
220: printNonFound(found, currentPoDescriptor, childValuePath);
221: }
222:
223: public boolean assignValue(String valuePath,
224: RequestContext context, Object currentBean,
225: PropertyDescriptor[] currentBeanDescriptors,
226: Object currentPo, PropertyDescriptor currentPoDescriptor,
227: boolean forModification) {
228: try {
229: boolean found = false;
230: String poFieldName = currentPoDescriptor.getName();
231: String beanPredictedSetterName = "set"
232: + NameHelper.capitalizeField(poFieldName);
233: Method poReadMethod = currentPoDescriptor.getReadMethod();
234: if (poReadMethod != null) {
235: found = processBean(poReadMethod,
236: beanPredictedSetterName, context, valuePath,
237: currentBean, currentBeanDescriptors, currentPo,
238: currentPoDescriptor, forModification);
239:
240: }
241: return found;
242: } catch (Exception e) {
243: throw new OdalMappingRuntimeException(
244: "Error at valuePath : " + valuePath, e);
245: }
246: }
247:
248: private void printNonFound(boolean found,
249: PropertyDescriptor currentPoDescriptor, String valuePath) {
250: if (!found) {
251: Method poReadMethod = currentPoDescriptor.getReadMethod();
252: getLogger().debug(
253: "Did not find setter for property name "
254: + currentPoDescriptor.getName()
255: + " with read method "
256: + poReadMethod.getName()
257: + "], valuePath = " + valuePath);
258:
259: }
260: }
261:
262: protected boolean processBean(Method poReadMethod,
263: String beanPredictedSetterName, RequestContext context,
264: String valuePath, Object currentBean,
265: PropertyDescriptor[] currentBeanDescriptors,
266: Object currentPo, PropertyDescriptor currentPoDescriptor,
267: boolean forModification) throws IntrospectionException,
268: IllegalAccessException, InvocationTargetException,
269: CloneNotSupportedException {
270:
271: if (valuePath != null && context.isSeen(valuePath)) {
272: getLogger().debug("processBean : seen path : " + valuePath);
273: return false;
274: }
275: context.addToSeen(valuePath);
276:
277: Object poReturnValue = extractPropertyValue(poReadMethod,
278: currentPo);
279: boolean found = false;
280:
281: for (int j = 0; j < currentBeanDescriptors.length; j++) {
282: try {
283: if (j == 15) {
284: int k = 0;
285: }
286: PropertyDescriptor beanDescriptor = currentBeanDescriptors[j];
287: Method beanWriteMethod = beanDescriptor
288: .getWriteMethod();
289: Method beanReadMethod = beanDescriptor.getReadMethod();
290: if (poReturnValue instanceof Collection) {
291: found = processCollection(beanReadMethod,
292: poReadMethod, currentBean, poReturnValue,
293: valuePath, context, forModification);
294: } else {
295: found = processNonCollection(beanWriteMethod,
296: beanPredictedSetterName, poReadMethod,
297: poReturnValue, currentBean, valuePath,
298: context, forModification);
299: }
300: if (found) {
301: break;
302: }
303: } catch (IllegalAccessException e) {
304: System.err.println("Error in processBean at j = " + j);
305: throw e;
306: } catch (InvocationTargetException e) {
307: System.err.println("Error in processBean at j = " + j);
308: throw e;
309: }
310: }
311: return found;
312: }
313:
314: protected boolean processNonCollection(Method beanWriteMethod,
315: String beanPredictedSetterName, Method poReadMethod,
316: Object poReturnValue, Object currentBean, String valuePath,
317: RequestContext context, boolean forModification)
318: throws IllegalAccessException, InvocationTargetException {
319: boolean found = false;
320: if (beanWriteMethod != null
321: && beanPredictedSetterName.equals(beanWriteMethod
322: .getName())) {
323: Class[] beanParamTypes = beanWriteMethod
324: .getParameterTypes();
325: Class poReturnType = poReadMethod.getReturnType();
326: // getLogger().debug("Found setter " + beanWriteMethod.getName() + " for property name " + poDescriptor.getName());
327: Class beanParamType = beanParamTypes[0];
328: if (beanParamType.isAssignableFrom(poReturnType)) {
329: // Assume this is a leaf:
330: // getLogger().debug("Found setter for leaf " + poDescriptor.getName()
331: // + "; beanParamType = " + beanParamType + "; poReturnType = " + poReturnType);
332: if (!(poReturnValue == null && notOverwriteWithNulls)) {
333: beanWriteMethod.invoke(currentBean,
334: new Object[] { poReturnValue });
335: }
336: found = true;
337: } else if (poReturnValue != null) {
338: Object value = processPo(poReturnValue, valuePath,
339: context, forModification);
340: beanWriteMethod.invoke(currentBean,
341: new Object[] { value });
342: found = true;
343: }
344: }
345: return found;
346: }
347:
348: protected boolean processCollection(Method beanReadMethod,
349: Method poReadMethod, Object currentBean,
350: Object poReturnValue, String valuePath,
351: RequestContext context, boolean forModification)
352: throws IllegalAccessException, InvocationTargetException {
353: boolean found = false;
354: if (beanReadMethod != null
355: && beanReadMethod.getName().equals(
356: poReadMethod.getName())) {
357: try {
358: Object beanPropertyValue = extractPropertyValue(
359: beanReadMethod, currentBean);
360: if (beanPropertyValue instanceof Collection) {
361: Collection nestedCollection = (Collection) poReturnValue;
362: Collection beanCollection = (Collection) beanPropertyValue;
363: processCollection(beanCollection, nestedCollection,
364: valuePath, context, forModification);
365: }
366: } catch (RuntimeException e) {
367: System.err
368: .println("Error in processCollection: beanReadMethod.getName(): "
369: + beanReadMethod.getName());
370: throw e;
371: }
372: found = true;
373: }
374: return found;
375: }
376:
377: public static Object extractPropertyValue(Method beanReadMethod,
378: Object currentBean) {
379: try {
380: return beanReadMethod.invoke(currentBean, null);
381: } catch (IllegalAccessException e) {
382: throw new OdalRuntimePersistencyException(
383: "Cannot extract Property Value because of IllegalAccessException: "
384: + e.getMessage());
385: } catch (InvocationTargetException e) {
386: throw new OdalRuntimePersistencyException(
387: "Cannot extract Property Value because of IllegalAccessException: "
388: + e.getMessage());
389: }
390: }
391:
392: private void processCollection(Collection beanCollection,
393: Collection nestedCollection, String valuePath,
394: RequestContext context, boolean forModification) {
395: getLogger().debug("---- Nested collection begin ----");
396: int index = 0;
397:
398: if (nestedCollection != null && !nestedCollection.isEmpty()) {
399: if (forModification
400: && beanCollection instanceof TracingCollection) {
401: getLogger().debug(
402: "forModification && beanCollection instanceof TracingCollection of size "
403: + nestedCollection.size()
404: + ": valuePath = " + valuePath);
405: LinkedHashSet temp = new LinkedHashSet(nestedCollection
406: .size());
407: for (Iterator iterator = nestedCollection.iterator(); iterator
408: .hasNext(); index++) {
409: Object value = iterator.next();
410: String collValuePath = addValuePath(valuePath,
411: index);
412: Object childBean = processPo(value, collValuePath,
413: context, forModification);
414: temp.add(childBean);
415: }
416: TracingCollection tracingCollection = (TracingCollection) beanCollection;
417: tracingCollection.trace(temp);
418: temp.clear();
419: } else {
420: HashSet seen = new HashSet(beanCollection);
421: for (Iterator iterator = nestedCollection.iterator(); iterator
422: .hasNext(); index++) {
423: Object value = iterator.next();
424: String collValuePath = addValuePath(valuePath,
425: index);
426: Object childBean = processPo(value, collValuePath,
427: context, forModification);
428: if (!seen.contains(childBean)) {
429: beanCollection.add(childBean);
430: }
431: }
432: seen.clear();
433: }
434: }
435: getLogger().debug("---- Nested collection end ----");
436: }
437:
438: private Object processPo(Object nestedPo, String valuePath,
439: RequestContext context, boolean forModification) {
440: getLogger().debug("---- Nested po begin ----");
441: Object value = toBean0(valuePath, nestedPo, context,
442: forModification);
443: getLogger().debug("---- Nested po end ----");
444: return value;
445: }
446:
447: protected Object objectNewInstance(Class beanClass,
448: Object fromObject, boolean forModification) {
449: return objectNewInstance(beanClass);
450: }
451:
452: protected Object objectNewInstance(Class beanClass) {
453: Object bean;
454: try {
455: bean = beanClass.newInstance();
456: } catch (InstantiationException e) {
457: throw new OdalRuntimePersistencyException(
458: "InstantiationException: of " + beanClass + "; "
459: + e.getMessage());
460: } catch (IllegalAccessException e) {
461: throw new OdalRuntimePersistencyException(
462: "IllegalAccessException: to " + beanClass + "; "
463: + e.getMessage());
464: }
465: return bean;
466: }
467:
468: protected String addValuePath(String valuePath, Object po,
469: String poFieldName) {
470: valuePath = valuePath == null ? po.getClass().getName() + "#"
471: + poFieldName : valuePath + "." + poFieldName;
472: return valuePath;
473: }
474:
475: protected String addValuePath(String valuePath, int index) {
476: return valuePath + "[" + index + "]";
477: }
478:
479: public Log getLogger() {
480: return logger;
481: }
482:
483: public void setLogger(Log logger) {
484: if (logger != null) {
485: this .logger = logger;
486: }
487: }
488:
489: public boolean isNotOverwriteWithNulls() {
490: return notOverwriteWithNulls;
491: }
492:
493: public void setNotOverwriteWithNulls(boolean notOverwriteWithNulls) {
494: this .notOverwriteWithNulls = notOverwriteWithNulls;
495: }
496:
497: public Mapper getMapper() {
498: return mapper;
499: }
500:
501: }
|