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