KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > cmp > jdbc > JDBCTypeFactory


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.ejb.plugins.cmp.jdbc;
23
24 import java.lang.reflect.Method JavaDoc;
25 import java.lang.reflect.Array JavaDoc;
26 import java.lang.reflect.Constructor JavaDoc;
27
28 import java.util.ArrayList JavaDoc;
29 import java.util.Collection JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Set JavaDoc;
35
36 import javax.ejb.EJBException JavaDoc;
37
38 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData;
39 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldPropertyMetaData;
40 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCTypeMappingMetaData;
41 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCValueClassMetaData;
42 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCValuePropertyMetaData;
43 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCUserTypeMappingMetaData;
44 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCMappingMetaData;
45 import org.jboss.deployment.DeploymentException;
46 //import org.jboss.logging.Logger;
47

48 /**
49  * JDBCTypeFactory mapps Java Classes to JDBCType objects. The main job of
50  * this class is to flatten the JDBCValueClassMetaData into columns.
51  *
52  * @author <a HREF="mailto:dain@daingroup.com">Dain Sundstrom</a>
53  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
54  * @version $Revision: 41537 $
55  */

56 public final class JDBCTypeFactory
57 {
58    //private static final Logger log = Logger.getLogger(JDBCTypeFactory.class);
59

60    //
61
// Default CMPFieldStateFactory implementations
62
//
63

64    /**
65     * This implementation uses field's value as its state.
66     */

67    public static final CMPFieldStateFactory EQUALS = new CMPFieldStateFactory()
68    {
69       public Object JavaDoc getFieldState(Object JavaDoc fieldValue)
70       {
71          return fieldValue;
72       }
73
74       public boolean isStateValid(Object JavaDoc state, Object JavaDoc fieldValue)
75       {
76          return state == null ? fieldValue == null : state.equals(fieldValue);
77       }
78    };
79
80    /**
81     * This implementation will always suppose that the state is invalid unless
82     * both states are null.
83     */

84    private static final CMPFieldStateFactory INVALID_UNLESS_NULL = new CMPFieldStateFactory()
85    {
86       public Object JavaDoc getFieldState(Object JavaDoc fieldValue)
87       {
88          return fieldValue;
89       }
90
91       public boolean isStateValid(Object JavaDoc state, Object JavaDoc fieldValue)
92       {
93          return state == null ? fieldValue == null : false;
94       }
95    };
96
97    /**
98     * Field state factory for java.util.Map implementations. The state is
99     * a deep copy of the value.
100     */

101    private static final CMPFieldStateFactory MAP = new CMPFieldStateFactory()
102    {
103       public Object JavaDoc getFieldState(Object JavaDoc fieldValue)
104       {
105          return cloneValue(fieldValue, Map JavaDoc.class);
106       }
107
108       public boolean isStateValid(Object JavaDoc state, Object JavaDoc fieldValue)
109       {
110          return (state == null ? fieldValue == null : state.equals(fieldValue));
111       }
112    };
113
114    /**
115     * Field state factory for java.util.List implementations. The state is
116     * a deep copy of the value.
117     */

118    private static final CMPFieldStateFactory LIST = new CMPFieldStateFactory()
119    {
120       public Object JavaDoc getFieldState(Object JavaDoc fieldValue)
121       {
122          return cloneValue(fieldValue, Collection JavaDoc.class);
123       }
124
125       public boolean isStateValid(Object JavaDoc state, Object JavaDoc fieldValue)
126       {
127          return (state == null ? fieldValue == null : state.equals(fieldValue));
128       }
129    };
130
131    /**
132     * Field state factory for java.util.Set implementations. The state is
133     * a deep copy of the value.
134     */

135    private static final CMPFieldStateFactory SET = new CMPFieldStateFactory()
136    {
137       public Object JavaDoc getFieldState(Object JavaDoc fieldValue)
138       {
139          return cloneValue(fieldValue, Collection JavaDoc.class);
140       }
141
142       public boolean isStateValid(Object JavaDoc state, Object JavaDoc fieldValue)
143       {
144          return (state == null ? fieldValue == null : state.equals(fieldValue));
145       }
146    };
147
148    /**
149     * Field state factory for arrays. The state is a deep copy of the value.
150     */

151    private static final CMPFieldStateFactory ARRAY = new CMPFieldStateFactory()
152    {
153       public Object JavaDoc getFieldState(Object JavaDoc fieldValue)
154       {
155          Object JavaDoc state = null;
156          if(fieldValue != null)
157          {
158             int length = Array.getLength(fieldValue);
159             state = Array.newInstance(fieldValue.getClass().getComponentType(), length);
160             System.arraycopy(fieldValue, 0, state, 0, length);
161          }
162          return state;
163       }
164
165       public boolean isStateValid(Object JavaDoc state, Object JavaDoc fieldValue)
166       {
167          boolean valid;
168          if(state == null)
169          {
170             valid = fieldValue == null;
171          }
172          else
173          {
174             if(fieldValue == null)
175             {
176                valid = false;
177             }
178             else
179             {
180                int stateLength = Array.getLength(state);
181                if(stateLength != Array.getLength(fieldValue))
182                {
183                   valid = false;
184                }
185                else
186                {
187                   valid = true;
188                   for(int i = 0; i < stateLength; ++i)
189                   {
190                      Object JavaDoc stateEl = Array.get(state, i);
191                      Object JavaDoc valueEl = Array.get(fieldValue, i);
192                      valid = (stateEl == null ? valueEl == null : stateEl.equals(valueEl));
193                      if(!valid)
194                      {
195                         break;
196                      }
197                   }
198                }
199             }
200          }
201          return valid;
202       }
203    };
204
205    //
206
// Static
207
//
208

209    public static final CMPFieldStateFactory getCMPFieldStateFactory(JDBCTypeFactory factory,
210                                                                     String JavaDoc implClassName,
211                                                                     Class JavaDoc clazz)
212       throws DeploymentException
213    {
214       CMPFieldStateFactory stateFactory;
215
216       // if the state factory is not provided on the field level use the one from the user type mapping if any
217
if(implClassName == null)
218       {
219          JDBCUserTypeMappingMetaData userMapping = (JDBCUserTypeMappingMetaData)factory.userTypeMappings.get(clazz.getName());
220          if(userMapping != null)
221          {
222             implClassName = userMapping.getStateFactory();
223          }
224       }
225
226       if(implClassName != null)
227       {
228          try
229          {
230             Class JavaDoc implClass = TCLAction.UTIL.getContextClassLoader().loadClass(implClassName);
231             stateFactory = (CMPFieldStateFactory)implClass.newInstance();
232          }
233          catch(ClassNotFoundException JavaDoc e)
234          {
235             throw new DeploymentException("Could not load state factory class: " + implClassName);
236          }
237          catch(Exception JavaDoc e)
238          {
239             throw new DeploymentException("Failed instantiate state factory: " + implClassName);
240          }
241       }
242       else if(Map JavaDoc.class.isAssignableFrom(clazz))
243       {
244          stateFactory = MAP;
245       }
246       else if(List JavaDoc.class.isAssignableFrom(clazz))
247       {
248          stateFactory = LIST;
249       }
250       else if(Set JavaDoc.class.isAssignableFrom(clazz))
251       {
252          stateFactory = SET;
253       }
254       else if(clazz.isArray())
255       {
256          stateFactory = ARRAY;
257       }
258       else if(usedWithEqualsStateFactory(clazz))
259       {
260          stateFactory = EQUALS;
261       }
262       else
263       {
264          stateFactory = INVALID_UNLESS_NULL;
265       }
266       return stateFactory;
267    }
268
269    public static final boolean checkDirtyAfterGet(JDBCTypeFactory factory, byte checkDirtyAfterGet, Class JavaDoc fieldType)
270    {
271       boolean result;
272       if(checkDirtyAfterGet == JDBCCMPFieldMetaData.CHECK_DIRTY_AFTER_GET_NOT_PRESENT)
273       {
274          JDBCUserTypeMappingMetaData userMapping = (JDBCUserTypeMappingMetaData)factory.
275             userTypeMappings.get(fieldType.getName());
276          if(userMapping != null &&
277             userMapping.checkDirtyAfterGet() != JDBCCMPFieldMetaData.CHECK_DIRTY_AFTER_GET_NOT_PRESENT)
278          {
279             result = userMapping.checkDirtyAfterGet() == JDBCCMPFieldMetaData.CHECK_DIRTY_AFTER_GET_TRUE;
280          }
281          else
282          {
283             result = !isDefaultImmutable(fieldType);
284          }
285       }
286       else
287       {
288          result = checkDirtyAfterGet == JDBCCMPFieldMetaData.CHECK_DIRTY_AFTER_GET_TRUE;
289       }
290       return result;
291    }
292
293    private static Object JavaDoc cloneValue(Object JavaDoc fieldValue, Class JavaDoc argType)
294    {
295       if(fieldValue == null)
296       {
297          return null;
298       }
299
300       Class JavaDoc valueType = fieldValue.getClass();
301       Constructor JavaDoc ctor;
302       try
303       {
304          ctor = valueType.getConstructor(new Class JavaDoc[]{argType});
305       }
306       catch(NoSuchMethodException JavaDoc e)
307       {
308          throw new IllegalStateException JavaDoc(
309             "Failed to find a ctor in " + valueType +
310             " that takes an instance of " + argType + " as an argument."
311          );
312       }
313
314       try
315       {
316          return ctor.newInstance(new Object JavaDoc[]{fieldValue});
317       }
318       catch(Exception JavaDoc e)
319       {
320          throw new IllegalStateException JavaDoc(
321             "Failed to create an instance of " + valueType +
322             " with the " + fieldValue + " as a ctor argument"
323          );
324       }
325    }
326
327    private static final boolean usedWithEqualsStateFactory(Class JavaDoc clazz)
328    {
329       return
330          isDefaultImmutable(clazz) ||
331          clazz == java.util.Date JavaDoc.class ||
332          clazz == java.sql.Date JavaDoc.class ||
333          clazz == java.sql.Time JavaDoc.class ||
334          clazz == java.sql.Timestamp JavaDoc.class;
335    }
336
337    private static final boolean isDefaultImmutable(Class JavaDoc clazz)
338    {
339       boolean result = false;
340       if(clazz.isPrimitive()
341          || clazz == Boolean JavaDoc.class
342          || clazz == Byte JavaDoc.class
343          || clazz == Short JavaDoc.class
344          || clazz == Integer JavaDoc.class
345          || clazz == Long JavaDoc.class
346          || clazz == Float JavaDoc.class
347          || clazz == Double JavaDoc.class
348          || clazz == Character JavaDoc.class
349          || clazz == String JavaDoc.class
350          || clazz == java.math.BigInteger JavaDoc.class
351          || clazz == java.math.BigDecimal JavaDoc.class
352       )
353       {
354          result = true;
355       }
356       return result;
357    }
358
359    //
360
// Attributes
361
//
362

363    // the type mapping to use with the specified database
364
private final JDBCTypeMappingMetaData typeMapping;
365
366    // all known complex types by java class type
367
private final Map JavaDoc complexTypes = new HashMap JavaDoc();
368    private final Map JavaDoc mappedSimpleTypes = new HashMap JavaDoc();
369
370    /** user types mappings */
371    private final Map JavaDoc userTypeMappings;
372
373    public JDBCTypeFactory(JDBCTypeMappingMetaData typeMapping,
374                           Collection JavaDoc valueClasses,
375                           Map JavaDoc userTypeMappings) throws DeploymentException
376    {
377       this.typeMapping = typeMapping;
378       this.userTypeMappings = userTypeMappings;
379
380       HashMap JavaDoc valueClassesByType = new HashMap JavaDoc();
381       for(Iterator JavaDoc i = valueClasses.iterator(); i.hasNext();)
382       {
383          JDBCValueClassMetaData valueClass = (JDBCValueClassMetaData)i.next();
384          valueClassesByType.put(valueClass.getJavaType(), valueClass);
385       }
386
387
388       // convert the value class meta data to a jdbc complex type
389
for(Iterator JavaDoc i = valueClasses.iterator(); i.hasNext();)
390       {
391          JDBCValueClassMetaData valueClass = (JDBCValueClassMetaData)i.next();
392          JDBCTypeComplex type = createTypeComplex(valueClass, valueClassesByType);
393          complexTypes.put(valueClass.getJavaType(), type);
394       }
395
396       Iterator JavaDoc i = typeMapping.getMappings().iterator();
397       while(i.hasNext())
398       {
399          JDBCMappingMetaData mapping = (JDBCMappingMetaData)i.next();
400
401          String JavaDoc sqlType = mapping.getSqlType();
402          int jdbcType = mapping.getJdbcType();
403          Class JavaDoc javaType = loadClass(mapping.getJavaType());
404          boolean notNull = javaType.isPrimitive();
405          boolean autoIncrement = false;
406
407          JDBCParameterSetter paramSetter;
408          if(mapping.getParamSetter() != null)
409          {
410             paramSetter = (JDBCParameterSetter)newInstance(mapping.getParamSetter());
411          }
412          else
413          {
414             paramSetter = JDBCUtil.getParameterSetter(jdbcType, javaType);
415          }
416
417          JDBCResultSetReader resultReader;
418          if(mapping.getResultReader() != null)
419          {
420             resultReader = (JDBCResultSetReader)newInstance(mapping.getResultReader());
421          }
422          else
423          {
424             resultReader = JDBCUtil.getResultSetReader(jdbcType, javaType);
425          }
426
427          JDBCTypeSimple type = new JDBCTypeSimple(
428             null, javaType, jdbcType, sqlType, notNull, autoIncrement, null, paramSetter, resultReader
429          );
430          mappedSimpleTypes.put(javaType, type);
431       }
432    }
433
434    public JDBCType getJDBCType(Class JavaDoc javaType)
435    {
436       if(complexTypes.containsKey(javaType))
437       {
438          return (JDBCTypeComplex)complexTypes.get(javaType);
439       }
440       else
441       {
442          JDBCTypeSimple type = (JDBCTypeSimple)mappedSimpleTypes.get(javaType);
443          if(type == null)
444          {
445             JDBCUserTypeMappingMetaData userTypeMapping =
446                (JDBCUserTypeMappingMetaData)userTypeMappings.get(javaType.getName());
447             Mapper mapper = null;
448             if(userTypeMapping != null)
449             {
450                ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
451                try
452                {
453                   javaType = cl.loadClass(userTypeMapping.getMappedType());
454                }
455                catch(ClassNotFoundException JavaDoc e)
456                {
457                   throw new IllegalStateException JavaDoc("Failed to load mapped type: " + userTypeMapping.getMappedType());
458                }
459
460                try
461                {
462                   mapper = (Mapper)newInstance(userTypeMapping.getMapper());
463                }
464                catch(DeploymentException e)
465                {
466                   throw new IllegalStateException JavaDoc("Failed to create Mapper instance of " + userTypeMapping.getMapper());
467                }
468             }
469
470             JDBCMappingMetaData typeMappingMD = typeMapping.getTypeMappingMetaData(javaType);
471             String JavaDoc sqlType = typeMappingMD.getSqlType();
472             int jdbcType = typeMappingMD.getJdbcType();
473             boolean notNull = javaType.isPrimitive();
474             boolean autoIncrement = false;
475
476             JDBCParameterSetter paramSetter;
477             if(typeMappingMD.getParamSetter() != null)
478             {
479                try
480                {
481                   paramSetter = (JDBCParameterSetter)newInstance(typeMappingMD.getParamSetter());
482                }
483                catch(DeploymentException e)
484                {
485                   throw new IllegalStateException JavaDoc(e.getMessage());
486                }
487             }
488             else
489             {
490                paramSetter = JDBCUtil.getParameterSetter(jdbcType, javaType);
491             }
492
493             JDBCResultSetReader resultReader;
494             if(typeMappingMD.getResultReader() != null)
495             {
496                try
497                {
498                   resultReader = (JDBCResultSetReader)newInstance(typeMappingMD.getResultReader());
499                }
500                catch(DeploymentException e)
501                {
502                   throw new IllegalStateException JavaDoc(e.getMessage());
503                }
504             }
505             else
506             {
507                resultReader = JDBCUtil.getResultSetReader(jdbcType, javaType);
508             }
509
510             type = new JDBCTypeSimple(
511                null, javaType, jdbcType, sqlType, notNull, autoIncrement, mapper, paramSetter, resultReader
512             );
513          }
514          return type;
515       }
516    }
517
518    public JDBCType getJDBCType(JDBCCMPFieldMetaData cmpField) throws DeploymentException
519    {
520       JDBCType fieldJDBCType;
521       final Class JavaDoc fieldType = cmpField.getFieldType();
522       if(complexTypes.containsKey(fieldType))
523       {
524          fieldJDBCType = createTypeComplex(cmpField);
525       }
526       else
527       {
528          fieldJDBCType = createTypeSimple(cmpField);
529       }
530       return fieldJDBCType;
531    }
532
533    public int getJDBCTypeForJavaType(Class JavaDoc clazz)
534    {
535       return typeMapping.getTypeMappingMetaData(clazz).getJdbcType();
536    }
537
538    public JDBCTypeMappingMetaData getTypeMapping()
539    {
540       return typeMapping;
541    }
542
543    private JDBCTypeComplex createTypeComplex(
544       JDBCValueClassMetaData valueClass,
545       HashMap JavaDoc valueClassesByType)
546    {
547       // get the properties
548
ArrayList JavaDoc propertyList = createComplexProperties(valueClass, valueClassesByType, new PropertyStack());
549
550       // transform properties into an array
551
JDBCTypeComplexProperty[] properties = new JDBCTypeComplexProperty[propertyList.size()];
552       properties = (JDBCTypeComplexProperty[])propertyList.toArray(properties);
553
554       return new JDBCTypeComplex(properties, valueClass.getJavaType());
555    }
556
557    private JDBCTypeSimple createTypeSimple(JDBCCMPFieldMetaData cmpField) throws DeploymentException
558    {
559       String JavaDoc columnName = cmpField.getColumnName();
560       Class JavaDoc javaType = cmpField.getFieldType();
561
562       JDBCMappingMetaData typeMappingMD = typeMapping.getTypeMappingMetaData(javaType);
563       String JavaDoc paramSetter = typeMappingMD.getParamSetter();
564       String JavaDoc resultReader = typeMappingMD.getResultReader();
565
566       int jdbcType;
567       String JavaDoc sqlType = cmpField.getSQLType();
568       if(sqlType != null)
569       {
570          jdbcType = cmpField.getJDBCType();
571       }
572       else
573       {
574          // get jdbcType and sqlType from typeMapping
575
sqlType = typeMappingMD.getSqlType();
576          jdbcType = typeMappingMD.getJdbcType();
577       }
578
579       boolean notNull = cmpField.isNotNull();
580       boolean autoIncrement = cmpField.isAutoIncrement();
581
582       Mapper mapper = null;
583       JDBCUserTypeMappingMetaData userTypeMapping = (JDBCUserTypeMappingMetaData)userTypeMappings.get(javaType.getName());
584       if(userTypeMapping != null)
585       {
586          String JavaDoc mappedTypeStr = userTypeMapping.getMappedType();
587          try
588          {
589             final ClassLoader JavaDoc contextClassLoader = TCLAction.UTIL.getContextClassLoader();
590             Class JavaDoc mapperClass = contextClassLoader.loadClass(userTypeMapping.getMapper());
591             mapper = (Mapper)mapperClass.newInstance();
592             javaType = contextClassLoader.loadClass(mappedTypeStr);
593             if(cmpField.getSQLType() == null)
594             {
595                JDBCMappingMetaData mappingMD = typeMapping.getTypeMappingMetaData(javaType);
596                sqlType = mappingMD.getSqlType();
597                jdbcType = mappingMD.getJdbcType();
598                paramSetter = mappingMD.getParamSetter();
599                resultReader = mappingMD.getResultReader();
600             }
601          }
602          catch(ClassNotFoundException JavaDoc e)
603          {
604             throw new DeploymentException("Class not found for mapper: " + userTypeMapping.getMapper(), e);
605          }
606          catch(Exception JavaDoc e)
607          {
608             throw new DeploymentException("Could not instantiate mapper: " + userTypeMapping.getMapper(), e);
609          }
610       }
611
612       JDBCParameterSetter paramSetterImpl;
613       if(paramSetter == null)
614       {
615          paramSetterImpl = JDBCUtil.getParameterSetter(jdbcType, javaType);
616       }
617       else
618       {
619          paramSetterImpl = (JDBCParameterSetter)newInstance(paramSetter);
620       }
621
622       JDBCResultSetReader resultReaderImpl;
623       if(resultReader == null)
624       {
625          resultReaderImpl = JDBCUtil.getResultSetReader(jdbcType, javaType);
626       }
627       else
628       {
629          resultReaderImpl = (JDBCResultSetReader)newInstance(resultReader);
630       }
631
632       return new JDBCTypeSimple(
633          columnName,
634          javaType,
635          jdbcType,
636          sqlType,
637          notNull,
638          autoIncrement,
639          mapper,
640          paramSetterImpl,
641          resultReaderImpl
642       );
643    }
644
645    private JDBCTypeComplex createTypeComplex(JDBCCMPFieldMetaData cmpField)
646    {
647       // get the default properties for a field of its type
648
JDBCTypeComplex type = (JDBCTypeComplex)complexTypes.get(cmpField.getFieldType());
649       JDBCTypeComplexProperty[] defaultProperties = type.getProperties();
650
651       // create a map of the overrides based on flat property name
652
HashMap JavaDoc overrides = new HashMap JavaDoc();
653
654       for(int i = 0; i < cmpField.getPropertyOverrides().size(); ++i)
655       {
656          JDBCCMPFieldPropertyMetaData p = (JDBCCMPFieldPropertyMetaData)cmpField.getPropertyOverrides().get(i);
657          overrides.put(p.getPropertyName(), p);
658       }
659
660       // array that will hold the final properites after overrides
661
JDBCTypeComplexProperty[] finalProperties = new JDBCTypeComplexProperty[defaultProperties.length];
662
663       // override property default values
664
for(int i = 0; i < defaultProperties.length; i++)
665       {
666          // pop off the override, if present
667
JDBCCMPFieldPropertyMetaData override;
668          override = (JDBCCMPFieldPropertyMetaData)overrides.remove(defaultProperties[i].getPropertyName());
669
670          if(override == null)
671          {
672             finalProperties[i] = defaultProperties[i];
673             finalProperties[i] = new JDBCTypeComplexProperty(
674                defaultProperties[i],
675                cmpField.getColumnName() + "_" +
676                defaultProperties[i].getColumnName(),
677                defaultProperties[i].getJDBCType(),
678                defaultProperties[i].getSQLType(),
679                cmpField.isNotNull() || defaultProperties[i].isNotNull());
680          }
681          else
682          {
683             // columnName
684
String JavaDoc columnName = override.getColumnName();
685             if(columnName == null)
686             {
687                columnName = cmpField.getColumnName() + "_" + defaultProperties[i].getColumnName();
688             }
689
690             // sql and jdbc type
691
String JavaDoc sqlType = override.getSQLType();
692             int jdbcType;
693             if(sqlType != null)
694             {
695                jdbcType = override.getJDBCType();
696             }
697             else
698             {
699                sqlType = defaultProperties[i].getSQLType();
700                jdbcType = defaultProperties[i].getJDBCType();
701             }
702
703             boolean notNull = cmpField.isNotNull() ||
704                override.isNotNull() ||
705                defaultProperties[i].isNotNull();
706
707             finalProperties[i] = new JDBCTypeComplexProperty(
708                defaultProperties[i],
709                columnName,
710                jdbcType,
711                sqlType,
712                notNull);
713          }
714       }
715
716       // did we find all overriden properties
717
if(overrides.size() > 0)
718       {
719          String JavaDoc propertyName = (String JavaDoc)overrides.keySet().iterator().next();
720          throw new EJBException JavaDoc("Property " + propertyName + " in field " +
721             cmpField.getFieldName() + " is not a property of value object " +
722             cmpField.getFieldType().getName());
723       }
724
725       // return the new complex type
726
return new JDBCTypeComplex(finalProperties, cmpField.getFieldType());
727    }
728
729    private ArrayList JavaDoc createComplexProperties(
730       JDBCValueClassMetaData valueClass,
731       HashMap JavaDoc valueClassesByType,
732       PropertyStack propertyStack)
733    {
734
735       ArrayList JavaDoc properties = new ArrayList JavaDoc();
736
737       // add the properties each property to the list
738
java.util.List JavaDoc valueClassProperties = valueClass.getProperties();
739       for(int i = 0; i < valueClassProperties.size(); ++i)
740       {
741          JDBCValuePropertyMetaData propertyMetaData =
742             (JDBCValuePropertyMetaData)valueClassProperties.get(i);
743          properties.addAll(createComplexProperties(propertyMetaData,
744             valueClassesByType, propertyStack));
745       }
746       return properties;
747    }
748
749    private ArrayList JavaDoc createComplexProperties(
750       JDBCValuePropertyMetaData propertyMetaData,
751       HashMap JavaDoc valueClassesByType,
752       PropertyStack propertyStack)
753    {
754
755       // push my data onto the stack
756
propertyStack.pushPropertyMetaData(propertyMetaData);
757
758       ArrayList JavaDoc properties = new ArrayList JavaDoc();
759
760       Class JavaDoc javaType = propertyMetaData.getPropertyType();
761       if(!valueClassesByType.containsKey(javaType))
762       {
763
764          // this property is a simple type
765
// which makes this the end of the line for recursion
766
String JavaDoc propertyName = propertyStack.getPropertyName();
767          String JavaDoc columnName = propertyStack.getColumnName();
768
769          String JavaDoc sqlType = propertyMetaData.getSqlType();
770          int jdbcType;
771          if(sqlType != null)
772          {
773             jdbcType = propertyMetaData.getJDBCType();
774          }
775          else
776          {
777             // get jdbcType and sqlType from typeMapping
778
JDBCMappingMetaData typeMappingMD = typeMapping.getTypeMappingMetaData(javaType);
779             sqlType = typeMappingMD.getSqlType();
780             jdbcType = typeMappingMD.getJdbcType();
781          }
782
783          boolean notNull = propertyStack.isNotNull();
784
785          Method JavaDoc[] getters = propertyStack.getGetters();
786          Method JavaDoc[] setters = propertyStack.getSetters();
787
788          properties.add(new JDBCTypeComplexProperty(
789             propertyName,
790             columnName,
791             javaType,
792             jdbcType,
793             sqlType,
794             notNull,
795             getters,
796             setters));
797
798       }
799       else
800       {
801
802          // this property is a value object, recurse
803
JDBCValueClassMetaData valueClass =
804             (JDBCValueClassMetaData)valueClassesByType.get(javaType);
805          properties.addAll(createComplexProperties(
806             valueClass,
807             valueClassesByType,
808             propertyStack));
809
810       }
811
812       // pop my data, back off
813
propertyStack.popPropertyMetaData();
814
815       return properties;
816    }
817
818    private static final class PropertyStack
819    {
820       final ArrayList JavaDoc properties = new ArrayList JavaDoc();
821       final ArrayList JavaDoc propertyNames = new ArrayList JavaDoc();
822       final ArrayList JavaDoc columnNames = new ArrayList JavaDoc();
823       final ArrayList JavaDoc notNulls = new ArrayList JavaDoc();
824       final ArrayList JavaDoc getters = new ArrayList JavaDoc();
825       final ArrayList JavaDoc setters = new ArrayList JavaDoc();
826
827       public PropertyStack()
828       {
829       }
830
831       public final void pushPropertyMetaData(
832          JDBCValuePropertyMetaData propertyMetaData)
833       {
834
835          propertyNames.add(propertyMetaData.getPropertyName());
836          columnNames.add(propertyMetaData.getColumnName());
837          notNulls.add(new Boolean JavaDoc(propertyMetaData.isNotNull()));
838          getters.add(propertyMetaData.getGetter());
839          setters.add(propertyMetaData.getSetter());
840
841          if(properties.contains(propertyMetaData))
842          {
843             throw new EJBException JavaDoc("Circular reference discoverd at " +
844                "property: " + getPropertyName());
845          }
846          properties.add(propertyMetaData);
847       }
848
849       public final void popPropertyMetaData()
850       {
851          propertyNames.remove(propertyNames.size() - 1);
852          columnNames.remove(columnNames.size() - 1);
853          notNulls.remove(notNulls.size() - 1);
854          getters.remove(getters.size() - 1);
855          setters.remove(setters.size() - 1);
856
857          properties.remove(properties.size() - 1);
858       }
859
860       public final String JavaDoc getPropertyName()
861       {
862          StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
863          for(int i = 0; i < propertyNames.size(); i++)
864          {
865             if(i > 0)
866             {
867                buf.append(".");
868             }
869             buf.append((String JavaDoc)propertyNames.get(i));
870          }
871          return buf.toString();
872       }
873
874       public final String JavaDoc getColumnName()
875       {
876          StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
877          for(int i = 0; i < columnNames.size(); i++)
878          {
879             if(i > 0)
880             {
881                buf.append("_");
882             }
883             buf.append((String JavaDoc)columnNames.get(i));
884          }
885          return buf.toString();
886       }
887
888       public final boolean isNotNull()
889       {
890          for(int i = 0; i < notNulls.size(); i++)
891          {
892             if(((Boolean JavaDoc)notNulls.get(i)).booleanValue())
893             {
894                return true;
895             }
896          }
897          return false;
898       }
899
900       public final Method JavaDoc[] getGetters()
901       {
902          return (Method JavaDoc[])getters.toArray(new Method JavaDoc[getters.size()]);
903       }
904
905       public final Method JavaDoc[] getSetters()
906       {
907          return (Method JavaDoc[])setters.toArray(new Method JavaDoc[setters.size()]);
908       }
909    }
910
911
912    private Object JavaDoc newInstance(String JavaDoc className) throws DeploymentException
913    {
914       Class JavaDoc clazz = loadClass(className);
915       try
916       {
917          return clazz.newInstance();
918       }
919       catch(Exception JavaDoc e)
920       {
921          throw new DeploymentException("Failed to instantiate " + className, e);
922       }
923    }
924    private Class JavaDoc loadClass(String JavaDoc className) throws DeploymentException
925    {
926       try
927       {
928          final ClassLoader JavaDoc contextClassLoader = TCLAction.UTIL.getContextClassLoader();
929          return contextClassLoader.loadClass(className);
930       }
931       catch(ClassNotFoundException JavaDoc e)
932       {
933          throw new DeploymentException("Failed to load class: " + className, e);
934       }
935    }
936 }
937
Popular Tags