
org.enhydra.xml.xmlc.compiler.ClassGenerator Maven / Gradle / Ivy
The newest version!
/*
* Enhydra Java Application Server Project
*
* The contents of this file are subject to the Enhydra Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License on
* the Enhydra web site ( http://www.enhydra.org/ ).
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific terms governing rights and limitations
* under the License.
*
* The Initial Developer of the Enhydra Application Server is Lutris
* Technologies, Inc. The Enhydra Application Server and portions created
* by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
* All Rights Reserved.
*
* Contributor(s):
*
* $Id: ClassGenerator.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
*/
package org.enhydra.xml.xmlc.compiler;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import org.enhydra.xml.xmlc.XMLCException;
import org.enhydra.xml.xmlc.XMLObject;
import org.enhydra.xml.xmlc.codegen.IndentWriter;
import org.enhydra.xml.xmlc.codegen.JavaClass;
import org.enhydra.xml.xmlc.codegen.JavaCode;
import org.enhydra.xml.xmlc.codegen.JavaField;
import org.enhydra.xml.xmlc.codegen.JavaLang;
import org.enhydra.xml.xmlc.codegen.JavaMethod;
import org.enhydra.xml.xmlc.codegen.JavaModifiers;
import org.enhydra.xml.xmlc.codegen.JavaParameter;
import org.enhydra.xml.xmlc.deferredparsing.DeferredParsingAccessorGenerator;
import org.enhydra.xml.xmlc.deferredparsing.DeferredParsingDocBuilderGenerator;
import org.enhydra.xml.xmlc.dom.AccessorGenerator;
import org.enhydra.xml.xmlc.dom.DocBuilderGenerator;
import org.enhydra.xml.xmlc.dom.XMLCDocument;
import org.enhydra.xml.xmlc.dom.XMLCDomFactory;
import org.enhydra.xml.xmlc.dom.XMLCDomFactoryCache;
import org.enhydra.xml.xmlc.metadata.DocumentClass;
import org.enhydra.xml.xmlc.metadata.GenerateType;
import org.enhydra.xml.xmlc.metadata.MetaData;
import org.w3c.dom.Document;
/**
* Generate XML classes and interfaces.
*/
public class ClassGenerator {
/*
* List of standard imports for generated classes and interfaces.
*/
private static final String[] IMPORT_LIST = {
"org.w3c.dom.*",
};
/*
* List of standard imports for generated classes.
*/
private static final String[] CLASS_IMPORT_LIST = {
// "org.enhydra.xml.xmlc.XMLCUtil",
// "org.enhydra.xml.xmlc.XMLCError",
"org.enhydra.xml.xmlc.dom.XMLCDomFactory",
// "org.enhydra.xml.dom.DOMOps"
};
/*
* List of additional imports for deferred parsing support.
*/
private static final String[] DEFERRED_PARSING_CLASS_IMPORT_LIST = {
"org.enhydra.xml.xmlc.deferredparsing.DocumentLoader",
"org.enhydra.xml.xmlc.deferredparsing.StandardDocumentLoader",
};
/**
* Name of field containing document loader reference for deferred parsing.
*/
public static final String DOC_LOADER_FIELD_NAME = "fDocumentLoader";
/**
* Class name of the document loader for deferred parsing.
*/
public static final String DOC_LOADER_CLASS_NAME = "DocumentLoader";
/**
* Name of field containing delegate reference.
*/
public static final String DELEGATE_FIELD_NAME = "fDelegate";
/**
* Name for the static field holding the XMLCDomFactory.
*/
public static final String DOM_FACTORY_FIELD_NAME = "fDOMFactory";
/*
* Header to place in each generated file.
*/
private static final String[] WARNING_HEADER = {
"/*",
" ************************************",
" * XMLC GENERATED CODE, DO NOT EDIT *",
" ************************************",
" */"
};
/**
* Document metadata.
*/
private MetaData fMetaData;
private DocumentClass fDocumentClass;
/*
* What to generate.
*/
private GenerateType fGenerate;
/*
* XMLC DOM management object.
*/
private XMLCDocument fXmlcDoc;
/*
* Source document.
*/
private Document fDocument;
/**
* Table of elements used by code generators.
*/
private ElementTable fElementTable;
/*
* Access method creator.
*/
private AccessMethods fAccessMethods;
/*
* Access constants creator.
*/
private AccessConsts fAccessConsts;
/**
* DOM Accessor generator.
*/
private AccessorGenerator fAccessorGenerator;
/*
* Document builder generator.
*/
private DocBuilderGenerator fDocBuilderGenerator;
/**
* Class being constructed.
*/
JavaClass fDocClass;
/**
* Construct an object.
*
* @param metaData Document metadata.
* @param xmlcDoc XMLC DOM object containing the document.
* @param methodOutput Write information about the generated
* methods to this file if not NULL.
* @exception XMLCException If an error is detected.
*/
public ClassGenerator(MetaData metaData,
XMLCDocument xmlcDoc,
PrintWriter methodOutput)
throws XMLCException {
// Setup fields
fMetaData = metaData;
fXmlcDoc = xmlcDoc;
fDocumentClass = fMetaData.getDocumentClass();
fGenerate = fDocumentClass.getGenerate();
fDocument = xmlcDoc.getDocument();
// Get the deferred parsing specific generators if deferred
// parsing support is desired. Otherwise, get the DOM specific
// generators
if (fDocumentClass.getDeferredParsing()) {
fAccessorGenerator =
new DeferredParsingAccessorGenerator();
fDocBuilderGenerator =
new DeferredParsingDocBuilderGenerator();
} else {
XMLCDomFactory domFactory = fXmlcDoc.getDomFactory();
fAccessorGenerator = domFactory.createAccessorGenerator(fDocument);
fDocBuilderGenerator = domFactory.createDocBuilderGenerator(fDocument);
}
fElementTable = new ElementTable(metaData, fXmlcDoc);
fAccessMethods = new AccessMethods(fMetaData, fElementTable,
fAccessorGenerator);
fAccessConsts = new AccessConsts(fMetaData, fElementTable);
// Build class and imports
createClass();
fAccessMethods.generateCode(fDocClass);
fAccessConsts.generateCode(fDocClass);
// Construct the rest of the class.
createConstructors();
createDomFactoryField();
if (fDocumentClass.getDeferredParsing()) {
createDeferredParsingFields();
}
createBuildDocument();
fAccessMethods.generateCode(fDocClass);
if (fDocumentClass.getDelegateSupport()) {
createDelegateSupport();
}
createClassIdent();
createSourceFileConst();
// Output information about created and omitted accessors.
if (methodOutput != null) {
fAccessMethods.printAccessMethods(methodOutput);
fAccessConsts.printAccessConstants(methodOutput);
fAccessMethods.printOmittedIds(methodOutput);
fAccessConsts.printOmittedConstants(methodOutput);
}
}
/**
* Create the default constructor (no arguments).
*/
private void createDefaultConstructor() {
JavaMethod constr
= new JavaMethod(fDocumentClass.getUnqualClassName(),
null,
JavaModifiers.PUBLIC,
null,
new String[] {"Default constructor."});
if (fDocumentClass.getDeferredParsing()) {
constr.getCode().addln("this(StandardDocumentLoader.getInstance());");
}
constr.getCode().addln("buildDocument();");
fDocClass.addConstructor(constr);
}
/**
* Create the buildDocument optional constructor.
*/
private void createOptionalBuildDocConstructor() {
String[] buildArgDoc = {
"buildDOM If false, the DOM will not be built until",
"buildDocument() is called by the derived class. If true, ",
"the DOM is built immediatly."
};
JavaParameter buildArg
= new JavaParameter("buildDOM", "boolean", buildArgDoc);
JavaMethod constr
= new JavaMethod(fDocumentClass.getUnqualClassName(),
null,
JavaModifiers.PUBLIC,
new JavaParameter[] {buildArg},
new String[] {"Constructor with optional building of the DOM."});
if (fDocumentClass.getDeferredParsing()) {
constr.getCode().addln("this(StandardDocumentLoader.getInstance(), buildDOM);");
} else constr.getCode().addln(new String[] {
"if (buildDOM) {",
" buildDocument();",
"}"
});
fDocClass.addConstructor(constr);
}
/**
* Create the deferred parsing constructor
*/
private void createDeferredParsingConstructors() {
String[] buildArgDoc = {
"buildDOM If false, the DOM will not be built until",
"buildDocument() is called by the derived class. If true, ",
"the DOM is built immediatly."
};
JavaParameter buildArg
= new JavaParameter("buildDOM", "boolean", buildArgDoc);
String[] loaderArgDoc = {
"loader the document loader to delegate document",
"creation to."
};
JavaParameter loaderArg
= new JavaParameter("loader", "DocumentLoader", buildArgDoc);
JavaMethod constr
= new JavaMethod(fDocumentClass.getUnqualClassName(),
null,
JavaModifiers.PUBLIC,
new JavaParameter[] {loaderArg, buildArg},
new String[] {
"Constructor for deferred parsing support.",
"The supplied document loader is used to",
"create the DOM."
});
constr.getCode().addln(new String[] {
DOC_LOADER_FIELD_NAME + " = loader;",
"if (buildDOM) {",
" buildDocument();",
"}"
});
fDocClass.addConstructor(constr);
constr
= new JavaMethod(fDocumentClass.getUnqualClassName(),
null,
JavaModifiers.PUBLIC,
new JavaParameter[] {loaderArg},
new String[] {
"Constructor for deferred parsing support.",
"The supplied document loader is used to",
"create the DOM."
});
constr.getCode().addln("this(loader, true);");
fDocClass.addConstructor(constr);
}
/**
* Create the copy constructor.
*/
private void createCopyConstructor() {
//FIXME: Should really use interface name if one is generated.
JavaParameter srcArg
= new JavaParameter("src",
fDocumentClass.getUnqualClassName(),
"The document to clone.");
JavaMethod constr
= new JavaMethod(fDocumentClass.getUnqualClassName(),
null,
JavaModifiers.PUBLIC,
new JavaParameter[] {srcArg},
new String[] {"Copy constructor."});
if (fDocumentClass.getDeferredParsing()) {
constr.getCode().addln(DOC_LOADER_FIELD_NAME +
" = src.getDocumentLoader();");
}
constr.getCode().addln(new String[] {
"setDocument((Document)src.getDocument().cloneNode(true), src.getMIMEType(), src.getEncoding());",
"syncAccessMethods();"
});
fDocClass.addConstructor(constr);
}
/**
* Create the clone method.
*/
private void createCloneMethod() {
JavaParameter deepArg
= new JavaParameter("deep", "boolean",
"Must be true, only deep clone is supported.");
JavaMethod method
= new JavaMethod("cloneNode",
"Node",
JavaModifiers.PUBLIC | JavaModifiers.OMIT_INTERFACE,
new JavaParameter[] {deepArg},
new String[] {"Clone the document."});
fDocClass.addMethod(method);
method.getCode().addln(new String[] {
"cloneDeepCheck(deep);",
"return new " + fDocumentClass.getUnqualClassName() + "(this);"
});
}
/**
* Create the constructors and clone method
*/
private void createConstructors() {
createDefaultConstructor();
createOptionalBuildDocConstructor();
createCopyConstructor();
if (fDocumentClass.getDeferredParsing()) {
createDeferredParsingConstructors();
}
createCloneMethod();
}
/**
* Create the delegate support methods and fields. Only
* used when delegation support is being compiled in.
*/
private void createDelegateSupport() {
String unqualInterfaceName = fDocumentClass.getUnqualInterfaceName();
// NOTE: the argument to setDelegate is not the specific interface
// type since we want it to override the method in the base class.
// The generated type-cast will catch the wrong type being passed in.
JavaParameter param
= new JavaParameter("delegate", XMLObject.class.getName(),
new String[] {
"The delegate to set. This must be an object",
"implementing " + unqualInterfaceName + ", however the parameter",
"is untyped, since this method must override XMLOject.setDelegate()",
"New value for text child."});
JavaMethod method
= new JavaMethod("setDelegate",
"void",
JavaModifiers.PUBLIC,
new JavaParameter[] {param},
new String[] {"Set the delegate object."});
fDocClass.addMethod(method);
JavaCode body = method.getCode();
body.addln(DELEGATE_FIELD_NAME + " = (" + unqualInterfaceName + ")delegate;");
body.addln("super.setDelegate(" + DELEGATE_FIELD_NAME + ");");
JavaField field =
new JavaField(DELEGATE_FIELD_NAME,
unqualInterfaceName,
JavaModifiers.PRIVATE,
"Pointer to delegate object", null);
fDocClass.addField(field);
}
/**
* Create the field containing the document loader and matching
* access method. Only created if deferred parsing support is enabled.
*/
private void createDeferredParsingFields() {
String[] doc = {
"Document loader for deferred parsing.",
};
JavaField field =
new JavaField(DOC_LOADER_FIELD_NAME,
DOC_LOADER_CLASS_NAME,
JavaModifiers.PRIVATE | JavaModifiers.FINAL,
doc, null);
fDocClass.addField(field);
JavaMethod method
= new JavaMethod("getDocumentLoader",
DOC_LOADER_CLASS_NAME,
JavaModifiers.PROTECTED | JavaModifiers.FINAL,
null,
new String[] {"Get the document loader associated with the class."});
fDocClass.addMethod(method);
JavaCode body = method.getCode();
body.addln("return " + DOC_LOADER_FIELD_NAME + ";");
}
/**
* Create the static field that identifies the generated class.
* Used by auto-recompilation to determine the XMLC generated
* class in an inheritance hierarchy.
*/
private void createClassIdent() {
String[] doc = {
"Field that is used to identify this as the XMLC generated class",
"in an inheritance chain. Contains a reference to the class object."
};
//FIXME: Should this be in interface if both generated???
JavaField field =
new JavaField(XMLObject.XMLC_GENERATED_CLASS_FIELD_NAME,
"Class",
JavaModifiers.PUBLIC_CONST | JavaModifiers.OMIT_INTERFACE,
doc,
fDocumentClass.getUnqualClassName() + ".class");
fDocClass.addField(field);
}
/**
* Create the static field that contains the name of the source file. Used
* by auto-recompilation to find the file to recompile.
*/
private void createSourceFileConst() {
String[] doc = {
"Field containing CLASSPATH relative name of the source file",
"that this class can be regenerated from."
};
JavaField field =
new JavaField(XMLObject.XMLC_SOURCE_FILE_FIELD_NAME,
"String",
JavaModifiers.PUBLIC_CONST | JavaModifiers.OMIT_INTERFACE,
doc,
JavaLang.createStringConst(fMetaData.getInputDocument().getRecompileSource()));
fDocClass.addField(field);
}
/**
* Create the static field containing the XMLCDomFactory for the
* class and the instance method to access it.
*/
private void createDomFactoryField() {
String[] doc = {
"XMLC DOM factory associated with this class.",
};
String init
= XMLCDomFactoryCache.class.getName()
+ ".getFactory(" + fXmlcDoc.getDomFactory().getClass().getName()
+ ".class)";
JavaField field =
new JavaField(DOM_FACTORY_FIELD_NAME,
XMLCDomFactory.class.getName(),
JavaModifiers.PRIVATE | JavaModifiers.STATIC | JavaModifiers.FINAL,
doc, init);
fDocClass.addField(field);
JavaMethod method
= new JavaMethod("getDomFactory",
XMLCDomFactory.class.getName(),
JavaModifiers.PROTECTED | JavaModifiers.FINAL,
null,
new String[] {"Get the XMLC DOM factory associated with the class."});
fDocClass.addMethod(method);
JavaCode body = method.getCode();
body.addln("return " + DOM_FACTORY_FIELD_NAME + ";");
}
/**
* Create the DOM building function. This creates the base
* method and delegate check, then class the DOM-specific
* builder generator.
*/
private void createBuildDocument() throws XMLCException {
JavaMethod method
= new JavaMethod("buildDocument",
"void",
JavaModifiers.PUBLIC | JavaModifiers.OMIT_INTERFACE,
null,
new String[] {"Create document as a DOM and initialize accessor method fields."});
fDocClass.addMethod(method);
JavaCode body = method.getCode();
if (fDocumentClass.getDelegateSupport()) {
body.addln(new String[] {
"if (" + DELEGATE_FIELD_NAME + " != null) {",
" " + DELEGATE_FIELD_NAME + ".buildDocument();",
" return;",
"}"});
}
fDocBuilderGenerator.createBuildDocumentMethod(fXmlcDoc,
fAccessorGenerator,
fElementTable,
fDocClass,
method);
}
/**
* Create the class object.
*/
private void createClass() throws XMLCException {
XMLCDomFactory domFactory = fXmlcDoc.getDomFactory();
// NB: Must replace the backslash in window file name in comment or
// the JBuild compiler tries to treat it as an escape character.
String[] doc = {
"XMLC Document class, generated from",
fMetaData.getInputDocument().getUrl().replace('\\','/')
};
fDocClass= new JavaClass(fDocumentClass.getPackageName(),
fDocumentClass.getUnqualClassName(),
JavaModifiers.PUBLIC,
doc);
// Interface name for generated interface.
if (fDocumentClass.getUnqualInterfaceName() != null) {
fDocClass.setInterface(fDocumentClass.getUnqualInterfaceName());
}
// Imports
fDocClass.addImports(IMPORT_LIST);
fDocClass.addClassImports(CLASS_IMPORT_LIST);
if (fDocumentClass.getDeferredParsing()) {
fDocClass.addClassImports(DEFERRED_PARSING_CLASS_IMPORT_LIST);
}
// Determine class that will be extended
String baseClassName = fDocumentClass.getExtends();
if (baseClassName == null) {
baseClassName = domFactory.getBaseClassName();
}
fDocClass.setExtends(baseClassName);
// Determine interfaces to be implemented.
fDocClass.addImplements(XMLObject.class.getName());
String[] faces = domFactory.getInterfaceNames();
if (faces != null) {
fDocClass.addImplements(faces);
}
faces = fDocumentClass.getImplements();
if (faces != null) {
fDocClass.addImplements(faces);
}
}
/**
* Generate the class source.
*/
private void generateClassSource(PrintWriter verboseOut)
throws XMLCException, IOException {
File src = fDocumentClass.getJavaClassSource();
if (verboseOut != null) {
// verboseOut.println(" creating class " + fDocumentClass.getUnqualClassName() + " at " + src.getAbsolutePath());
verboseOut.println(" creating class: " + src.getPath());
}
IndentWriter out = new IndentWriter(src, "ISO-8859-1");
boolean finishedOk = false; // determine if all is ok
try {
out.println(WARNING_HEADER);
if (fGenerate == GenerateType.IMPLEMENTATION) {
fDocClass.printImplementation(out);
} else {
fDocClass.printClass(out);
}
finishedOk = true; // must be last in this block
} finally {
out.close(!finishedOk);
}
}
/**
* Generate an interface source and write to a file.
*/
private void generateInterfaceSource(PrintWriter verboseOut)
throws XMLCException, IOException {
File src = fDocumentClass.getJavaInterfaceSource();
if (verboseOut != null) {
verboseOut.println(" creating interface: " + src.getAbsolutePath());
}
IndentWriter out = new IndentWriter(src, "ISO-8859-1");
boolean finishedOk = false; // determine if all is ok
try {
out.println(WARNING_HEADER);
fDocClass.printInterface(out);
finishedOk = true; // must be last in this block
} finally {
out.close(!finishedOk);
}
}
/*
* Generate the Java source files.
*/
public void generateJavaSource(PrintWriter verboseOut)
throws XMLCException, IOException {
if (fGenerate.generateClass()) {
generateClassSource(verboseOut);
}
if (fGenerate.generateInterface()) {
generateInterfaceSource(verboseOut);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy