View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
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  
17  package org.apache.jdo.impl.enhancer.generator;
18  
19  import java.lang.reflect.Modifier;
20  
21  import java.util.Iterator;
22  import java.util.Collection;
23  import java.util.List;
24  import java.util.ArrayList;
25  import java.util.HashMap;
26  import java.util.Properties;
27  
28  import java.io.Serializable;
29  import java.io.File;
30  import java.io.Writer;
31  import java.io.PrintWriter;
32  import java.io.FileWriter;
33  import java.io.BufferedWriter;
34  import java.io.InputStream;
35  import java.io.BufferedInputStream;
36  import java.io.FileInputStream;
37  import java.io.ObjectOutputStream;
38  import java.io.IOException;
39  import java.io.FileNotFoundException;
40  
41  import org.apache.jdo.impl.enhancer.meta.ExtendedMetaData;
42  import org.apache.jdo.impl.enhancer.meta.prop.EnhancerMetaDataPropertyImpl;
43  import org.apache.jdo.impl.enhancer.util.Support;
44  
45  
46  
47  
48  /***
49   *
50   */
51  public final class Main
52      extends Support
53  {
54      /***
55       *  The stream to write messages to.
56       */
57      private final PrintWriter out = new PrintWriter(System.out, true);
58  
59      /***
60       *  The stream to write error messages to.
61       */
62      private final PrintWriter err = new PrintWriter(System.err, true);
63  
64      /***
65       *  The command line options.
66       */
67      private final CmdLineOptions opts = new CmdLineOptions();
68  
69      /***
70       *
71       */
72      private final CodeWriter writer = new CodeWriter();
73  
74      /***
75       * The MetaData for generating classes.
76       */
77      private ExtendedMetaData meta = null;
78  
79      /***
80       *
81       */
82      public Main()
83      {}
84  
85      /***
86       *
87       */
88      public static final void main(String[] argv)
89      {
90          final Main gen = new Main();
91          try {
92              gen.opts.processArgs(argv);
93              gen.init();
94              gen.generate();
95          } catch(Exception ex) {
96              gen.printError(null, ex);
97          }
98      }
99  
100     /***
101      *  A class for holding the command line options.
102      */
103     private class CmdLineOptions
104     {
105         // final Collection inputFileNames = new ArrayList();
106         String destinationDirectory = null;
107         String jdoXMLModelFileName = null;
108         String jdoPropertiesFileName = null;
109         boolean verbose = false;
110         boolean quiet = false;
111         boolean forceWrite = false;
112         boolean noWrite = false;
113 
114         /***
115          * Print a usage message to System.err
116          */
117         public void usage() {
118             err.println("Usage: Main <options> <arguments>...");
119             err.println("Options:");
120             err.println("  -v, --verbose            print verbose output");
121 /*
122             err.println("  -q, --quiet              supress warnings");
123             err.println("  -n, --nowrite            never write classfiles");
124             err.println("  -f, --force              ever write classfiles");
125 */
126             err.println("  -d, --dest <dir>         destination directory for output files");
127             err.println("  -p, --properties <file>  use property file for meta data");
128 /*
129             err.println("  -x, --xmlmodel <file>    use JDO XML model file for meta data");
130 */
131             err.println();
132             err.println("Arguments:");
133             err.println();
134             err.println("Returns a non-zero value in case of errors.");
135             System.exit(1);
136         }
137 
138         /***
139          * Process command line options
140          */
141         protected int processArgs(String[] argv)
142         {
143             for (int i = 0; i < argv.length; i++) {
144                 final String arg = argv[i];
145                 if (arg.equals("-v")
146                     || arg.equals("--verbose")) {
147                     verbose = true;
148                     quiet = false;
149                     continue;
150                 }
151 /*
152                 if (arg.equals("-q")
153                     || arg.equals("--quiet")) {
154                     quiet = true;
155                     verbose = false;
156                     continue;
157                 }
158                 if (arg.equals("-f")
159                     || arg.equals("--force")) {
160                     forceWrite = true;
161                     continue;
162                 }
163                 if (arg.equals("-n")
164                     || arg.equals("--nowrite")) {
165                     noWrite = true;
166                     continue;
167                 }
168 */
169                 if (arg.equals("-d")
170                     || arg.equals("--dest")) {
171                     if (argv.length - i < 2) {
172                         printError("Missing argument to the -d/-dest option", null);
173                         usage();
174                     }
175                     destinationDirectory = argv[++i];
176                     continue;
177                 }
178                 if (arg.equals("-p") ||
179                     arg.equals("--properties")) {
180                     if (argv.length - i < 2) {
181                         printError("Missing argument to the -p/--properties option", null);
182                         usage();
183                     }
184                     jdoPropertiesFileName = argv[++i];
185                     continue;
186                 }
187 /*
188                 if (arg.equals("-x") ||
189                     arg.equals("--xmlmodel")) {
190                     if (argv.length - i < 2) {
191                         printError("Missing argument to the -p/--properties option", null);
192                         usage();
193                     }
194                     jdoXMLModelFileName = argv[++i];
195                     continue;
196                 }
197 */
198                 if (arg.length() > 0 && arg.charAt(0) == '-') {
199                     printError("Unrecognized option:" + arg, null);
200                     usage();
201                 }
202                 if (arg.length() == 0) {
203                     printMessage("Ignoring empty command line argument.");
204                     continue;
205                 }
206 
207                 //inputFileNames.add(arg);
208             }
209 
210             // The user must specify a destination directory
211             if (jdoPropertiesFileName == null) {
212                 printError("No destination directory specified", null);
213                 usage();
214             }
215 
216             // The user must specify a destination directory
217             if (destinationDirectory == null) {
218                 printError("No destination directory specified", null);
219                 usage();
220             }
221 
222             return 0;
223         }
224     }
225 
226     private void init()
227         throws FileNotFoundException, IOException
228     {
229         // load the properties
230         affirm(opts.jdoPropertiesFileName != null);
231         meta = new EnhancerMetaDataPropertyImpl(out, opts.verbose,
232                                                 opts.jdoPropertiesFileName);
233 
234         // create the destination directory
235         affirm(opts.destinationDirectory != null);
236         final File destinationDir = new File(opts.destinationDirectory);
237         boolean res = destinationDir.mkdirs();
238         if (!res) {
239             throw new IOException("unable to create destination directory: "
240                                   + "'" + destinationDir + "'");
241         }
242     }
243 
244     private void generate()
245     {
246         final String[] classes = meta.getKnownClasses();
247         for (int i = 0; i < classes.length; i++) {
248             final String classname = classes[i];
249             try {
250                 if (classname.indexOf('$') != -1) {
251                     printMessage("Skipping generation of nested class " + classname + "." +
252                                  " Note, a nested ObjectId class is generated with its pc class.");
253                     continue;
254                 }
255                 final Writer writer = createFileWriter(classname);
256                 this.writer.setWriter(writer);
257                 generateClass(classname);
258                 writer.close();
259             } catch(IOException ex) {
260                 printError("Error generating class '" + classname + "'.", ex);
261             }
262         }
263     }
264 
265     private void generateClass(final String classname)
266         throws IOException
267     {
268         affirm(classname);
269         
270         final String normClassName = NameHelper.normalizeClassName(classname);
271         printMessage("generating '" + normClassName + "'...");
272 
273         final</strong> String packageName = NameHelper.getPackageName(classname);
274         writer.writePackage(
275             packageName,
276             null);
277 
278         writer.writeImports(
279             null,
280             null);
281         
282         // write the class header and key class
283         final String oidClassName = meta.getKeyClass(classname);
284         if (oidClassName == null) {
285             writeClassHeader(classname);
286         } else {
287             final String oidPackageName
288                 = NameHelper.getPackageName(oidClassName);
289             affirm(packageName.equals(oidPackageName),
290                    "PC class and key class must be in same package.");
291 
292             final boolean enclosedOid
293                 = oidClassName.startsWith(classname + "$");
294             if (enclosedOid) {
295                 writeClassHeader(classname);
296                 writeOidClass(classname, oidClassName, enclosedOid);
297             } else {
298                 writeOidClass(classname, oidClassName, enclosedOid);
299                 writeClassHeader(classname);
300             }
301         }
302         
303         writeClassMembers(classname);
304 
305         // write the augmentation
306         final boolean isPC = meta.isPersistenceCapableClass(classname);
307         if (isPC) {
308             final boolean isPCRoot
309                 = meta.isPersistenceCapableRootClass(classname);
310             if (isPCRoot) {
311                 writePCRootMembers(classname);
312             }
313             writePCMembers(classname);
314             
315             writeClassMemberAccessors(classname);
316         }
317 
318         writer.writeClassEnd();
319     }
320 
321     private Writer createFileWriter(String classname)
322         throws IOException
323     {
324         final File file = new File(opts.destinationDirectory,
325                                    classname + ".java");
326         file.getAbsoluteFile().getParentFile().mkdirs();
327         return new BufferedWriter(new FileWriter(file));
328     }
329 
330     private void writeClassHeader(final String classname)
331         throws IOException
332     {
333         final boolean isPCRoot = meta.isPersistenceCapableRootClass(classname);
334         final String superclass = meta.getSuperClass(classname);
335 
336         String[] interfaces = null;
337         String[] comments = null;
338         interfaces
339             = new String[]{ ImplHelper.CLASSNAME_JDO_PERSISTENCE_CAPABLE };
340         writer.writeClassHeader(meta.getClassModifiers(classname),
341                                 ImplHelper.getClassName(classname),
342                                 superclass,
343                                 interfaces,
344                                 comments);
345     }
346 
347     private void writeClassMembers(final String classname)
348         throws IOException
349     {
350         writer.writeComments(1, new String[]{
351             "----------------------------------------------------------------------",
352             "Class Members:",
353             "----------------------------------------------------------------------"
354         });
355         writer.writeln();
356         
357         // write default constructor
358         writer.writeConstructor(
359             ImplHelper.getClassName(classname),
360             Modifier.PUBLIC,
361             null, null, null,
362             ImplHelper.getDefaultConstructorImpl(),
363             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
364 
365         // write default constructor
366         writer.writeConstructor(
367             ImplHelper.getClassName(classname),
368             Modifier.PUBLIC,
369             new String[]{ "str" },
370             new String[]{ "String" },
371             null,
372             ImplHelper.getDummyConstructorImpl(),
373             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
374 
375         final String[] fieldnames = meta.getKnownFields(classname);
376         final int n = (fieldnames != null ? fieldnames.length : 0);
377         
378         // write the fields and with their bean getters/setters
379         for (int i = 0; i < n; i++) {
380             final String fieldname = (String)fieldnames[i];
381             writeFieldMember(classname, fieldname);
382         }
383     }
384     
385     private void writeFieldMember(final String classname,
386                                   final String fieldname)
387         throws IOException
388     {
389         final String fieldtype = meta.getFieldType(classname, fieldname);
390         final int access = meta.getFieldModifiers(classname, fieldname);
391         final String normClassName = NameHelper.normalizeClassName(classname);
392         final List impl = new ArrayList();
393 
394         // the field
395         writer.writeField(
396             fieldname,
397             access,
398             fieldtype,
399             null, null);
400 
401         // do not write bean getters and setters for static fields
402         if ((access & Modifier.STATIC) != 0) {
403             return;
404         }
405 
406         // write bean getter (calling accessor)
407         impl.clear();
408         impl.add("//return this." + fieldname + ';');
409         final String accessor
410             = ImplHelper.createJDOFieldAccessorName(classname, fieldname);
411         impl.add("return " + normClassName + "." + accessor + "(this);");
412         writer.writeMethod(
413             createMethodName("get", fieldname),
414             Modifier.PUBLIC,
415             fieldtype,
416             null,
417             null,
418             null,
419             impl,
420             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
421 
422         // write bean setter (calling mutator)
423         impl.clear();
424         impl.add("//this." + fieldname + " = " + fieldname + ';');
425         final String mutator
426             = ImplHelper.createJDOFieldMutatorName(classname, fieldname);
427         impl.add(normClassName + "." + mutator + "(this, " + fieldname + ");");
428         writer.writeMethod(
429             createMethodName("set", fieldname),
430             Modifier.PUBLIC,
431             "void",
432             new String[]{ fieldname },
433             new String[]{ fieldtype },
434             null,
435             impl,
436             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
437     }
438 
439     private void writeClassMemberAccessors(final String classname)
440         throws IOException
441     {
442         writer.writeComments(1, new String[]{
443             "----------------------------------------------------------------------",
444             "Augmentation for Field Accessors and Mutators (added by enhancer):",
445             "----------------------------------------------------------------------"
446         });
447         writer.writeln();
448 
449         // write the fields and their access methods
450         final String[] fields = meta.getManagedFields(classname);
451         final int n = (fields != null ? fields.length : 0);
452         for (int i = 0; i < n; i++) {
453             final String fieldname = (String)fields[i];
454             writeFieldAccessors(classname, fieldname);
455         }
456     }
457     
458     private void writeFieldAccessors(final String classname,
459                                      final String fieldname)
460         throws IOException
461     {
462         final String fieldtype
463             = meta.getFieldType(classname, fieldname);
464         final int fieldnumber
465             = meta.getFieldNumber(classname, fieldname);
466         final boolean dfg
467             = meta.isDefaultFetchGroupField(classname, fieldname);
468         final int access
469             = meta.getFieldModifiers(classname, fieldname);
470         final int flags
471             = meta.getFieldFlags(classname, fieldname);
472 
473         final String accessor
474             = ImplHelper.createJDOFieldAccessorName(classname, fieldname);
475         final String mutator
476             = ImplHelper.createJDOFieldMutatorName(classname, fieldname);
477 
478         final String instancename
479             = "instance";
480         
481         // jdo accessor
482         {
483             affirm(((flags & meta.CHECK_READ) == 0)
484                    | (flags & meta.MEDIATE_READ) == 0);
485             final List impl;
486             if ((flags & meta.CHECK_READ) != 0) {
487                 impl = ImplHelper.getJDOFieldCheckReadImpl(fieldname,
488                                                            fieldtype,
489                                                            fieldnumber,
490                                                            instancename);
491             } else if ((flags & meta.MEDIATE_READ) != 0) {
492                 impl = ImplHelper.getJDOFieldMediateReadImpl(fieldname,
493                                                              fieldtype,
494                                                              fieldnumber,
495                                                              instancename);
496             } else {
497                 impl = ImplHelper.getJDOFieldDirectReadImpl(fieldname,
498                                                             fieldtype,
499                                                             fieldnumber,
500                                                             instancename);
501             }
502             writer.writeMethod(
503                 accessor,
504                 access | Modifier.STATIC | Modifier.FINAL,
505                 fieldtype,
506                 new String[]{ instancename },
507                 new String[]{ classname },
508                 null,
509                 impl,
510                 ImplHelper.COMMENT_ENHANCER_ADDED);
511         }
512         
513         // jdo mutator
514         {
515             affirm(((flags & meta.CHECK_WRITE) == 0)
516                    | (flags & meta.MEDIATE_WRITE) == 0);
517             final List impl;
518             if ((flags & meta.CHECK_WRITE) != 0) {
519                 impl = ImplHelper.getJDOFieldCheckWriteImpl(fieldname,
520                                                             fieldtype,
521                                                             fieldnumber,
522                                                             instancename,
523                                                             fieldname);
524             } else if ((flags & meta.MEDIATE_WRITE) != 0) {
525                 impl = ImplHelper.getJDOFieldMediateWriteImpl(fieldname,
526                                                               fieldtype,
527                                                               fieldnumber,
528                                                               instancename,
529                                                               fieldname);
530             } else {
531                 impl = ImplHelper.getJDOFieldDirectWriteImpl(fieldname,
532                                                              fieldtype,
533                                                              fieldnumber,
534                                                              instancename,
535                                                              fieldname);
536             }
537             writer.writeMethod(
538                 mutator,
539                 access | Modifier.STATIC | Modifier.FINAL,
540                 "void",
541                 new String[]{ instancename, fieldname },
542                 new String[]{ classname, fieldtype },
543                 null,
544                 impl,
545                 ImplHelper.COMMENT_ENHANCER_ADDED);
546         }
547     }
548     
549     private void writePCRootMembers(final String classname)
550         throws IOException
551     {
552         writer.writeComments(1, new String[]{
553             "----------------------------------------------------------------------",
554             "Augmentation for Persistence-Capable Root Classes (added by enhancer):",
555             "----------------------------------------------------------------------"
556         });
557         writer.writeln();
558 
559         // jdoStateManager
560         writer.writeField(
561             ImplHelper.FIELDNAME_JDO_STATE_MANAGER,
562             Modifier.PROTECTED | Modifier.TRANSIENT,
563             ImplHelper.CLASSNAME_JDO_STATE_MANAGER,
564             "null",
565             ImplHelper.COMMENT_ENHANCER_ADDED);
566 
567         // jdoFlags
568         writer.writeField(
569             ImplHelper.FIELDNAME_JDO_FLAGS,
570             Modifier.PROTECTED | Modifier.TRANSIENT,
571             "byte",
572             "0", // (ImplHelper.CLASSNAME_JDO_PERSISTENCE_CAPABLE
573             //       + "." + "READ_WRITE_OK"),
574             ImplHelper.COMMENT_ENHANCER_ADDED);
575 
576         // jdoReplaceStateManager
577         writer.writeMethod(
578             ImplHelper.METHODNAME_JDO_REPLACE_STATE_MANAGER,
579             Modifier.PUBLIC | Modifier.FINAL | Modifier.SYNCHRONIZED,
580             "void",
581             new String[]{ "sm" },
582             new String[]{ ImplHelper.CLASSNAME_JDO_STATE_MANAGER },
583             null,
584             ImplHelper.getJDOReplaceStateManagerImpl("sm"),
585             ImplHelper.COMMENT_ENHANCER_ADDED);
586         
587         // jdoReplaceFlags
588         writer.writeMethod(
589             ImplHelper.METHODNAME_JDO_REPLACE_FLAGS,
590             Modifier.PUBLIC | Modifier.FINAL,
591             "void", null, null, null,
592             ImplHelper.getJDOReplaceFlagsImpl(),
593             ImplHelper.COMMENT_ENHANCER_ADDED);
594 
595         // getPersistenceManager
596         writer.writeMethod(
597             ImplHelper.METHODNAME_JDO_GET_PERSISTENCE_MANAGER,
598             Modifier.PUBLIC | Modifier.FINAL,
599             ImplHelper.CLASSNAME_JDO_PERSISTENCE_MANAGER, null, null, null,
600             ImplHelper.getJDOStateManagerObjectDelegationImpl("getPersistenceManager(this)"),
601             ImplHelper.COMMENT_ENHANCER_ADDED);
602         
603         // getObjectId
604         writer.writeMethod(
605             ImplHelper.METHODNAME_JDO_GET_OBJECT_ID,
606             Modifier.PUBLIC | Modifier.FINAL,
607             Object.class.getName(), null, null, null,
608             ImplHelper.getJDOStateManagerObjectDelegationImpl("getObjectId(this)"),
609             ImplHelper.COMMENT_ENHANCER_ADDED);
610 
611         writer.writeMethod(
612             ImplHelper.METHODNAME_JDO_GET_TRANSACTIONAL_OBJECT_ID,
613             Modifier.PUBLIC | Modifier.FINAL,
614             Object.class.getName(), null, null, null,
615             ImplHelper.getJDOStateManagerObjectDelegationImpl("getTransactionalObjectId(this)"),
616             ImplHelper.COMMENT_ENHANCER_ADDED);
617 
618         // jdoGetVersion
619         writer.writeMethod(
620             ImplHelper.METHODNAME_JDO_GET_VERSION,
621             Modifier.PUBLIC | Modifier.FINAL,
622             Object.class.getName(), null, null, null,
623             // TODO: generate real method body
624             ImplHelper.getNotYetImplemented(
625                 ImplHelper.METHODNAME_JDO_GET_VERSION),
626             ImplHelper.COMMENT_ENHANCER_ADDED);
627 
628         // is-methods
629         writer.writeMethod(
630             ImplHelper.METHODNAME_JDO_IS_PERSISTENT,
631             Modifier.PUBLIC | Modifier.FINAL,
632             "boolean", null, null, null,
633             ImplHelper.getJDOStateManagerBooleanDelegationImpl("isPersistent(this)"),
634             ImplHelper.COMMENT_ENHANCER_ADDED);
635 
636         writer.writeMethod(
637             ImplHelper.METHODNAME_JDO_IS_TRANSACTIONAL,
638             Modifier.PUBLIC | Modifier.FINAL,
639             "boolean", null, null, null,
640             ImplHelper.getJDOStateManagerBooleanDelegationImpl("isTransactional(this)"),
641             ImplHelper.COMMENT_ENHANCER_ADDED);
642 
643         writer.writeMethod(
644             ImplHelper.METHODNAME_JDO_IS_NEW,
645             Modifier.PUBLIC | Modifier.FINAL,
646             "boolean", null, null, null,
647             ImplHelper.getJDOStateManagerBooleanDelegationImpl("isNew(this)"),
648             ImplHelper.COMMENT_ENHANCER_ADDED);
649 
650         writer.writeMethod(
651             ImplHelper.METHODNAME_JDO_IS_DELETED,
652             Modifier.PUBLIC | Modifier.FINAL,
653             "boolean", null, null, null,
654             ImplHelper.getJDOStateManagerBooleanDelegationImpl("isDeleted(this)"),
655             ImplHelper.COMMENT_ENHANCER_ADDED);
656 
657         writer.writeMethod(
658             ImplHelper.METHODNAME_JDO_IS_DIRTY,
659             Modifier.PUBLIC | Modifier.FINAL,
660             "boolean", null, null, null,
661             ImplHelper.getJDOStateManagerBooleanDelegationImpl("isDirty(this)"),
662             ImplHelper.COMMENT_ENHANCER_ADDED);
663 
664         writer.writeMethod(
665             ImplHelper.METHODNAME_JDO_IS_DETACHED,
666             Modifier.PUBLIC | Modifier.FINAL,
667             "boolean", null, null, null,
668             // TODO: generate real method body
669             ImplHelper.getNotYetImplemented(
670                 ImplHelper.METHODNAME_JDO_IS_DETACHED),
671             ImplHelper.COMMENT_ENHANCER_ADDED);
672 
673         // makeDirty
674         writer.writeMethod(
675             ImplHelper.METHODNAME_JDO_MAKE_DIRTY,
676             Modifier.PUBLIC | Modifier.FINAL,
677             "void",
678             new String[]{ "fieldname" },
679             new String[]{ String.class.getName() },
680             null,
681             ImplHelper.getJDOStateManagerVoidDelegationImpl("makeDirty(this, fieldname)"),
682             ImplHelper.COMMENT_ENHANCER_ADDED);
683 
684         // replaceFields
685         writer.writeMethod(
686             ImplHelper.METHODNAME_JDO_REPLACE_FIELDS,
687             Modifier.PUBLIC | Modifier.FINAL,
688             "void",
689             new String[]{ "fieldnumbers" },
690             new String[]{ "int[]" },
691             null,
692             ImplHelper.getJDOFieldIterationImpl("fieldnumbers",
693                                                 ImplHelper.METHODNAME_JDO_REPLACE_FIELD),
694             ImplHelper.COMMENT_ENHANCER_ADDED);
695 
696         // provideFields
697         writer.writeMethod(
698             ImplHelper.METHODNAME_JDO_PROVIDE_FIELDS,
699             Modifier.PUBLIC | Modifier.FINAL,
700             "void",
701             new String[]{ "fieldnumbers" },
702             new String[]{ "int[]" },
703             null,
704             ImplHelper.getJDOFieldIterationImpl("fieldnumbers",
705                                                 ImplHelper.METHODNAME_JDO_PROVIDE_FIELD),
706             ImplHelper.COMMENT_ENHANCER_ADDED);
707 
708         // preSerialize
709         writer.writeMethod(
710             ImplHelper.METHODNAME_JDO_PRE_SERIALIZE,
711             Modifier.PROTECTED | Modifier.FINAL,
712             "void", null, null, null,
713             ImplHelper.getJDOStateManagerVoidDelegationImpl("preSerialize(this)"),
714             ImplHelper.COMMENT_ENHANCER_ADDED);
715 
716         // write method clone()
717         writer.writeMethod(
718             "clone",
719             Modifier.PUBLIC,
720             "Object",
721             null,
722             null,
723             new String[]{ "java.lang.CloneNotSupportedException" },
724             ImplHelper.getCloneImpl(classname),
725             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
726 
727     }
728 
729     private void writePCMembers(final String classname)
730         throws IOException
731     {
732         writer.writeComments(1, new String[]{
733             "----------------------------------------------------------------------",
734             "Augmentation for Persistence-Capable Classes (added by enhancer):",
735             "----------------------------------------------------------------------"
736         });
737         writer.writeln();
738         
739         final String[] managedFieldNames
740             = meta.getManagedFields(classname);
741         final String[] managedFieldTypes
742             = meta.getFieldType(classname, managedFieldNames);
743         final boolean isPCRoot
744             = meta.isPersistenceCapableRootClass(classname);
745 
746         writePCStaticMembers(classname);
747 
748         // jdoNewInstance
749         writer.writeMethod(
750             ImplHelper.METHODNAME_JDO_NEW_INSTANCE,
751             Modifier.PUBLIC,
752             ImplHelper.CLASSNAME_JDO_PERSISTENCE_CAPABLE,
753             new String[]{ "sm" },
754             new String[]{ ImplHelper.CLASSNAME_JDO_STATE_MANAGER },
755             null,
756             ImplHelper.getJDONewInstanceImpl(classname,
757                                              "sm"),
758             ImplHelper.COMMENT_ENHANCER_ADDED);
759 
760         // jdoNewInstance
761         writer.writeMethod(
762             ImplHelper.METHODNAME_JDO_NEW_INSTANCE,
763             Modifier.PUBLIC,
764             ImplHelper.CLASSNAME_JDO_PERSISTENCE_CAPABLE,
765             new String[]{ "sm", "oid" },
766             new String[]{ ImplHelper.CLASSNAME_JDO_STATE_MANAGER, "Object" },
767             null,
768             ImplHelper.getJDONewInstanceKeyImpl(classname,
769                                                 //oidClassName,
770                                                 "sm",
771                                                 "oid"),
772                                                 //keyFieldNames),
773             ImplHelper.COMMENT_ENHANCER_ADDED);
774 
775         // jdoReplaceField
776         writer.writeMethod(
777             ImplHelper.METHODNAME_JDO_REPLACE_FIELD,
778             Modifier.PUBLIC,
779             "void",
780             new String[]{ "fieldnumber" },
781             new String[]{ "int" },
782             null,
783             ImplHelper.getJDOReplaceFieldImpl("fieldnumber",
784                                               isPCRoot,
785                                               managedFieldNames,
786                                               managedFieldTypes),
787             ImplHelper.COMMENT_ENHANCER_ADDED);
788 
789         // jdoProvideField(s)
790         writer.writeMethod(
791             ImplHelper.METHODNAME_JDO_PROVIDE_FIELD,
792                            Modifier.PUBLIC,
793             "void",
794             new String[]{ "fieldnumber" },
795             new String[]{ "int" },
796             null,
797             ImplHelper.getJDOProvideFieldImpl("fieldnumber",
798                                               isPCRoot,
799                                               managedFieldNames,
800                                               managedFieldTypes),
801             ImplHelper.COMMENT_ENHANCER_ADDED);
802 
803         // jdoCopyFields
804         writer.writeMethod(
805             ImplHelper.METHODNAME_JDO_COPY_FIELDS,
806             Modifier.PUBLIC,
807             "void",
808             new String[]{ "pc", "fieldnumbers" },
809             new String[]{ Object.class.getName(), "int[]" },
810             null,
811             ImplHelper.getJDOCopyFieldsImpl(classname,
812                                             "pc",
813                                             "fieldnumbers"),
814             ImplHelper.COMMENT_ENHANCER_ADDED);
815 
816         // jdoCopyField
817         writer.writeMethod(
818             ImplHelper.METHODNAME_JDO_COPY_FIELD,
819             Modifier.PROTECTED | Modifier.FINAL,
820             "void",
821             new String[]{ "pc", "fieldnumber" },
822             new String[]{ classname, "int" },
823             null,
824             ImplHelper.getJDOCopyFieldImpl(classname,
825                                            "pc",
826                                            "fieldnumber",
827                                            managedFieldNames,
828                                            isPCRoot),
829             ImplHelper.COMMENT_ENHANCER_ADDED);
830 
831         writePCKeyHandlingMembers(classname);
832 
833         writePCSerializationMembers(classname);
834     }
835 
836     private void writePCStaticMembers(final String classname)
837         throws IOException
838     {
839         final String[] managedFieldNames
840             = meta.getManagedFields(classname);
841         final String superPC
842             = meta.getPersistenceCapableSuperClass(classname);
843         final String[] managedFieldTypes
844             = meta.getFieldType(classname, managedFieldNames);
845         final int[] managedFieldFlags
846             = meta.getFieldFlags(classname, managedFieldNames);
847         final boolean isPCRoot 
848             = meta.isPersistenceCapableRootClass(classname);
849 
850         // inheritedFieldCount
851         writer.writeField(
852             ImplHelper.FIELDNAME_JDO_INHERITED_FIELD_COUNT,
853             Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
854             "int",
855             null,
856             ImplHelper.COMMENT_ENHANCER_ADDED);
857 
858         // fieldNames
859         writer.writeField(
860             ImplHelper.FIELDNAME_JDO_FIELD_NAMES,
861             Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
862             "String[]",
863             null,
864             ImplHelper.COMMENT_ENHANCER_ADDED);
865 
866         // fieldTypes
867         writer.writeField(
868             ImplHelper.FIELDNAME_JDO_FIELD_TYPES,
869             Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
870             "Class[]",
871             null,
872             ImplHelper.COMMENT_ENHANCER_ADDED);
873 
874         // fieldFlags
875         writer.writeField(
876             ImplHelper.FIELDNAME_JDO_FIELD_FLAGS,
877             Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
878             "byte[]",
879             null,
880             ImplHelper.COMMENT_ENHANCER_ADDED);
881 
882         // PC superclass
883         writer.writeField(
884             ImplHelper.FIELDNAME_JDO_PC_SUPERCLASS,
885             Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
886             "Class",
887             null,
888             ImplHelper.COMMENT_ENHANCER_ADDED);
889 
890         // static initializer
891         writer.writeStaticInitializer(
892             ImplHelper.getStaticInitializerImpl(classname,
893                                                 superPC,
894                                                 managedFieldNames,
895                                                 managedFieldTypes,
896                                                 managedFieldFlags),
897             ImplHelper.COMMENT_ENHANCER_ADDED);
898 
899         // jdoGetManagedFieldCount
900         writer.writeMethod(
901             ImplHelper.METHODNAME_JDO_GET_MANAGED_FIELD_COUNT,
902             Modifier.PROTECTED | Modifier.STATIC,
903             "int", null, null, null,
904             ImplHelper.getJDOGetManagedFieldCountImpl(
905                 isPCRoot, superPC, managedFieldNames.length),
906             ImplHelper.COMMENT_ENHANCER_ADDED);
907     }
908 
909     private void writePCKeyHandlingMembers(final String classname)
910         throws IOException
911     {
912         final boolean isPCRoot
913             = meta.isPersistenceCapableRootClass(classname);
914         final String oidClassName
915             = NameHelper.normalizeClassName(meta.getKeyClass(classname));
916 
917         // generate these methods if this is the PC root class or if
918         // there's a key class definition
919         if (!isPCRoot && oidClassName == null) {
920             return;
921         }
922 
923         final String superOidClassName
924             = NameHelper.normalizeClassName(meta.getSuperKeyClass(classname));
925         final String[] keyFieldNames
926             = meta.getKeyFields(classname);
927         final String[] keyFieldTypes
928             = meta.getFieldType(classname, keyFieldNames);
929         final int[] keyFieldNumbers
930             = meta.getFieldNumber(classname, keyFieldNames);
931 
932         // jdoNewOidInstance
933         writer.writeMethod(
934             ImplHelper.METHODNAME_JDO_NEW_OID_INSTANCE,
935             Modifier.PUBLIC,
936             Object.class.getName(), null, null, null,
937             ImplHelper.getJDONewOidInstanceImpl(oidClassName),
938             ImplHelper.COMMENT_ENHANCER_ADDED);
939 
940         writer.writeMethod(
941             ImplHelper.METHODNAME_JDO_NEW_OID_INSTANCE,
942             Modifier.PUBLIC,
943             Object.class.getName(),
944             new String[]{ "o" },
945             new String[]{ "Object" },
946             null,
947             ImplHelper.getJDONewOidInstanceImpl(oidClassName,
948                                                 "o"),
949             ImplHelper.COMMENT_ENHANCER_ADDED);
950 
951         // jdoCopyKeyFieldsTo/FromOid
952         writer.writeMethod(
953             ImplHelper.METHODNAME_JDO_COPY_KEY_FIELDS_TO_OID,
954             Modifier.PUBLIC,
955             "void",
956             new String[]{ "oid" },
957             new String[]{ "Object" },
958             null,
959             ImplHelper.getJDOCopyKeyFieldsToOid(oidClassName,
960                                                 superOidClassName,
961                                                 "oid",
962                                                 keyFieldNames),
963             ImplHelper.COMMENT_ENHANCER_ADDED);
964 
965         writer.writeMethod(
966             ImplHelper.METHODNAME_JDO_COPY_KEY_FIELDS_FROM_OID,
967             Modifier.PROTECTED,
968             "void",
969             new String[]{ "oid" },
970             new String[]{ "Object" },
971             null,
972             ImplHelper.getJDOCopyKeyFieldsFromOid(oidClassName,
973                                                   superOidClassName,
974                                                   "oid",
975                                                   keyFieldNames),
976             ImplHelper.COMMENT_ENHANCER_ADDED);
977 
978         writer.writeMethod(
979             ImplHelper.METHODNAME_JDO_COPY_KEY_FIELDS_TO_OID,
980             Modifier.PUBLIC,
981             "void",
982             new String[]{ "ofs", "oid" },
983             new String[]{ ImplHelper.CLASSNAME_JDO_OBJECT_ID_FIELD_SUPPLIER,
984                           "Object" },
985             null,
986             ImplHelper.getJDOCopyKeyFieldsToOid(oidClassName,
987                                                 superOidClassName,
988                                                 "ofs",
989                                                 "oid",
990                                                 keyFieldNames,
991                                                 keyFieldTypes,
992                                                 keyFieldNumbers),
993             ImplHelper.COMMENT_ENHANCER_ADDED);
994 
995         writer.writeMethod(
996             ImplHelper.METHODNAME_JDO_COPY_KEY_FIELDS_FROM_OID,
997             Modifier.PUBLIC,
998             "void",
999             new String[]{ "ofc", "oid" },
1000             new String[]{ ImplHelper.CLASSNAME_JDO_OBJECT_ID_FIELD_CONSUMER,
1001                           "Object" },
1002             null,
1003             ImplHelper.getJDOCopyKeyFieldsFromOid(oidClassName,
1004                                                   superOidClassName,
1005                                                   "ofc",
1006                                                   "oid",
1007                                                   keyFieldNames,
1008                                                   keyFieldTypes,
1009                                                   keyFieldNumbers),
1010             ImplHelper.COMMENT_ENHANCER_ADDED);
1011     }
1012 
1013     private void writePCSerializationMembers(final String classname)
1014         throws IOException
1015     {
1016         final long serialUID
1017             = createJDOVersionUID(classname);
1018 
1019         //^olsen: to adapt
1020         writer.writeField(
1021             ImplHelper.FIELDNAME_SERIAL_VERSION_UID,
1022             Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
1023             "long",
1024             ImplHelper.getSerialVersionUIDInitValue(serialUID),
1025             new String[]{ "only a dummy value yet"});
1026         //ImplHelper.COMMENT_ENHANCER_ADDED);
1027 
1028         writer.writeMethod(
1029             ImplHelper.METHODNAME_WRITE_OBJECT,
1030             Modifier.PRIVATE,
1031             "void",
1032             new String[]{ "out" },
1033             new String[]{ ObjectOutputStream.class.getName() },
1034             new String[]{ IOException.class.getName() },
1035             ImplHelper.getWriteObjectImpl("out"),
1036             ImplHelper.COMMENT_ENHANCER_ADDED);
1037     }
1038 
1039     private void writeOidClass(final String classname,
1040                                final String oidClassName,
1041                                final boolean enclosedOid)
1042         throws IOException
1043     {
1044         final int indent = (enclosedOid ? 1 : 0);
1045         writer.writeComments(indent, new String[]{
1046             "----------------------------------------------------------------------",
1047             "Key Class:",
1048             "----------------------------------------------------------------------"
1049         });
1050         writer.writeln();
1051 
1052         writer.setInitialIndents(indent);
1053 
1054         final String superOidClassName
1055             = NameHelper.normalizeClassName(meta.getSuperKeyClass(classname));
1056 
1057         writer.writeClassHeader(
1058             (enclosedOid ? Modifier.PUBLIC | Modifier.STATIC : 0),
1059             oidClassName,
1060             superOidClassName,
1061             new String[]{ Serializable.class.getName() },
1062             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
1063 
1064         final boolean isPCRoot
1065             = meta.isPersistenceCapableRootClass(classname);
1066 
1067         final String[] pknames = meta.getKeyFields(classname);
1068         final String[] pktypes = meta.getFieldType(classname, pknames);
1069 
1070         // write the PK-fields
1071         for (int i = 0; i < pknames.length; i++) {
1072             writer.writeField(
1073                 pknames[i],
1074                 Modifier.PUBLIC,
1075                 pktypes[i],
1076                 null,
1077                 null);
1078         }
1079 
1080         // write default constructor
1081         writer.writeConstructor(
1082             NameHelper.getClassName(oidClassName),
1083             Modifier.PUBLIC,
1084             null, null, null,
1085             ImplHelper.getDefaultConstructorImpl(),
1086             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
1087 
1088         // write string argument constructor
1089         writer.writeConstructor(
1090             NameHelper.getClassName(oidClassName),
1091             Modifier.PUBLIC,
1092             new String[]{ "str" },
1093             new String[]{ "String" },
1094             null,
1095             ImplHelper.getOidStringArgConstructorImpl(superOidClassName,
1096                                                       "str"),
1097             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
1098 
1099         // hashCode
1100         writer.writeMethod(
1101             "hashCode",
1102             Modifier.PUBLIC,
1103             "int",
1104             null,
1105             null,
1106             null,
1107             ImplHelper.getOidHashCodeImpl(pknames,
1108                                           pktypes,
1109                                           isPCRoot),
1110             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
1111 
1112         // equals
1113         writer.writeMethod(
1114             "equals", Modifier.PUBLIC, "boolean",
1115             new String[]{ "pk" },
1116             new String[]{ Object.class.getName() },
1117             null,
1118             ImplHelper.getOidEqualsImpl(oidClassName,
1119                                         pknames,
1120                                         pktypes,
1121                                         "pk",
1122                                         isPCRoot),
1123             ImplHelper.COMMENT_NOT_ENHANCER_ADDED);
1124 
1125         writer.writeClassEnd();
1126         writer.setInitialIndents(0);
1127     }
1128 
1129     //^olsen to adapt
1130     static private long createJDOVersionUID(final String classname)
1131     {
1132         return classname.hashCode();
1133     }
1134 
1135     static private String createMethodName(final String prefix,
1136                                            final String fieldname)
1137     {
1138         return (prefix + Character.toUpperCase(fieldname.charAt(0))
1139                 + fieldname.substring(1));
1140     }
1141 
1142     private void printMessage(String msg)
1143     {
1144         out.println(msg);
1145     }
1146 
1147     private void printError(String    msg,
1148                                    Throwable ex)
1149     {
1150         if (msg != null) {
1151             err.println(msg + (ex != null ? ": " + ex.getMessage() : ""));
1152         }
1153         if (ex != null) {
1154             ex.printStackTrace(err);
1155         }
1156     }
1157 }