View Javadoc
1   /*
2    * Copyright 2008 Filip Hianik, Vanja Culafic
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.exolab.castor.builder.descriptors;
17  
18  import java.util.List;
19  
20  import org.castor.core.constants.cpa.JDOConstants;
21  import org.exolab.castor.builder.BuilderConfiguration;
22  import org.exolab.castor.builder.info.ClassInfo;
23  import org.exolab.castor.builder.info.FieldInfo;
24  import org.exolab.castor.builder.info.nature.JDOClassInfoNature;
25  import org.exolab.castor.builder.info.nature.JDOFieldInfoNature;
26  import org.exolab.castor.builder.info.nature.XMLInfoNature;
27  import org.exolab.castor.builder.info.nature.relation.JDOOneToManyNature;
28  import org.exolab.castor.builder.info.nature.relation.JDOOneToOneNature;
29  import org.exolab.castor.builder.types.XSList;
30  import org.exolab.castor.builder.types.XSType;
31  import org.exolab.javasource.JClass;
32  import org.exolab.javasource.JConstructor;
33  import org.exolab.javasource.JNaming;
34  import org.exolab.javasource.JPrimitiveType;
35  import org.exolab.javasource.JSourceCode;
36  import org.exolab.javasource.JType;
37  
38  /**
39   * A class for creating the source code of JDO-specific descriptor classes.
40   *
41   * @author Filip Hianik
42   * @author Vanja Culafic
43   * @since 1.2.1
44   *
45   * @see DescriptorSourceFactory
46   * @see JDODescriptorJClass
47   *
48   */
49  public final class JDOClassDescriptorFactory {
50  
51     /**
52      * The BuilderConfiguration instance.
53      */
54     private final BuilderConfiguration _config;
55  
56     /**
57      * Contains all fields exclusive identities.
58      */
59     private String _fields = null;
60  
61     /**
62      * Contains all identities.
63      */
64     private String _identities = null;
65  
66     /**
67      * Creates a new {@link JDOClassDescriptorFactory} with the given
68      * configuration.
69      *
70      * @param config
71      *                A {@link BuilderConfiguration} instance
72      */
73     public JDOClassDescriptorFactory(final BuilderConfiguration config) {
74         if (config == null) {
75             String err = "The argument 'config' must not be null.";
76             throw new IllegalArgumentException(err);
77         }
78         _config = config;
79     }
80  
81     /**
82      * Creates the Source code of a ClassInfo for a given XML Schema element
83      * declaration.
84      *
85      * @param classInfo
86      *                the XML Schema element declaration
87      * @return the JClass representing the ClassInfo source code
88      */
89     public JClass createSource(final ClassInfo classInfo) {
90         if (!checkClassInfoNature(classInfo)) {
91             return null;
92         }
93  
94         JClass jClass               = classInfo.getJClass();
95         String descriptorClassName  = 
96             getQualifiedJDODescriptorClassName(jClass.getName());
97         JDODescriptorJClass classDesc = 
98             new JDODescriptorJClass(_config, descriptorClassName, jClass);
99         JDOClassInfoNature cNature = new JDOClassInfoNature(classInfo);
100 
101        //-- get handle to default constructor
102        JConstructor ctor   = classDesc.getConstructor(0);
103        JSourceCode jsc     = ctor.getSourceCode();
104 
105        jsc = createClassInfoPart(classInfo, jsc);
106 
107        //=================
108        // FieldDescriptors
109        //=================
110 
111        for (int i = 0; i < classInfo.getElementFields().length; i++) {
112            FieldInfo fInfo = classInfo.getElementFields()[i];
113            if (checkFieldInfoNatures(fInfo)) {
114                
115                if (fInfo.hasNature(JDOOneToOneNature.class.getName())) {
116                    jsc = createOneToOneFieldInfoPart(fInfo, jsc);
117                    
118                } else if (fInfo.hasNature(JDOOneToManyNature.class.getName())) {
119                    jsc = createOneToManyFieldInfoPart(fInfo, jsc);
120                } else {
121                    jsc = createEntityFieldInfoPart(fInfo, jsc);
122                }
123            }
124        }
125 
126 
127        _fields = setFields(classInfo.getElementFields());
128        _identities = setIdentities(cNature.getPrimaryKeys());
129 
130        jsc.add("");
131 
132        jsc.add("setFields(new FieldDescriptor[] {" + _fields + "});");
133        jsc.add("setIdentities(new FieldDescriptor[] {" + _identities + "});");
134 
135        return classDesc;
136    }
137 
138    /**
139     * Returns the fully-qualified class name of the JDODescriptor to create.
140     * Given the fully-qualified class name of the class we are creating a
141     * JDODescriptor for, return the correct fully-qualified name for the
142     * JDODescriptor.
143     *
144     * @param name
145     *                fully-qualified class name of the class we are describing
146     * @return the fully-qualified class name of the JDODescriptor to create
147     */
148    private String getQualifiedJDODescriptorClassName(final String name) {
149        String descPackage = JNaming.getPackageFromClassName(name);
150        String descClassName = JNaming.getLocalNameFromClassName(name);
151 
152        if (descPackage != null && descPackage.length() > 0) {
153            descPackage = descPackage + "."
154                    + JDOConstants.JDO_DESCRIPTOR_PACKAGE + ".";
155        } else {
156            descPackage = "";
157        }
158        // TODO integrate XMLConstants.JDO_DESCRIPTOR_SUFFIX;
159        return descPackage + descClassName + "JDODescriptor";
160    }
161 
162    /**
163     * Returns the modified string with the first letter upperCase.
164     * @param string String to upper case
165     * @return the string with first letter upperCase
166     */
167    private static String toUpperCaseFirstLetter(final String string) {
168        return string.substring(0, 1).toUpperCase() + string.substring(1);
169    }
170 
171    /**
172     * Returns the string which contains names of all FieldDescriptors
173     * for Fields that are not identities. Names are separated by comma.
174     * @param fInfos Array of FieldInfos
175     * @return names of all FieldDescriptors as one String (separated by comma)
176     */
177    private String setFields(final FieldInfo[] fInfos) {
178        String str = "";
179 
180        FieldInfo fInfo;
181        ClassInfo cInfo;
182        for (int i = 0; i < fInfos.length; i++) {
183            fInfo = fInfos[i];
184            cInfo = fInfo.getDeclaringClassInfo();
185            JDOClassInfoNature cNature = new JDOClassInfoNature(cInfo);
186            if (cNature.getPrimaryKeys() != null) {
187                if (cNature.getPrimaryKeys().contains(new XMLInfoNature(fInfo).getNodeName())) {
188                    continue;
189                }
190            }
191            if (str.equals("")) {
192                str = str + new XMLInfoNature(fInfo).getNodeName() + "FieldDescr";
193            } else {
194                str = str + "," +  new XMLInfoNature(fInfo).getNodeName() + "FieldDescr";
195            }
196        }
197        return str;
198    }
199 
200    /**
201     * Returns the string which contains names of all FieldDescriptors
202     * for Fields that are identities. Names are separated by comma.
203     * @param primaryKeys Array of primary keys.
204     * @return names of all FieldDescriptors as one String (separated by comma)
205     */
206    private String setIdentities(final List<?> primaryKeys) {
207        String identities = "";
208        Object[] pkArray = null;
209        if (primaryKeys != null) {
210            pkArray = primaryKeys.toArray();
211            for (int i = 0; i < pkArray.length; i++) {
212                if (identities.equals("")) {
213                    identities = identities + pkArray[i] + "FieldDescr";
214                } else {
215                    identities = identities + "," + pkArray[i] + "FieldDescr";
216                }
217            }
218        }
219        return identities;
220    }
221    
222    /**
223     * Checks if ClassInfo has the JDOClassNature and if their required
224     * attributes are properly set.
225     * @param cInfo the ClassInfo object
226     * @return true when ClassInfo has a JDOClassNature with all required
227     *              attributes properly set, false otherwise
228     */
229    private boolean checkClassInfoNature(final ClassInfo cInfo) {
230        if (cInfo.hasNature(JDOClassInfoNature.class.getName())) {
231            JDOClassInfoNature cNature = new JDOClassInfoNature(cInfo);
232            if (cNature.getAccessMode() == null
233                    || cNature.getPrimaryKeys() == null
234                    || cNature.getPrimaryKeys().isEmpty()
235                    || cNature.getTableName() == null
236                    || cNature.getTableName().length() == 0) {
237                return false;
238            }
239            return true;
240        }
241        return false;
242    }
243 
244    /**
245     * Checks if FieldInfo has the XMLInfoNature and JDOFieldNature and if 
246     * their required attributes are properly set.
247     * @param fInfo the FieldInfo object
248     * @return true when FieldInfo has a XMLInfoNature and JDOFieldNature 
249     *              with all required attributes properly set, false otherwise
250     */
251    private boolean checkFieldInfoNatures(final FieldInfo fInfo) {
252        if (!fInfo.hasNature(XMLInfoNature.class.getName())) {
253            return false;
254        }
255        
256        if (fInfo.hasNature(JDOFieldInfoNature.class.getName())) {
257            JDOFieldInfoNature fNature = new JDOFieldInfoNature(fInfo);
258            if (fNature.getColumnName() == null
259                    || fNature.getColumnName().length() == 0
260                    || fNature.getColumnType() == null) {
261                return false;
262            }
263            return true;
264        }
265        
266        if (fInfo.hasNature(JDOOneToOneNature.class.getName())) {
267            JDOOneToOneNature oneNature = new JDOOneToOneNature(fInfo);
268            if (oneNature.getForeignKeys().size() != 1) {
269                return false;
270            }
271            return true;
272        }
273        
274        if (fInfo.hasNature(JDOOneToManyNature.class.getName())) {
275            JDOOneToManyNature manyNature = new JDOOneToManyNature(fInfo);
276            if (manyNature.getForeignKeys().size() != 1) {
277                return false;
278            }
279            return true;
280        }       
281        return false;
282    }
283 
284    /**
285     * Creates the ClassInfo part of the JDOClassDescriptor.
286     * @param classInfo ClassInfo object
287     * @param jsc JSourceCode
288     * @return JSourceCode created in this method
289     */
290    private JSourceCode createClassInfoPart(final ClassInfo classInfo, final JSourceCode jsc) {
291 
292        JDOClassInfoNature cNature = new JDOClassInfoNature(classInfo);
293 
294        jsc.add("");
295        
296        jsc.add("addNature(ClassDescriptorJDONature.class.getName());");
297        jsc.add("ClassDescriptorJDONature jdoNature = new ClassDescriptorJDONature(this);");
298 
299        //-- set table name
300        String tableName = cNature.getTableName();
301        jsc.add("jdoNature.setTableName(\"" + tableName + "\");");
302 
303        //-- set corresponding Java class
304        // TODO IS THERE A NEED TO CHECK THIS?!
305        String className = classInfo.getJClass().getLocalName();
306        if ((className != null) && (className.length() > 0)) {
307            jsc.add("setJavaClass(");
308            jsc.append(className);
309            jsc.append(".class);");
310        }
311 
312        //-- set access mode
313        String accessMode = cNature.getAccessMode().getName();
314        jsc.add("jdoNature.setAccessMode(AccessMode.valueOf(\"" + accessMode + "\"));");
315 
316        //-- set cache key
317        // TODO IS THERE A NEED TO CHECK THIS?!
318        String fullName = classInfo.getJClass().getName();
319        if ((fullName != null) && (fullName.length() > 0)) {
320            jsc.add("jdoNature.addCacheParam(\"name\", \"");
321            jsc.append(fullName);
322            jsc.append("\");");
323        }
324 
325        jsc.add("");
326 
327        //-- Configure class mapping
328        jsc.add("mapping.setAccess(ClassMappingAccessType.fromValue(\"");
329        jsc.append(accessMode);
330        jsc.append("\"));");
331 
332        jsc.add("mapping.setAutoComplete(true);");
333 
334        // TODO IS THERE A NEED TO CHECK THIS?!
335        if ((fullName != null) && (fullName.length() > 0)) {
336            jsc.add("mapping.setName(\"");
337            jsc.append(fullName);
338            jsc.append("\");");
339        }
340 
341        //-- set class choice
342        jsc.add("mapping.setClassChoice(choice);");
343 
344        //-- set table
345        String table = cNature.getTableName();
346        jsc.add("mapTo.setTable(\"" + table + "\");");
347 
348        //-- set table mapping
349        jsc.add("mapping.setMapTo(mapTo);");
350 
351        //-- set mapping
352        jsc.add("setMapping(mapping);");
353 
354        return jsc;
355    }
356 
357    /**
358     * Creates the source code of the FieldInfo part appeding it to
359     * the source code generated till now.
360     * @param fInfo FieldInfo object
361     * @param jsc JSourceCode created till now
362     * @return JSourceCode created in this method
363     */
364    private JSourceCode createEntityFieldInfoPart(final FieldInfo fInfo, final JSourceCode jsc) {
365        JDOFieldInfoNature fNature = new JDOFieldInfoNature(fInfo);
366        JDOClassInfoNature cNature = new JDOClassInfoNature(fInfo.getDeclaringClassInfo());
367        XMLInfoNature xmlNature = new XMLInfoNature(fInfo);
368        
369        //-- set name
370        String name = xmlNature.getNodeName();
371        jsc.add("");
372        jsc.add("//" + name + " field");
373        jsc.add("String " + name + "FieldName = \"" + name + "\";");
374 
375        //-- initialize objects
376        jsc.add("FieldDescriptorImpl " + name + "FieldDescr;");
377 
378        jsc.add("FieldMapping " + name + "FM = new FieldMapping();");
379 
380        //-- set typeInfo
381        String type = null;
382        XSType schemaType;
383        
384        schemaType = xmlNature.getSchemaType();
385        JType javaType = schemaType.getJType();
386        type = javaType.toString();
387        String wrapperType = null;
388        if (javaType instanceof JPrimitiveType) {
389            wrapperType = ((JPrimitiveType) javaType).getWrapperName();
390        } else {
391            wrapperType = type;
392        }
393 
394        // TODO IS THERE A NEED TO CHECK THIS?!
395        if ((type != null) && (type.length() > 0)) {
396            jsc.add("TypeInfo " + name
397                    + "Type = new TypeInfo(" + wrapperType + ".class);");
398        }
399 
400        jsc.add("// Set columns required (= not null)");
401        jsc.add(name + "Type.setRequired("
402                + Boolean.toString(xmlNature.isRequired()) + ");");
403 
404        jsc.add("");
405 
406        jsc.add("FieldHandler " + name + "Handler;");
407        jsc.add("try {");
408 
409        //-- get/set methods
410        jsc.indent();
411        String className = fInfo.getDeclaringClassInfo().getJClass().getLocalName();
412        // TODO IS THERE A NEED TO CHECK THIS?!
413        if ((className != null) && (className.length() > 0)) {
414            jsc.add("Method " + name + "GetMethod = "
415                    + className + ".class.getMethod(\"get"
416                    + toUpperCaseFirstLetter(name) + "\", null);");
417            jsc.add("Method " + name + "SetMethod = "
418                    + className + ".class.getMethod(\"set"
419                    + toUpperCaseFirstLetter(name) + "\", new Class[]{");
420        }
421 
422        // TODO IS THERE A NEED TO CHECK THIS?!
423        if ((type != null) && (type.length() > 0)) {
424            jsc.addIndented(type + ".class});");
425        }
426 
427        jsc.add("");
428        jsc.add(name + "Handler = new FieldHandlerImpl(" + name + "FieldName, ");
429        jsc.append("null, null,");
430        jsc.addIndented(name + "GetMethod, " + name + "SetMethod, " + name + "Type);");
431        jsc.unindent();
432        jsc.add("");
433 
434        //-- Catch of exceptions
435        jsc.add("} catch (SecurityException e1) {");
436        jsc.indent();
437        jsc.add("throw new RuntimeException(e1.getMessage());");
438        jsc.unindent();
439        jsc.add("} catch (MappingException e1) {");
440        jsc.indent();
441        jsc.add("throw new RuntimeException(e1.getMessage());");
442        jsc.unindent();
443        jsc.add("} catch (NoSuchMethodException e1) {");
444        jsc.indent();
445        jsc.add("throw new RuntimeException(e1.getMessage());");
446        jsc.unindent();
447        jsc.add("}");
448 
449 //       //-- JDOFieldDescriptorImpl constructor
450 //       jsc.add("// Instantiate " + name + " field descriptor");
451 //       jsc.add(name + "FieldDescr = new JDOFieldDescriptorImpl(");
452 //       jsc.append(name + "FieldName, " + name + "Type,");
453 //       jsc.indent();
454 //       jsc.add(name + "Handler, ");
455 //       jsc.append(Boolean.toString(fInfo.isTransient()) + ", ");
456 //       String sqlName = new JDOFieldInfoNature(fInfo).getColumnName();
457 //       jsc.append("new String[] { \"" + sqlName + "\" },");
458 //       jsc.add("new int[] {SQLTypeInfos");
459 //       jsc.indent();
460 //       jsc.add(".javaType2sqlTypeNum(");
461 //
462 //       // TODO IS THERE NEED TO CHECK THIS?!
463 //       if ((type != null) && (type.length() > 0)) {
464 //           jsc.append(wrapperType + ".class) },");
465 //       }
466 //
467 //       jsc.unindent();
468 //       jsc.add("null, new String[] {}, ");
469 //       jsc.append(Boolean.toString(fNature.isDirty()) + ", ");
470 //       jsc.append(Boolean.toString(fNature.isReadOnly()) + ");");
471 //       jsc.unindent();
472 
473        //-- invoke FieldDescriptorImpl constructor
474        jsc.add("// Instantiate " + name + " field descriptor");
475        jsc.add(name + "FieldDescr = new FieldDescriptorImpl(");
476        jsc.append(name + "FieldName, " + name + "Type,");
477        jsc.append(name + "Handler, ");
478        jsc.append(Boolean.toString(fInfo.isTransient()) + ");");
479 
480        jsc.add(name + "FieldDescr.addNature(FieldDescriptorJDONature.class.getName());");
481 
482        jsc.add("FieldDescriptorJDONature " + name + "FieldJdoNature = new FieldDescriptorJDONature(" 
483                + name + "FieldDescr);");
484 
485        String sqlName = new JDOFieldInfoNature(fInfo).getColumnName();
486        jsc.add(name + "FieldJdoNature.setSQLName(new String[] { \"" + sqlName + "\" });");
487        jsc.add(name + "FieldJdoNature.setSQLType(new int[] {SQLTypeInfos");
488        jsc.append(".javaType2sqlTypeNum(");
489 
490        // TODO IS THERE NEED TO CHECK THIS?!
491        if ((type != null) && (type.length() > 0)) {
492            jsc.append(wrapperType + ".class) });");
493        }
494 
495        // jsc.add("null, new String[] {}, ");
496        jsc.add(name + "FieldJdoNature.setManyTable(null);");
497        jsc.add(name + "FieldJdoNature.setManyKey(new String[] {});");
498        jsc.add(name + "FieldJdoNature.setDirtyCheck(" + Boolean.toString(fNature.isDirty()) + ");");
499        jsc.add(name + "FieldJdoNature.setReadOnly(" + Boolean.toString(fNature.isReadOnly()) + ");");
500 
501        jsc.add("");
502 
503        jsc.add(name + "FieldDescr.setDirect(false);");
504        jsc.add(name + "FieldDescr.setRequired(" + xmlNature.isRequired() + ");");
505        jsc.add(name + "FieldDescr.setSetMethod(\"set"
506                + toUpperCaseFirstLetter(name) + "\");");
507        jsc.add(name + "FieldDescr.setGetMethod(\"get"
508                + toUpperCaseFirstLetter(name) + "\");");
509 
510        jsc.add("");
511 
512        //-- parent class descriptor
513        jsc.add(name + "FieldDescr.setContainingClassDescriptor(this);");
514        
515        boolean isPrimaryKey = false;
516        if (cNature.getPrimaryKeys() != null) {
517            isPrimaryKey = (cNature.getPrimaryKeys().contains(xmlNature.getNodeName()));
518        }
519        
520        jsc.add(name + "FieldDescr.setIdentity(" 
521                + Boolean.toString(isPrimaryKey) + ");");
522 
523        //-- fieldmapping
524        jsc.add(name + "FM.setIdentity(" + Boolean.toString(isPrimaryKey) + ");");
525        jsc.add(name + "FM.setDirect(false);");
526        jsc.add(name + "FM.setName(\"" + name + "\");");
527        jsc.add(name + "FM.setRequired(" + xmlNature.isRequired() + ");");
528        jsc.add(name + "FM.setSetMethod(\"set"
529                + toUpperCaseFirstLetter(name) + "\");");
530        jsc.add(name + "FM.setGetMethod(\"get"
531                + toUpperCaseFirstLetter(name) + "\");");
532 
533        //-- sql part
534        jsc.add("Sql " + name + "Sql = new Sql();");
535        jsc.add(name + "Sql.addName(\"" + name + "\");");
536 
537        String sqlType = fNature.getColumnType();
538        if ((sqlType != null) && (sqlType.length() > 0)) {
539            jsc.add(name + "Sql.setType(\"" + sqlType + "\");");
540        }
541 
542        jsc.add(name + "FM.setSql(" + name + "Sql);");
543 
544        if ((type != null) && (type.length() > 0)) {
545            jsc.add(name + "FM.setType(\"" + type + "\");");
546        }
547 
548        jsc.add("choice.addFieldMapping(" + name + "FM);");
549 
550        return jsc;
551    }
552 
553    /**
554     * Creates the source code of the FieldInfo part with
555     * one-to-one relation appeding it to
556     * the source code generated till now.
557     * @param fInfo FieldInfo object
558     * @param jsc JSourceCode created till now
559     * @return JSourceCode created in this method
560     */
561    private JSourceCode createOneToOneFieldInfoPart(final FieldInfo fInfo, final JSourceCode jsc) {
562 //       JDOFieldInfoNature fNature = new JDOFieldInfoNature(fInfo);
563        JDOClassInfoNature cNature = new JDOClassInfoNature(fInfo.getDeclaringClassInfo());
564        JDOOneToOneNature oneNature = new JDOOneToOneNature(fInfo);
565        XMLInfoNature xmlNature = new XMLInfoNature(fInfo);
566        
567        //-- set name
568        String name = xmlNature.getNodeName();
569        jsc.add("");
570        jsc.add("//" + name + " field");
571        jsc.add("String " + name + "FieldName = \"" + name + "\";");
572        
573        String sqlName = oneNature.getForeignKeys().get(0).toString();
574        jsc.add("String " + name + "SqlName = \"" + sqlName + "\";");
575        
576        //-- initialize objects
577        jsc.add("FieldDescriptorImpl " + name + "FieldDescr;");
578        jsc.add("FieldMapping " + name + "FM = new FieldMapping();");
579 
580        //-- set typeInfo
581        String type = null;
582        XSType schemaType;
583        
584        schemaType = xmlNature.getSchemaType();
585        JType javaType = schemaType.getJType();
586        type = javaType.toString();
587        
588        String wrapperType = null;
589        if (javaType instanceof JPrimitiveType) {
590         wrapperType = ((JPrimitiveType) javaType).getWrapperName();
591        } else {
592            wrapperType = type;
593        }
594 
595 
596        // TODO IS THERE A NEED TO CHECK THIS?!
597        if ((type != null) && (type.length() > 0)) {
598            jsc.add("TypeInfo " + name
599                    + "Type = new TypeInfo(" + type + ".class);");
600        }
601 
602        jsc.add("// Set columns required (= not null)");
603        jsc.add(name + "Type.setRequired("
604                + Boolean.toString(xmlNature.isRequired()) + ");");
605 
606        jsc.add("");
607 
608        jsc.add("FieldHandler " + name + "Handler;");
609        jsc.add("try {");
610 
611        //-- get/set methods
612        jsc.indent();
613        // TODO HOW ABOUT GETTING THE NAME FROM NATURE?
614        String className = fInfo.getDeclaringClassInfo().getJClass().getLocalName();
615        // TODO IS THERE A NEED TO CHECK THIS?!
616        if ((className != null) && (className.length() > 0)) {
617            jsc.add("Method " + name + "GetMethod = "
618                    + className + ".class.getMethod(\"get"
619                    + toUpperCaseFirstLetter(name) + "\", null);");
620            jsc.add("Method " + name + "SetMethod = "
621                    + className + ".class.getMethod(\"set"
622                    + toUpperCaseFirstLetter(name) + "\", new Class[]{");
623        }
624 
625        // TODO IS THERE A NEED TO CHECK THIS?!
626        if ((type != null) && (type.length() > 0)) {
627            jsc.addIndented(type + ".class});");
628        }
629 
630        jsc.add("");
631        jsc.add(name + "Handler = new FieldHandlerImpl(" + name + "FieldName, ");
632        jsc.append("null, null,");
633        jsc.addIndented(name + "GetMethod, " + name + "SetMethod, " + name + "Type);");
634        jsc.unindent();
635        jsc.add("");
636 
637        //-- Catch of exceptions
638        jsc.add("} catch (SecurityException e1) {");
639        jsc.indent();
640        jsc.add("throw new RuntimeException(e1.getMessage());");
641        jsc.unindent();
642        jsc.add("} catch (MappingException e1) {");
643        jsc.indent();
644        jsc.add("throw new RuntimeException(e1.getMessage());");
645        jsc.unindent();
646        jsc.add("} catch (NoSuchMethodException e1) {");
647        jsc.indent();
648        jsc.add("throw new RuntimeException(e1.getMessage());");
649        jsc.unindent();
650        jsc.add("}");
651 
652 
653 //       //-- JDOFieldDescriptorImpl constructor
654 //       jsc.add("// Instantiate " + name + " field descriptor");
655 //       jsc.add(name + "FieldDescr = new JDOFieldDescriptorImpl(");
656 //       jsc.append(name + "FieldName, " + name + "Type,");
657 //       jsc.indent();
658 //       jsc.add(name + "Handler, ");
659 //       jsc.append(Boolean.toString(fInfo.isTransient()) + ", ");
660 //       jsc.append("new String[] { " + name + "SqlName },");
661 //       jsc.add("new int[] {SQLTypeInfos");
662 //       jsc.indent();
663 //       jsc.add(".javaType2sqlTypeNum(");
664 //
665 //       // TODO IS THERE NEED TO CHECK THIS?!
666 //       if ((type != null) && (type.length() > 0)) {
667 //           jsc.append(wrapperType + ".class) },");
668 //       }
669 //
670 //       jsc.unindent();
671 //       jsc.add("null, new String[] { " + name + "SqlName }, ");
672 //       jsc.append(Boolean.toString(oneNature.isDirty()) + ", ");
673 //       jsc.append(Boolean.toString(oneNature.isReadOnly()) + ");");
674 //       jsc.unindent();
675 
676        //-- invoke FieldDescriptorImpl constructor
677        jsc.add("// Instantiate " + name + " field descriptor");
678        jsc.add(name + "FieldDescr = new FieldDescriptorImpl(");
679        jsc.append(name + "FieldName, " + name + "Type,");
680        jsc.append(name + "Handler, ");
681        jsc.append(Boolean.toString(fInfo.isTransient()) + ");");
682 
683        jsc.add(name + "FieldDescr.addNature(FieldDescriptorJDONature.class.getName());");
684 
685        jsc.add("FieldDescriptorJDONature " + name + "FieldJdoNature = new FieldDescriptorJDONature(" 
686                + name + "FieldDescr);");
687 
688        jsc.add(name + "FieldJdoNature.setSQLName(new String[] { " + name + "SqlName });");
689        jsc.add(name + "FieldJdoNature.setSQLType(new int[] {SQLTypeInfos");
690        jsc.append(".javaType2sqlTypeNum(");
691 
692        // TODO IS THERE NEED TO CHECK THIS?!
693        if ((type != null) && (type.length() > 0)) {
694            jsc.append(wrapperType + ".class) });");
695        }
696 
697 //       jsc.add(name + "FieldJdoNature.setManyTable(null);");
698        jsc.add(name + "FieldJdoNature.setManyKey(new String[] { " + name + "SqlName });");
699        jsc.add(name + "FieldJdoNature.setDirtyCheck(" + Boolean.toString(oneNature.isDirty()) + ");");
700        jsc.add(name + "FieldJdoNature.setReadOnly(" + Boolean.toString(oneNature.isReadOnly()) + ");");
701 
702        jsc.add("");
703 
704        //-- parent class descriptor
705        jsc.add(name + "FieldDescr.setContainingClassDescriptor(this);");
706        jsc.add(name + "FieldDescr.setClassDescriptor(new " + getLocalName(type) 
707                + "JDODescriptor());");
708        
709        boolean isPrimaryKey = false;
710        if (cNature.getPrimaryKeys() != null) {
711            isPrimaryKey = (cNature.getPrimaryKeys().contains(xmlNature.getNodeName()));
712        }
713 
714        //-- fieldmapping
715        jsc.add(name + "FM.setIdentity(" + Boolean.toString(isPrimaryKey) + ");");
716        jsc.add(name + "FM.setDirect(false);");
717        jsc.add(name + "FM.setName(\"" + name + "\");");
718        jsc.add(name + "FM.setRequired(" + xmlNature.isRequired() + ");");
719        jsc.add(name + "FM.setSetMethod(\"set"
720                + toUpperCaseFirstLetter(name) + "\");");
721        jsc.add(name + "FM.setGetMethod(\"get"
722                + toUpperCaseFirstLetter(name) + "\");");
723 
724        //-- sql part
725        jsc.add("Sql " + name + "Sql = new Sql();");
726        jsc.add(name + "Sql.addName(\"" + sqlName + "\");");       
727        jsc.add(name + "Sql.setManyKey(new String[] {\"" + sqlName + "\"});");
728        jsc.add(name + "FM.setSql(" + name + "Sql);");
729 
730        if ((type != null) && (type.length() > 0)) {
731            jsc.add(name + "FM.setType(\"" + type + "\");");
732        }
733 
734        jsc.add("choice.addFieldMapping(" + name + "FM);");
735        return jsc;
736    }
737    
738    /**
739     * Creates the source code of the FieldInfo part with
740     * one-to-one relation appeding it to
741     * the source code generated till now.
742     * @param fInfo FieldInfo object
743     * @param jsc JSourceCode created till now
744     * @return JSourceCode created in this method
745     */
746    private JSourceCode createOneToManyFieldInfoPart(final FieldInfo fInfo, final JSourceCode jsc) {
747        
748        //JDOFieldInfoNature fNature = new JDOFieldInfoNature(fInfo);
749        JDOClassInfoNature cNature = new JDOClassInfoNature(fInfo.getDeclaringClassInfo());
750        JDOOneToManyNature manyNature = new JDOOneToManyNature(fInfo);
751        XMLInfoNature xmlNature = new XMLInfoNature(fInfo);
752        
753        //-- set name
754        String name = xmlNature.getNodeName();
755        jsc.add("");
756        jsc.add("//" + name + " field");
757        jsc.add("String " + name + "FieldName = \"" + name + "\";");
758        
759        String sqlName = manyNature.getForeignKeys().get(0).toString();
760        jsc.add("String " + name + "SqlName = \"" + sqlName + "\";");
761        
762        //-- initialize objects
763        jsc.add("FieldDescriptorImpl " + name + "FieldDescr;");
764        jsc.add("FieldMapping " + name + "FM = new FieldMapping();");
765 
766        //-- set typeInfo
767        String type = null;
768        XSList schemaType;
769        
770        schemaType = (XSList) xmlNature.getSchemaType();
771        JType javaType = schemaType.getContentType().getJType();
772        type = javaType.toString();
773        
774        String wrapperType = null;
775        if (javaType instanceof JPrimitiveType) {
776         wrapperType = ((JPrimitiveType) javaType).getWrapperName();
777        } else {
778            wrapperType = type;
779        }       
780 
781        // TODO IS THERE A NEED TO CHECK THIS?!
782        if ((type != null) && (type.length() > 0)) {
783            jsc.add("TypeInfo " + name
784                    + "Type = new TypeInfo(" + type + ".class);");
785        }
786 
787        jsc.add("// Set columns required (= not null)");
788        jsc.add(name + "Type.setRequired("
789                + Boolean.toString(xmlNature.isRequired()) + ");");
790 
791        jsc.add("");
792 
793        jsc.add("FieldHandler " + name + "Handler;");
794        jsc.add("try {");
795 
796        //-- get/set methods
797        jsc.indent();
798        // TODO HOW ABOUT GETTING THE NAME FROM NATURE?
799        String className = fInfo.getDeclaringClassInfo().getJClass().getLocalName();
800        // TODO IS THERE A NEED TO CHECK THIS?!
801        if ((className != null) && (className.length() > 0)) {
802            jsc.add("Method " + name + "GetMethod = "
803                    + className + ".class.getMethod(\"get"
804                    + toUpperCaseFirstLetter(name) + "\", null);");
805            jsc.add("Method " + name + "SetMethod = "
806                    + className + ".class.getMethod(\"set"
807                    + toUpperCaseFirstLetter(name) + "\", new Class[]{");       
808        }
809        
810        // TODO IS THERE A NEED TO CHECK THIS?!
811        if ((type != null) && (type.length() > 0)) {
812            jsc.addIndented(type + "[].class});");
813        }
814 
815        jsc.add("");
816        jsc.add(name + "Handler = new FieldHandlerImpl(" + name + "FieldName, ");
817        jsc.append("null, null,");
818        jsc.addIndented(name + "GetMethod, " + name + "SetMethod, " + name + "Type);");
819        jsc.unindent();
820        jsc.add("");
821 
822        //-- Catch of exceptions
823        jsc.add("} catch (SecurityException e1) {");
824        jsc.indent();
825        jsc.add("throw new RuntimeException(e1.getMessage());");
826        jsc.unindent();
827        jsc.add("} catch (MappingException e1) {");
828        jsc.indent();
829        jsc.add("throw new RuntimeException(e1.getMessage());");
830        jsc.unindent();
831        jsc.add("} catch (NoSuchMethodException e1) {");
832        jsc.indent();
833        jsc.add("throw new RuntimeException(e1.getMessage());");
834        jsc.unindent();
835        jsc.add("}");
836 
837 
838 //       //-- JDOFieldDescriptorImpl constructor
839 //       jsc.add("// Instantiate " + name + " field descriptor");
840 //       jsc.add(name + "FieldDescr = new JDOFieldDescriptorImpl(");
841 //       jsc.append(name + "FieldName, " + name + "Type,");
842 //       jsc.indent();
843 //       jsc.add(name + "Handler, ");
844 //       jsc.append(Boolean.toString(fInfo.isTransient()) + ", ");
845 //       jsc.append("new String[] { },");
846 //       jsc.add("new int[] {SQLTypeInfos");
847 //       jsc.indent();
848 //       jsc.add(".javaType2sqlTypeNum(");
849 //
850 //       // TODO IS THERE NEED TO CHECK THIS?!
851 //       if ((type != null) && (type.length() > 0)) {
852 //           jsc.append(wrapperType + ".class) },");
853 //       }
854 //
855 //       jsc.unindent();
856 //       jsc.add("null, new String[] { " + name + "SqlName }, ");
857 //       jsc.append(Boolean.toString(manyNature.isDirty()) + ", ");
858 //       jsc.append(Boolean.toString(manyNature.isReadOnly()) + ");");
859 //       jsc.unindent();
860 
861        //-- invoke FieldDescriptorImpl constructor
862        jsc.add("// Instantiate " + name + " field descriptor");
863        jsc.add(name + "FieldDescr = new FieldDescriptorImpl(");
864        jsc.append(name + "FieldName, " + name + "Type,");
865        jsc.append(name + "Handler, ");
866        jsc.append(Boolean.toString(fInfo.isTransient()) + ");");
867        
868        jsc.add(name + "FieldDescr.addNature(FieldDescriptorJDONature.class.getName());");
869 
870        jsc.add("FieldDescriptorJDONature " + name + "FieldJdoNature = new FieldDescriptorJDONature(" 
871                + name + "FieldDescr);");
872 
873        jsc.add(name + "FieldJdoNature.setSQLName(null);");
874        jsc.add(name + "FieldJdoNature.setSQLType(new int[] {SQLTypeInfos");
875        jsc.append(".javaType2sqlTypeNum(");
876 
877        // TODO IS THERE NEED TO CHECK THIS?!
878        if ((type != null) && (type.length() > 0)) {
879            jsc.append(wrapperType + ".class) });");
880        }
881 
882        jsc.add(name + "FieldJdoNature.setManyKey(new String[] { " + name + "SqlName });");
883        jsc.add(name + "FieldJdoNature.setDirtyCheck(" + Boolean.toString(manyNature.isDirty()) + ");");
884        jsc.add(name + "FieldJdoNature.setReadOnly(" + Boolean.toString(manyNature.isReadOnly()) + ");");
885 
886        jsc.add("");
887 
888        jsc.add(name + "FieldDescr.setDirect(false);");
889        jsc.add(name + "FieldDescr.setName(\"" + name + "\");");
890        jsc.add(name + "FieldDescr.setRequired(" + xmlNature.isRequired() + ");");
891        // TODO support of other collection types
892        jsc.add(name + "FieldDescr.setCollection(FieldMappingCollectionType.ARRAY);");
893 
894        jsc.add("");
895 
896        //-- parent class descriptor
897        jsc.add(name + "FieldDescr.setContainingClassDescriptor(this);");
898        jsc.add(name + "FieldDescr.setClassDescriptor(new " + getLocalName(type) 
899                + "JDODescriptor());");
900        jsc.add(name + "FieldDescr.setMultivalued(true);");
901        
902        boolean isPrimaryKey = false;
903        if (cNature.getPrimaryKeys() != null) {
904            isPrimaryKey = (cNature.getPrimaryKeys().contains(xmlNature.getNodeName()));
905        }
906 
907        //-- fieldmapping
908        jsc.add(name + "FM.setIdentity(" + Boolean.toString(isPrimaryKey) + ");");
909        jsc.add(name + "FM.setDirect(false);");
910        jsc.add(name + "FM.setName(\"" + name + "\");");
911        jsc.add(name + "FM.setRequired(" + xmlNature.isRequired() + ");");
912        // TODO support of other collection types
913        jsc.add(name + "FM.setCollection(FieldMappingCollectionType.ARRAY);");
914        
915        //-- sql part
916        jsc.add("Sql " + name + "Sql = new Sql();");
917        jsc.add(name + "Sql.addName(\"" + sqlName + "\");");
918        jsc.add(name + "Sql.setManyKey(new String[] {\"" + sqlName + "\"});");
919        jsc.add(name + "FM.setSql(" + name + "Sql);");
920 
921        if ((type != null) && (type.length() > 0)) {
922            jsc.add(name + "FM.setType(\"" + type + "\");");
923        }
924 
925        jsc.add("choice.addFieldMapping(" + name + "FM);");
926        
927        return jsc;
928    }
929    
930    /**
931     * Returns the unqualified Java type name (i.e. without package).
932     *
933     * @param name the qualified Java type name.
934     * @return The unqualified Java type name.
935     */
936    private String getLocalName(final String name) {
937        // -- use getName method in case it's been overloaded
938        return JNaming.getLocalNameFromClassName(name);
939    }
940 }