blob: 466311d9fb6e260815e33fde9fde39c6d47afb48 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.sdo.helper;
import commonj.sdo.helper.HelperContext;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.sdo.SDOConstants;
import org.eclipse.persistence.sdo.SDOProperty;
import org.eclipse.persistence.sdo.SDOType;
import org.eclipse.persistence.sdo.helper.extension.SDOUtil;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.localization.ToStringLocalization;
import org.eclipse.persistence.logging.AbstractSessionLog;
/**
* <p><b>Purpose</b>: Generate Java interfaces and implementation classes from a list of SDO Type objects.
* <ul><li>This class can be run standalone - logging will default to level FINER when run from the command line.</li>
* </ul>
*/
public class SDOClassGenerator {
// Source Gen Stuff
private String indent = SDOConstants.EMPTY_STRING;
private static int INDENT_TAB = 3;
private static final String lsep = System.getProperty("line.separator");
private static final String lsep2 = lsep + lsep;
private static final String START_PROPERTY_INDEX = "START_PROPERTY_INDEX";
private Map generatedBuffers;
private boolean interfaceGenerator = true;
private boolean implGenerator = true;
private CodeWriter codeWriter;
private SDOClassGeneratorListener sdoClassGeneratorListener;
// hold the context containing all helpers so that we can preserve inter-helper relationships
private HelperContext aHelperContext;
public SDOClassGenerator() {
this(new SDOHelperContext());
}
public SDOClassGenerator(HelperContext aContext) {
aHelperContext = aContext;
generatedBuffers = new HashMap();
}
public void setInterfaceGenerator(boolean genIterfaces) {
interfaceGenerator = genIterfaces;
}
public void setImplGenerator(boolean genImpls) {
implGenerator = genImpls;
}
public static void main(String[] args) {
// default to dynamic context
SDOClassGenerator generator = new SDOClassGenerator(new SDOHelperContext());
String sourceDir = null;
String sourceFile = null;
int argsLength = args.length;
// default to FINEST subject to parameter override
AbstractSessionLog.getLog().setLevel(AbstractSessionLog.FINER);
for (int i = 0; i < argsLength; i++) {
if (args[i].equals("-help")) {
generator.printUsage(null);
System.exit(0);
} else if (args[i].equals("-sourceFile")) {
if (i == (argsLength - 1)) {
generator.printUsage("sdo_classgenerator_usage_missing_sourcefile_value");
System.exit(0);
}
sourceFile = args[++i];
} else if (args[i].equals("-targetDirectory")) {
if (i == (argsLength - 1)) {
generator.printUsage("sdo_classgenerator_usage_missing_targetdir");
System.exit(0);
}
sourceDir = args[++i];
} else if (args[i].equals("-logLevel")) {
// log level is optional and will default to INFO
if (i != (argsLength - 1)) {
AbstractSessionLog.getLog().setLevel(Integer.parseInt(args[++i]));
}
} else if (args[i].equals("-noInterfaces")) {
// This option introduced in EclipseLink 2.0
generator.setInterfaceGenerator(false);
} else if (args[i].equals("-noImpls")) {
// This option introduced in EclipseLink 2.0
generator.setImplGenerator(false);
}
}
if (null == sourceFile) {
generator.printUsage("sdo_classgenerator_usage_missing_sourcefile");
System.exit(0);
}
try {
FileReader reader = new FileReader(sourceFile);
FileCodeWriter fileCodeWriter = new FileCodeWriter();
fileCodeWriter.setSourceDir(sourceDir);
generator.generate(reader, fileCodeWriter, new DefaultSchemaResolver());
} catch (IOException e) {
AbstractSessionLog.getLog().log(AbstractSessionLog.SEVERE, "sdo_classgenerator_exception",//
e.getClass().getName(), e.getLocalizedMessage(), generator.getClass());
AbstractSessionLog.getLog().logThrowable(AbstractSessionLog.SEVERE, e);
}
}
/**
* INTERNAL:
* Print out what usage is missing as well as an example.
* The messageID parameter must have a corresponding entry in the LoggingLocalizationResource Map
* @param messageID
*/
private void printUsage(String messageID) {
if (null != messageID) {
System.out.println(ToStringLocalization.buildMessage(messageID, new Object[] { Helper.getShortClassName(getClass()) }));
}
// Because we can no longer use Helper.cr() inside of message bundles, we must break
// up the message into separate lines and use Helper.cr() here instead. (bug6470503)
String messageString = ToStringLocalization.buildMessage("sdo_classgenerator_usage_help_1of8", new Object[] { Helper.getShortClassName(getClass()) });
messageString += Helper.cr() + Helper.cr();
messageString += ToStringLocalization.buildMessage("sdo_classgenerator_usage_help_2of8");
messageString += Helper.cr();
messageString += ToStringLocalization.buildMessage("sdo_classgenerator_usage_help_3of8");
messageString += Helper.cr();
messageString += ToStringLocalization.buildMessage("sdo_classgenerator_usage_help_4of8");
messageString += Helper.cr();
messageString += ToStringLocalization.buildMessage("sdo_classgenerator_usage_help_5of8");
messageString += Helper.cr();
messageString += ToStringLocalization.buildMessage("sdo_classgenerator_usage_help_6of8");
messageString += Helper.cr();
messageString += ToStringLocalization.buildMessage("sdo_classgenerator_usage_help_7of8");
messageString += Helper.cr();
messageString += ToStringLocalization.buildMessage("sdo_classgenerator_usage_help_8of8");
messageString += Helper.cr();
System.out.println(messageString);
}
public Map generate(Reader xsdReader) {
FileCodeWriter fileCodeWriter = new FileCodeWriter();
return generate(new StreamSource(xsdReader), fileCodeWriter, new DefaultSchemaResolver());
}
public Map generate(Reader xsdReader, String sourceDir) {
FileCodeWriter fileCodeWriter = new FileCodeWriter();
fileCodeWriter.setSourceDir(sourceDir);
return generate(new StreamSource(xsdReader), fileCodeWriter, new DefaultSchemaResolver());
}
public Map generate(Reader xsdReader, String sourceDir, SchemaResolver schemaResolver) {
FileCodeWriter fileCodeWriter = new FileCodeWriter();
fileCodeWriter.setSourceDir(sourceDir);
return generate(new StreamSource(xsdReader), fileCodeWriter, schemaResolver);
}
public Map generate(Reader xsdReader, SchemaResolver schemaResolver) {
return generate(new StreamSource(xsdReader), new FileCodeWriter(), schemaResolver);
}
public Map generate(Reader xsdReader, CodeWriter aCodeWriter) {
return generate(new StreamSource(xsdReader), aCodeWriter, new DefaultSchemaResolver());
}
public Map generate(Reader xsdReader, CodeWriter aCodeWriter, SchemaResolver schemaResolver) {
return generate(new StreamSource(xsdReader), aCodeWriter, schemaResolver, true);
}
public Map generate(Reader xsdReader, CodeWriter aCodeWriter, SchemaResolver schemaResolver, boolean bProcessImports) {
return generate(new StreamSource(xsdReader), aCodeWriter, schemaResolver, bProcessImports);
}
public Map generate(Source xsdSource, String sourceDir) {
FileCodeWriter fileCodeWriter = new FileCodeWriter();
fileCodeWriter.setSourceDir(sourceDir);
return generate(xsdSource, fileCodeWriter, new DefaultSchemaResolver());
}
public Map generate(Source xsdSource, String sourceDir, SchemaResolver schemaResolver) {
FileCodeWriter fileCodeWriter = new FileCodeWriter();
fileCodeWriter.setSourceDir(sourceDir);
return generate(xsdSource, fileCodeWriter, schemaResolver);
}
public Map generate(Source xsdSource, SchemaResolver schemaResolver) {
return generate(xsdSource, new FileCodeWriter(), schemaResolver, true);
}
public Map generate(Source xsdSource, CodeWriter aCodeWriter) {
return generate(xsdSource, aCodeWriter, new DefaultSchemaResolver(), true);
}
public Map generate(Source xsdSource, CodeWriter aCodeWriter, SchemaResolver schemaResolver) {
return generate(xsdSource, aCodeWriter, schemaResolver, true);
}
public Map generate(Source xsdSource, CodeWriter aCodeWriter, SchemaResolver schemaResolver, boolean bProcessImports) {
SDOTypesGenerator gen = new SDOTypesGenerator(aHelperContext);
java.util.List types = gen.define(xsdSource, schemaResolver, true, bProcessImports);
return generate(aCodeWriter, types);
}
public Map generate(CodeWriter aCodeWriter, java.util.List types) {
generatedBuffers = new HashMap();
codeWriter = aCodeWriter;
for (int i = 0; i < types.size(); i++) {
SDOType theType = (SDOType)types.get(i);
if (!theType.isDataType()) {
ClassBuffer nextBuffer = buildClassForType(theType);
//write interface to file
String packageDir = nextBuffer.getPackageName();
packageDir = packageDir.replace('.', '/');
if(interfaceGenerator) {
String instanceClassName = Helper.getShortClassName(theType.getInstanceClassName());
getCodeWriter().writeInterface(packageDir, instanceClassName + ".java", nextBuffer.getInterfaceBuffer());
}
if(implGenerator) {
String implClassName = Helper.getShortClassName(theType.getImplClassName());
getCodeWriter().writeImpl(packageDir, implClassName + ".java", nextBuffer.getClassBuffer());
}
}
}
return generatedBuffers;
}
private ClassBuffer buildClassForType(SDOType sdoType) {
ClassBuffer classBuffer = new ClassBuffer(sdoClassGeneratorListener);
classBuffer.setSdoType(sdoType);
classBuffer.setGenerateInterface(interfaceGenerator);
classBuffer.setSdoTypeName(sdoType.getName());
StringBuffer currentClassBuffer = new StringBuffer();
if (sdoClassGeneratorListener != null) {
sdoClassGeneratorListener.preImplPackage(currentClassBuffer);
}
String packageName = null;
int lastDotIndex = sdoType.getInstanceClassName().lastIndexOf('.');
if (lastDotIndex > -1) {
packageName = sdoType.getInstanceClassName().substring(0, lastDotIndex);
}
currentClassBuffer.append(indent);
currentClassBuffer.append("package ");
if ((sdoType.getURI() != null) && (!sdoType.getURI().equals(SDOConstants.EMPTY_STRING))) {
classBuffer.setUri(sdoType.getURI());
}
currentClassBuffer.append(packageName);
classBuffer.setPackageName(packageName);
currentClassBuffer.append(";").append(lsep2);
if (sdoClassGeneratorListener != null) {
sdoClassGeneratorListener.preImplImports(currentClassBuffer);
}
currentClassBuffer.append("import ").append(//
SDOConstants.SDO_DATA_OBJECT_IMPL_CLASS_NAME).append(";").append(lsep2);
java.util.List documentation = (java.util.List)sdoType.get(SDOConstants.DOCUMENTATION_PROPERTY);
if ((documentation != null) && (documentation.size() > 0)) {
currentClassBuffer.append(indent);
currentClassBuffer.append(buildJavaDoc(documentation));
}
if (sdoClassGeneratorListener != null) {
sdoClassGeneratorListener.preImplClass(currentClassBuffer);
}
currentClassBuffer.append(indent);
currentClassBuffer.append("public class ");
// get the normalized name of the class without the package prefix
String upperClassName = SDOUtil.className(sdoType.getName(), true, true, true);
String interfaceName = upperClassName;
classBuffer.setInterfaceName(interfaceName);
String fullClassName = upperClassName + SDOConstants.SDO_IMPL_NAME;
currentClassBuffer.append(fullClassName + " ");
classBuffer.setClassName(fullClassName);
String implExtends = null;
String interfaceExtends = null;
if (sdoType.isSubType()) {
SDOType baseType = ((SDOType)sdoType.getBaseTypes().get(0));
if (!baseType.isDataType()) {
interfaceExtends = baseType.getInstanceClassName();
implExtends = baseType.getImplClassName();
}
} else {
implExtends = "SDODataObject";
}
currentClassBuffer.append("extends ").append(implExtends);
if (interfaceGenerator) {
currentClassBuffer.append(" implements ")//
.append(interfaceName);
}
classBuffer.getAttributeBuffer().append(buildStartAndEndPropAttribute(sdoType));
classBuffer.getMethodBuffer().append(buildNoArgCtor(fullClassName));
currentClassBuffer.append(indent).append(" {").append(lsep2);
if (interfaceGenerator) {
StringBuffer currentInterfaceBuffer = new StringBuffer();
if (sdoClassGeneratorListener != null) {
sdoClassGeneratorListener.preInterfacePackage(currentInterfaceBuffer);
}
currentInterfaceBuffer.append(indent);
currentInterfaceBuffer.append("package ");
currentInterfaceBuffer.append(packageName);
currentInterfaceBuffer.append(";").append(lsep2);
if (sdoClassGeneratorListener != null) {
sdoClassGeneratorListener.preInterfaceImports(currentInterfaceBuffer);
}
if (sdoClassGeneratorListener != null) {
sdoClassGeneratorListener.preInterfaceClass(currentInterfaceBuffer);
}
currentInterfaceBuffer.append(indent);
currentInterfaceBuffer.append("public interface ");
currentInterfaceBuffer.append(interfaceName);
if (interfaceExtends != null) {
currentInterfaceBuffer.append(" extends " + interfaceExtends );
} else{
currentInterfaceBuffer.append(" extends java.io.Serializable");
}
currentInterfaceBuffer.append(indent).append(" {").append(lsep2);
classBuffer.setInterfaceBuffer(currentInterfaceBuffer);
}
classBuffer.setClassBuffer(currentClassBuffer);
getGeneratedBuffers().put(new QName(sdoType.getURI(), sdoType.getName()), classBuffer);
java.util.List props = sdoType.getDeclaredProperties();
int propsSize = props.size();
for (int i = 0; i < propsSize; i++) {
SDOProperty nextProp = (SDOProperty)props.get(i);
buildGetterAndSetter(classBuffer, nextProp);
}
classBuffer.close();
return classBuffer;
}
private void addJavaDocLinesToBuffer(StringBuffer javaDocBuffer, java.util.List documentationList, boolean getterSetter) {
for (int i = 0; i < documentationList.size(); i++) {
String documentation = (String)documentationList.get(i);
StringTokenizer stok = new StringTokenizer(documentation, lsep);
int lineCount = 0;
while (stok.hasMoreTokens()) {
String nextLine = stok.nextToken().trim();
if (nextLine.length() > 0) {
if (lineCount > 0 || (lineCount == 0 && !getterSetter)) {
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_LINE);
}
javaDocBuffer.append(nextLine).append(lsep);
}
lineCount++;
}
if (i < (documentationList.size() - 1)) {
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_LINE);
}
}
}
private StringBuffer buildJavaDoc(java.util.List documentation) {
StringBuffer javaDocBuffer = new StringBuffer();
javaDocBuffer.append(SDOConstants.JAVADOC_START).append(lsep);
addJavaDocLinesToBuffer(javaDocBuffer, documentation, false);
javaDocBuffer.append(SDOConstants.JAVADOC_END).append(lsep);
return javaDocBuffer;
}
private StringBuffer buildGetterJavaDoc(java.util.List documentation, String name) {
StringBuffer javaDocBuffer = new StringBuffer();
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_START).append(lsep);
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_LINE).append("Gets ").append(name).append(".").append(lsep);
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_LINE).append("return ");
addJavaDocLinesToBuffer(javaDocBuffer, documentation, true);
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_END).append(lsep);
return javaDocBuffer;
}
private StringBuffer buildSetterJavaDoc(java.util.List documentation, String name) {
StringBuffer javaDocBuffer = new StringBuffer();
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_START).append(lsep);
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_LINE).append("Sets ").append(name).append(".").append(lsep);
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_LINE).append("param value ");
addJavaDocLinesToBuffer(javaDocBuffer, documentation, true);
javaDocBuffer.append(indent).append(SDOConstants.JAVADOC_END).append(lsep);
return javaDocBuffer;
}
private StringBuffer buildStartAndEndPropAttribute(SDOType sdoType) {
StringBuffer attrBuffer = new StringBuffer();
pushIndent();
int declPropsSize = sdoType.getDeclaredProperties().size();
attrBuffer.append(indent).append("public static final int START_PROPERTY_INDEX = ");
if (sdoType.isSubType()) {
String baseClassName = ((SDOType)sdoType.getBaseTypes().get(0)).getImplClassName();
attrBuffer.append(baseClassName).append(".END_PROPERTY_INDEX");
if (declPropsSize > 0) {
attrBuffer.append(" + 1");
}
attrBuffer.append(";");
} else {
if (declPropsSize > 0) {
attrBuffer.append("0;");
} else {
attrBuffer.append("-1;");
}
}
attrBuffer.append(lsep2);
int end = 0;
if (declPropsSize > 0) {
end = declPropsSize - 1;
} else {
end = 0;
}
attrBuffer.append(indent).append("public static final int END_PROPERTY_INDEX = START_PROPERTY_INDEX + ").append(end).append(";").append(lsep2);
popIndent();
return attrBuffer;
}
private StringBuffer buildNoArgCtor(String className) {
StringBuffer ctorBuffer = new StringBuffer();
pushIndent();
ctorBuffer.append(indent).append("public ").append(className).append("() {}").append(lsep2);
popIndent();
return ctorBuffer;
}
/**
* INTERNAL:
*/
private void buildGetterAndSetter(ClassBuffer classBuffer, SDOProperty property) {
pushIndent();
java.util.List documentation = (java.util.List)property.get(SDOConstants.DOCUMENTATION_PROPERTY);
buildGetMethodBuffer(classBuffer, property, documentation);
buildSetMethodBuffer(classBuffer, property, documentation);
popIndent();
}
/**
* INTERNAL:
* @param classBuffer
*/
private void buildGetMethodBuffer(ClassBuffer classBuffer, SDOProperty property, java.util.List documentation) {
String returnType = SDOUtil.getJavaTypeForProperty(property);
String methodName = SDOUtil.getMethodName(property.getName(), returnType);
if (!(property.getType().isChangeSummaryType() && methodName.equals("getChangeSummary"))) {
if ((documentation != null) && (documentation.size() > 0)) {
classBuffer.getMethodBuffer().append(buildGetterJavaDoc(documentation, property.getName()));
}
classBuffer.getMethodBuffer().append(indent);
classBuffer.getMethodBuffer().append("public ");
classBuffer.getMethodBuffer().append(returnType).append(" ");
classBuffer.getMethodBuffer().append(methodName);
classBuffer.getMethodBuffer().append("() {").append(lsep);
pushIndent();
classBuffer.getMethodBuffer().append(indent).append("return ");
//cast return value
String builtIn = SDOUtil.getBuiltInType(returnType);
if (builtIn != null) {
classBuffer.getMethodBuffer().append("get").append(builtIn).append("(");
classBuffer.getMethodBuffer().append(START_PROPERTY_INDEX).append(" + ").append(property.getIndexInDeclaredProperties());
classBuffer.getMethodBuffer().append(")");
} else {
if (!returnType.equals(ClassConstants.OBJECT.getName())) {
classBuffer.getMethodBuffer().append("(");
classBuffer.getMethodBuffer().append(returnType).append(")");
}
classBuffer.getMethodBuffer().append("get(");
classBuffer.getMethodBuffer().append(START_PROPERTY_INDEX).append(" + ").append(property.getIndexInDeclaredProperties());
classBuffer.getMethodBuffer().append(")");
}
classBuffer.getMethodBuffer().append(";").append(lsep);
popIndent();
classBuffer.getMethodBuffer().append(indent).append("}").append(lsep2);
}
if (interfaceGenerator) {
classBuffer.getInterfaceBuffer().append(indent);
classBuffer.getInterfaceBuffer().append("public ");
classBuffer.getInterfaceBuffer().append(returnType).append(" ");
classBuffer.getInterfaceBuffer().append(methodName);
classBuffer.getInterfaceBuffer().append("();").append(lsep2);
}
}
/**
* INTERNAL:
* @param classBuffer
*/
private void buildSetMethodBuffer(ClassBuffer classBuffer, SDOProperty property, java.util.List documentation) {
if (property.getType().isChangeSummaryType()) {
return;
}
if ((documentation != null) && (documentation.size() > 0)) {
classBuffer.getMethodBuffer().append(buildSetterJavaDoc(documentation, property.getName()));
}
classBuffer.getMethodBuffer().append(indent);
classBuffer.getMethodBuffer().append("public void ");
String methodName = SDOUtil.setMethodName(property.getName());
classBuffer.getMethodBuffer().append(methodName);
classBuffer.getMethodBuffer().append("(");
String paramType = SDOUtil.getJavaTypeForProperty(property);
classBuffer.getMethodBuffer().append(paramType).append(" value");
classBuffer.getMethodBuffer().append(")").append(" {").append(lsep);
pushIndent();
classBuffer.getMethodBuffer().append(indent).append("set(");
classBuffer.getMethodBuffer().append(START_PROPERTY_INDEX).append(" + ").append(property.getIndexInDeclaredProperties());
classBuffer.getMethodBuffer().append(" , value)");
classBuffer.getMethodBuffer().append(";").append(lsep);
popIndent();
classBuffer.getMethodBuffer().append(indent).append("}");
classBuffer.getMethodBuffer().append(lsep2);
if (interfaceGenerator) {
classBuffer.getInterfaceBuffer().append(indent);
classBuffer.getInterfaceBuffer().append("public void ");
classBuffer.getInterfaceBuffer().append(methodName);
classBuffer.getInterfaceBuffer().append("(");
classBuffer.getInterfaceBuffer().append(paramType).append(" value");
classBuffer.getInterfaceBuffer().append(");").append(lsep2);
}
}
private void pushIndent() {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < INDENT_TAB; i++) {
buf.append(" ");
}
indent += buf.toString();
}
private void popIndent() {
StringBuffer buf = new StringBuffer();
int size = indent.length() - INDENT_TAB;
for (int i = 0; i < size; i++) {
buf.append(" ");
}
indent = buf.toString();
}
public void setGeneratedBuffers(Map generatedBuffersMap) {
generatedBuffers = generatedBuffersMap;
}
public Map getGeneratedBuffers() {
return generatedBuffers;
}
public void setCodeWriter(CodeWriter theCodeWriter) {
codeWriter = theCodeWriter;
}
public CodeWriter getCodeWriter() {
return codeWriter;
}
public void setSDOClassGeneratorListener(SDOClassGeneratorListener listener) {
sdoClassGeneratorListener = listener;
}
public SDOClassGeneratorListener getSDOClassGeneratorListener() {
return sdoClassGeneratorListener;
}
}