KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > xml > xmlc > compiler > ClassGenerator


1 /*
2  * Enhydra Java Application Server Project
3  *
4  * The contents of this file are subject to the Enhydra Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License on
7  * the Enhydra web site ( http://www.enhydra.org/ ).
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11  * the License for the specific terms governing rights and limitations
12  * under the License.
13  *
14  * The Initial Developer of the Enhydra Application Server is Lutris
15  * Technologies, Inc. The Enhydra Application Server and portions created
16  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17  * All Rights Reserved.
18  *
19  * Contributor(s):
20  *
21  * $Id: ClassGenerator.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
22  */

23
24 package org.enhydra.xml.xmlc.compiler;
25
26 import java.io.File JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.PrintWriter JavaDoc;
29
30 import org.enhydra.xml.xmlc.XMLCException;
31 import org.enhydra.xml.xmlc.XMLObject;
32 import org.enhydra.xml.xmlc.codegen.IndentWriter;
33 import org.enhydra.xml.xmlc.codegen.JavaClass;
34 import org.enhydra.xml.xmlc.codegen.JavaCode;
35 import org.enhydra.xml.xmlc.codegen.JavaField;
36 import org.enhydra.xml.xmlc.codegen.JavaLang;
37 import org.enhydra.xml.xmlc.codegen.JavaMethod;
38 import org.enhydra.xml.xmlc.codegen.JavaModifiers;
39 import org.enhydra.xml.xmlc.codegen.JavaParameter;
40 import org.enhydra.xml.xmlc.deferredparsing.DeferredParsingAccessorGenerator;
41 import org.enhydra.xml.xmlc.deferredparsing.DeferredParsingDocBuilderGenerator;
42 import org.enhydra.xml.xmlc.dom.AccessorGenerator;
43 import org.enhydra.xml.xmlc.dom.DocBuilderGenerator;
44 import org.enhydra.xml.xmlc.dom.XMLCDocument;
45 import org.enhydra.xml.xmlc.dom.XMLCDomFactory;
46 import org.enhydra.xml.xmlc.dom.XMLCDomFactoryCache;
47 import org.enhydra.xml.xmlc.metadata.DocumentClass;
48 import org.enhydra.xml.xmlc.metadata.GenerateType;
49 import org.enhydra.xml.xmlc.metadata.MetaData;
50 import org.w3c.dom.Document JavaDoc;
51
52 /**
53  * Generate XML classes and interfaces.
54  */

55 public class ClassGenerator {
56     /*
57      * List of standard imports for generated classes and interfaces.
58      */

59     private static final String JavaDoc[] IMPORT_LIST = {
60         "org.w3c.dom.*",
61     };
62
63     /*
64      * List of standard imports for generated classes.
65      */

66     private static final String JavaDoc[] CLASS_IMPORT_LIST = {
67 // "org.enhydra.xml.xmlc.XMLCUtil",
68
// "org.enhydra.xml.xmlc.XMLCError",
69
"org.enhydra.xml.xmlc.dom.XMLCDomFactory",
70 // "org.enhydra.xml.dom.DOMOps"
71
};
72
73     /*
74      * List of additional imports for deferred parsing support.
75      */

76     private static final String JavaDoc[] DEFERRED_PARSING_CLASS_IMPORT_LIST = {
77         "org.enhydra.xml.xmlc.deferredparsing.DocumentLoader",
78         "org.enhydra.xml.xmlc.deferredparsing.StandardDocumentLoader",
79     };
80
81     /**
82      * Name of field containing document loader reference for deferred parsing.
83      */

84     public static final String JavaDoc DOC_LOADER_FIELD_NAME = "fDocumentLoader";
85
86     /**
87      * Class name of the document loader for deferred parsing.
88      */

89     public static final String JavaDoc DOC_LOADER_CLASS_NAME = "DocumentLoader";
90
91     /**
92      * Name of field containing delegate reference.
93      */

94     public static final String JavaDoc DELEGATE_FIELD_NAME = "fDelegate";
95
96     /**
97      * Name for the static field holding the XMLCDomFactory.
98      */

99     public static final String JavaDoc DOM_FACTORY_FIELD_NAME = "fDOMFactory";
100
101     /*
102      * Header to place in each generated file.
103      */

104     private static final String JavaDoc[] WARNING_HEADER = {
105         "/*",
106         " ************************************",
107         " * XMLC GENERATED CODE, DO NOT EDIT *",
108         " ************************************",
109         " */"
110     };
111
112     /**
113      * Document metadata.
114      */

115     private MetaData fMetaData;
116     private DocumentClass fDocumentClass;
117
118     /*
119      * What to generate.
120      */

121     private GenerateType fGenerate;
122
123     /*
124      * XMLC DOM management object.
125      */

126     private XMLCDocument fXmlcDoc;
127
128     /*
129      * Source document.
130      */

131     private Document fDocument;
132
133     /**
134      * Table of elements used by code generators.
135      */

136     private ElementTable fElementTable;
137
138     /*
139      * Access method creator.
140      */

141     private AccessMethods fAccessMethods;
142
143     /*
144      * Access constants creator.
145      */

146     private AccessConsts fAccessConsts;
147
148     /**
149      * DOM Accessor generator.
150      */

151     private AccessorGenerator fAccessorGenerator;
152
153     /*
154      * Document builder generator.
155      */

156     private DocBuilderGenerator fDocBuilderGenerator;
157
158     /**
159      * Class being constructed.
160      */

161     JavaClass fDocClass;
162
163     /**
164      * Construct an object.
165      *
166      * @param metaData Document metadata.
167      * @param xmlcDoc XMLC DOM object containing the document.
168      * @param methodOutput Write information about the generated
169      * methods to this file if not NULL.
170      * @exception XMLCException If an error is detected.
171      */

172     public ClassGenerator(MetaData metaData,
173                           XMLCDocument xmlcDoc,
174                           PrintWriter JavaDoc methodOutput)
175             throws XMLCException {
176         // Setup fields
177
fMetaData = metaData;
178         fXmlcDoc = xmlcDoc;
179         fDocumentClass = fMetaData.getDocumentClass();
180         fGenerate = fDocumentClass.getGenerate();
181         fDocument = xmlcDoc.getDocument();
182
183         // Get the deferred parsing specific generators if deferred
184
// parsing support is desired. Otherwise, get the DOM specific
185
// generators
186
if (fDocumentClass.getDeferredParsing()) {
187         fAccessorGenerator =
188         new DeferredParsingAccessorGenerator();
189         fDocBuilderGenerator =
190         new DeferredParsingDocBuilderGenerator();
191     } else {
192         XMLCDomFactory domFactory = fXmlcDoc.getDomFactory();
193         fAccessorGenerator = domFactory.createAccessorGenerator(fDocument);
194         fDocBuilderGenerator = domFactory.createDocBuilderGenerator(fDocument);
195     }
196
197         fElementTable = new ElementTable(metaData, fXmlcDoc);
198         fAccessMethods = new AccessMethods(fMetaData, fElementTable,
199                                            fAccessorGenerator);
200         fAccessConsts = new AccessConsts(fMetaData, fElementTable);
201
202         // Build class and imports
203
createClass();
204         fAccessMethods.generateCode(fDocClass);
205         fAccessConsts.generateCode(fDocClass);
206
207         // Construct the rest of the class.
208
createConstructors();
209     createDomFactoryField();
210     if (fDocumentClass.getDeferredParsing()) {
211         createDeferredParsingFields();
212     }
213     
214         createBuildDocument();
215         fAccessMethods.generateCode(fDocClass);
216
217         if (fDocumentClass.getDelegateSupport()) {
218             createDelegateSupport();
219         }
220         createClassIdent();
221         createSourceFileConst();
222
223         // Output information about created and omitted accessors.
224
if (methodOutput != null) {
225             fAccessMethods.printAccessMethods(methodOutput);
226             fAccessConsts.printAccessConstants(methodOutput);
227             fAccessMethods.printOmittedIds(methodOutput);
228             fAccessConsts.printOmittedConstants(methodOutput);
229         }
230     }
231
232     /**
233      * Create the default constructor (no arguments).
234      */

235     private void createDefaultConstructor() {
236         JavaMethod constr
237             = new JavaMethod(fDocumentClass.getUnqualClassName(),
238                              null,
239                              JavaModifiers.PUBLIC,
240                              null,
241                              new String JavaDoc[] {"Default constructor."});
242         if (fDocumentClass.getDeferredParsing()) {
243         constr.getCode().addln("this(StandardDocumentLoader.getInstance());");
244         }
245         constr.getCode().addln("buildDocument();");
246         fDocClass.addConstructor(constr);
247     }
248
249     /**
250      * Create the buildDocument optional constructor.
251      */

252     private void createOptionalBuildDocConstructor() {
253         String JavaDoc[] buildArgDoc = {
254             "buildDOM If false, the DOM will not be built until",
255             "buildDocument() is called by the derived class. If true, ",
256             "the DOM is built immediatly."
257         };
258         JavaParameter buildArg
259             = new JavaParameter("buildDOM", "boolean", buildArgDoc);
260
261         JavaMethod constr
262             = new JavaMethod(fDocumentClass.getUnqualClassName(),
263                              null,
264                              JavaModifiers.PUBLIC,
265                              new JavaParameter[] {buildArg},
266                              new String JavaDoc[] {"Constructor with optional building of the DOM."});
267         if (fDocumentClass.getDeferredParsing()) {
268         constr.getCode().addln("this(StandardDocumentLoader.getInstance(), buildDOM);");
269         } else constr.getCode().addln(new String JavaDoc[] {
270             "if (buildDOM) {",
271             " buildDocument();",
272             "}"
273         });
274         fDocClass.addConstructor(constr);
275     }
276
277     /**
278      * Create the deferred parsing constructor
279      */

280     private void createDeferredParsingConstructors() {
281         String JavaDoc[] buildArgDoc = {
282             "buildDOM If false, the DOM will not be built until",
283             "buildDocument() is called by the derived class. If true, ",
284             "the DOM is built immediatly."
285         };
286         JavaParameter buildArg
287             = new JavaParameter("buildDOM", "boolean", buildArgDoc);
288
289         String JavaDoc[] loaderArgDoc = {
290             "loader the document loader to delegate document",
291         "creation to."
292         };
293         JavaParameter loaderArg
294             = new JavaParameter("loader", "DocumentLoader", buildArgDoc);
295
296         JavaMethod constr
297             = new JavaMethod(fDocumentClass.getUnqualClassName(),
298                              null,
299                              JavaModifiers.PUBLIC,
300                              new JavaParameter[] {loaderArg, buildArg},
301                              new String JavaDoc[] {
302                     "Constructor for deferred parsing support.",
303                 "The supplied document loader is used to",
304                 "create the DOM."
305                  });
306         constr.getCode().addln(new String JavaDoc[] {
307         DOC_LOADER_FIELD_NAME + " = loader;",
308             "if (buildDOM) {",
309             " buildDocument();",
310             "}"
311         });
312         fDocClass.addConstructor(constr);
313
314         constr
315             = new JavaMethod(fDocumentClass.getUnqualClassName(),
316                              null,
317                              JavaModifiers.PUBLIC,
318                              new JavaParameter[] {loaderArg},
319                              new String JavaDoc[] {
320                     "Constructor for deferred parsing support.",
321                 "The supplied document loader is used to",
322                 "create the DOM."
323                  });
324         constr.getCode().addln("this(loader, true);");
325         fDocClass.addConstructor(constr);
326     }
327
328     /**
329      * Create the copy constructor.
330      */

331     private void createCopyConstructor() {
332         //FIXME: Should really use interface name if one is generated.
333
JavaParameter srcArg
334             = new JavaParameter("src",
335                                 fDocumentClass.getUnqualClassName(),
336                                 "The document to clone.");
337
338         JavaMethod constr
339             = new JavaMethod(fDocumentClass.getUnqualClassName(),
340                              null,
341                              JavaModifiers.PUBLIC,
342                              new JavaParameter[] {srcArg},
343                              new String JavaDoc[] {"Copy constructor."});
344         if (fDocumentClass.getDeferredParsing()) {
345         constr.getCode().addln(DOC_LOADER_FIELD_NAME +
346                    " = src.getDocumentLoader();");
347         }
348         constr.getCode().addln(new String JavaDoc[] {
349             "setDocument((Document)src.getDocument().cloneNode(true), src.getMIMEType(), src.getEncoding());",
350             "syncAccessMethods();"
351         });
352         fDocClass.addConstructor(constr);
353     }
354
355     /**
356      * Create the clone method.
357      */

358     private void createCloneMethod() {
359         JavaParameter deepArg
360             = new JavaParameter("deep", "boolean",
361                                 "Must be true, only deep clone is supported.");
362
363         JavaMethod method
364             = new JavaMethod("cloneNode",
365                              "Node",
366                              JavaModifiers.PUBLIC | JavaModifiers.OMIT_INTERFACE,
367                              new JavaParameter[] {deepArg},
368                              new String JavaDoc[] {"Clone the document."});
369         fDocClass.addMethod(method);
370         method.getCode().addln(new String JavaDoc[] {
371             "cloneDeepCheck(deep);",
372             "return new " + fDocumentClass.getUnqualClassName() + "(this);"
373         });
374     }
375
376     /**
377      * Create the constructors and clone method
378      */

379     private void createConstructors() {
380         createDefaultConstructor();
381         createOptionalBuildDocConstructor();
382         createCopyConstructor();
383     if (fDocumentClass.getDeferredParsing()) {
384         createDeferredParsingConstructors();
385     }
386         createCloneMethod();
387     }
388
389     /**
390      * Create the delegate support methods and fields. Only
391      * used when delegation support is being compiled in.
392      */

393     private void createDelegateSupport() {
394         String JavaDoc unqualInterfaceName = fDocumentClass.getUnqualInterfaceName();
395
396         // NOTE: the argument to setDelegate is not the specific interface
397
// type since we want it to override the method in the base class.
398
// The generated type-cast will catch the wrong type being passed in.
399
JavaParameter param
400             = new JavaParameter("delegate", XMLObject.class.getName(),
401                                 new String JavaDoc[] {
402                                     "The delegate to set. This must be an object",
403                                     "implementing " + unqualInterfaceName + ", however the parameter",
404                                     "is untyped, since this method must override XMLOject.setDelegate()",
405                                     "New value for text child."});
406
407         JavaMethod method
408             = new JavaMethod("setDelegate",
409                              "void",
410                              JavaModifiers.PUBLIC,
411                              new JavaParameter[] {param},
412                              new String JavaDoc[] {"Set the delegate object."});
413         fDocClass.addMethod(method);
414         JavaCode body = method.getCode();
415
416         body.addln(DELEGATE_FIELD_NAME + " = (" + unqualInterfaceName + ")delegate;");
417         body.addln("super.setDelegate(" + DELEGATE_FIELD_NAME + ");");
418
419         JavaField field =
420             new JavaField(DELEGATE_FIELD_NAME,
421                           unqualInterfaceName,
422                           JavaModifiers.PRIVATE,
423                           "Pointer to delegate object", null);
424         fDocClass.addField(field);
425     }
426
427     /**
428      * Create the field containing the document loader and matching
429      * access method. Only created if deferred parsing support is enabled.
430      */

431     private void createDeferredParsingFields() {
432         String JavaDoc[] doc = {
433             "Document loader for deferred parsing.",
434         };
435         JavaField field =
436             new JavaField(DOC_LOADER_FIELD_NAME,
437                           DOC_LOADER_CLASS_NAME,
438                           JavaModifiers.PRIVATE | JavaModifiers.FINAL,
439                           doc, null);
440         fDocClass.addField(field);
441
442         JavaMethod method
443             = new JavaMethod("getDocumentLoader",
444                              DOC_LOADER_CLASS_NAME,
445                              JavaModifiers.PROTECTED | JavaModifiers.FINAL,
446                              null,
447                              new String JavaDoc[] {"Get the document loader associated with the class."});
448         fDocClass.addMethod(method);
449         JavaCode body = method.getCode();
450         body.addln("return " + DOC_LOADER_FIELD_NAME + ";");
451     }
452
453     /**
454      * Create the static field that identifies the generated class.
455      * Used by auto-recompilation to determine the XMLC generated
456      * class in an inheritance hierarchy.
457      */

458     private void createClassIdent() {
459         String JavaDoc[] doc = {
460             "Field that is used to identify this as the XMLC generated class",
461             "in an inheritance chain. Contains a reference to the class object."
462         };
463         //FIXME: Should this be in interface if both generated???
464
JavaField field =
465             new JavaField(XMLObject.XMLC_GENERATED_CLASS_FIELD_NAME,
466                           "Class",
467                           JavaModifiers.PUBLIC_CONST | JavaModifiers.OMIT_INTERFACE,
468                           doc,
469                           fDocumentClass.getUnqualClassName() + ".class");
470         fDocClass.addField(field);
471     }
472
473     /**
474      * Create the static field that contains the name of the source file. Used
475      * by auto-recompilation to find the file to recompile.
476      */

477     private void createSourceFileConst() {
478         String JavaDoc[] doc = {
479             "Field containing CLASSPATH relative name of the source file",
480             "that this class can be regenerated from."
481         };
482         JavaField field =
483             new JavaField(XMLObject.XMLC_SOURCE_FILE_FIELD_NAME,
484                           "String",
485                           JavaModifiers.PUBLIC_CONST | JavaModifiers.OMIT_INTERFACE,
486                           doc,
487                           JavaLang.createStringConst(fMetaData.getInputDocument().getRecompileSource()));
488         fDocClass.addField(field);
489     }
490
491     /**
492      * Create the static field containing the XMLCDomFactory for the
493      * class and the instance method to access it.
494      */

495     private void createDomFactoryField() {
496         String JavaDoc[] doc = {
497             "XMLC DOM factory associated with this class.",
498         };
499         String JavaDoc init
500             = XMLCDomFactoryCache.class.getName()
501             + ".getFactory(" + fXmlcDoc.getDomFactory().getClass().getName()
502             + ".class)";
503
504         JavaField field =
505             new JavaField(DOM_FACTORY_FIELD_NAME,
506                           XMLCDomFactory.class.getName(),
507                           JavaModifiers.PRIVATE | JavaModifiers.STATIC | JavaModifiers.FINAL,
508                           doc, init);
509         fDocClass.addField(field);
510
511         JavaMethod method
512             = new JavaMethod("getDomFactory",
513                              XMLCDomFactory.class.getName(),
514                              JavaModifiers.PROTECTED | JavaModifiers.FINAL,
515                              null,
516                              new String JavaDoc[] {"Get the XMLC DOM factory associated with the class."});
517         fDocClass.addMethod(method);
518         JavaCode body = method.getCode();
519         body.addln("return " + DOM_FACTORY_FIELD_NAME + ";");
520     }
521
522     /**
523      * Create the DOM building function. This creates the base
524      * method and delegate check, then class the DOM-specific
525      * builder generator.
526      */

527     private void createBuildDocument() throws XMLCException {
528         JavaMethod method
529             = new JavaMethod("buildDocument",
530                              "void",
531                              JavaModifiers.PUBLIC | JavaModifiers.OMIT_INTERFACE,
532                              null,
533                              new String JavaDoc[] {"Create document as a DOM and initialize accessor method fields."});
534         fDocClass.addMethod(method);
535         JavaCode body = method.getCode();
536
537         if (fDocumentClass.getDelegateSupport()) {
538             body.addln(new String JavaDoc[] {
539                 "if (" + DELEGATE_FIELD_NAME + " != null) {",
540                     " " + DELEGATE_FIELD_NAME + ".buildDocument();",
541                     " return;",
542                 "}"});
543         }
544         fDocBuilderGenerator.createBuildDocumentMethod(fXmlcDoc,
545                                                        fAccessorGenerator,
546                                                        fElementTable,
547                                                        fDocClass,
548                                                        method);
549     }
550
551     /**
552      * Create the class object.
553      */

554     private void createClass() throws XMLCException {
555         XMLCDomFactory domFactory = fXmlcDoc.getDomFactory();
556
557         // NB: Must replace the backslash in window file name in comment or
558
// the JBuild compiler tries to treat it as an escape character.
559
String JavaDoc[] doc = {
560             "XMLC Document class, generated from",
561             fMetaData.getInputDocument().getUrl().replace('\\','/')
562         };
563
564         fDocClass= new JavaClass(fDocumentClass.getPackageName(),
565                                  fDocumentClass.getUnqualClassName(),
566                                  JavaModifiers.PUBLIC,
567                                  doc);
568         // Interface name for generated interface.
569
if (fDocumentClass.getUnqualInterfaceName() != null) {
570             fDocClass.setInterface(fDocumentClass.getUnqualInterfaceName());
571         }
572
573         // Imports
574
fDocClass.addImports(IMPORT_LIST);
575         fDocClass.addClassImports(CLASS_IMPORT_LIST);
576     if (fDocumentClass.getDeferredParsing()) {
577         fDocClass.addClassImports(DEFERRED_PARSING_CLASS_IMPORT_LIST);
578     }
579     
580         // Determine class that will be extended
581
String JavaDoc baseClassName = fDocumentClass.getExtends();
582         if (baseClassName == null) {
583             baseClassName = domFactory.getBaseClassName();
584         }
585         fDocClass.setExtends(baseClassName);
586
587         // Determine interfaces to be implemented.
588
fDocClass.addImplements(XMLObject.class.getName());
589         String JavaDoc[] faces = domFactory.getInterfaceNames();
590         if (faces != null) {
591             fDocClass.addImplements(faces);
592         }
593         faces = fDocumentClass.getImplements();
594         if (faces != null) {
595             fDocClass.addImplements(faces);
596         }
597     }
598
599     /**
600      * Generate the class source.
601      */

602     private void generateClassSource(PrintWriter JavaDoc verboseOut)
603         throws XMLCException, IOException JavaDoc {
604
605         File JavaDoc src = fDocumentClass.getJavaClassSource();
606         if (verboseOut != null) {
607             // verboseOut.println(" creating class " + fDocumentClass.getUnqualClassName() + " at " + src.getAbsolutePath());
608
verboseOut.println(" creating class: " + src.getPath());
609         }
610         IndentWriter out = new IndentWriter(src, "ISO-8859-1");
611         boolean finishedOk = false; // determine if all is ok
612
try {
613             out.println(WARNING_HEADER);
614             if (fGenerate == GenerateType.IMPLEMENTATION) {
615                 fDocClass.printImplementation(out);
616             } else {
617                 fDocClass.printClass(out);
618             }
619             finishedOk = true; // must be last in this block
620
} finally {
621             out.close(!finishedOk);
622         }
623     }
624
625     /**
626      * Generate an interface source and write to a file.
627      */

628     private void generateInterfaceSource(PrintWriter JavaDoc verboseOut)
629         throws XMLCException, IOException JavaDoc {
630
631         File JavaDoc src = fDocumentClass.getJavaInterfaceSource();
632         if (verboseOut != null) {
633             verboseOut.println(" creating interface: " + src.getAbsolutePath());
634         }
635         IndentWriter out = new IndentWriter(src, "ISO-8859-1");
636         boolean finishedOk = false; // determine if all is ok
637
try {
638             out.println(WARNING_HEADER);
639             fDocClass.printInterface(out);
640             finishedOk = true; // must be last in this block
641
} finally {
642             out.close(!finishedOk);
643         }
644     }
645
646     /*
647      * Generate the Java source files.
648      */

649     public void generateJavaSource(PrintWriter JavaDoc verboseOut)
650         throws XMLCException, IOException JavaDoc {
651
652         if (fGenerate.generateClass()) {
653             generateClassSource(verboseOut);
654         }
655         if (fGenerate.generateInterface()) {
656             generateInterfaceSource(verboseOut);
657         }
658     }
659 }
660
Popular Tags