blob: 4847e666acf05d644f6413d11f8c915fd9209487 [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.sessions.factories;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.internal.codegen.ClassDefinition;
import org.eclipse.persistence.internal.codegen.CodeGenerator;
import org.eclipse.persistence.internal.codegen.NonreflectiveMethodDefinition;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.sequencing.TableSequence;
import org.eclipse.persistence.sessions.DatabaseLogin;
import org.eclipse.persistence.tools.schemaframework.FieldDefinition;
import org.eclipse.persistence.tools.schemaframework.ForeignKeyConstraint;
import org.eclipse.persistence.tools.schemaframework.TableCreator;
import org.eclipse.persistence.tools.schemaframework.TableDefinition;
/**
* <p><b>Purpose</b>: Allow for a class storing a TopLink table creator's tables (meta-data) to be generated.
* This class can then be used at runtime to (re)create a project's database schema.
*
* @since TopLink 3.0
* @author James Sutherland
*/
public class TableCreatorClassGenerator {
protected String className;
protected String packageName;
protected String outputPath;
protected String outputFileName;
protected Writer outputWriter;
protected TableCreator tableCreator;
/**
* PUBLIC:
* Create a new generator.
*/
public TableCreatorClassGenerator() {
this.outputPath = "";
this.outputFileName = "TableCreator.java";
this.className = "TableCreator";
this.packageName = "";
}
/**
* PUBLIC:
* Create a new generator to output the table creator.
*/
public TableCreatorClassGenerator(TableCreator tableCreator) {
this();
this.tableCreator = tableCreator;
}
/**
* PUBLIC:
* Create a new generator to output the table creator.
*/
public TableCreatorClassGenerator(TableCreator tableCreator, String projectClassName, Writer outputWriter) {
this(tableCreator);
this.outputWriter = outputWriter;
setClassName(projectClassName);
}
/**
* PUBLIC:
* Create a new generator to output the table creator.
*/
public TableCreatorClassGenerator(TableCreator tableCreator, String projectClassName, String fileName) {
this(tableCreator);
setClassName(projectClassName);
setOutputFileName(fileName);
}
protected void addFieldLines(FieldDefinition field, NonreflectiveMethodDefinition method) {
String fieldName = "field" + field.getName();
method.addLine("FieldDefinition " + fieldName + " = new FieldDefinition();");
method.addLine(fieldName + ".setName(\"" + field.getName() + "\");");
String fieldTypeName = field.getTypeName();
if (fieldTypeName != null) {
method.addLine(fieldName + ".setTypeName(\"" + field.getTypeName() + "\");");
} else {//did not set the field type name, so use the Java type data
method.addLine(fieldName + ".setType(" + field.getType().getName() + ".class);");
}
method.addLine(fieldName + ".setSize(" + field.getSize() + ");");
method.addLine(fieldName + ".setSubSize(" + field.getSubSize() + ");");
method.addLine(fieldName + ".setIsPrimaryKey(" + field.isPrimaryKey() + ");");
method.addLine(fieldName + ".setIsIdentity(" + field.isIdentity() + ");");
method.addLine(fieldName + ".setUnique(" + field.isUnique() + ");");
method.addLine(fieldName + ".setShouldAllowNull(" + field.shouldAllowNull() + ");");
method.addLine("table.addField(" + fieldName + ");");
}
protected void addForeignKeyLines(ForeignKeyConstraint foreignKey, NonreflectiveMethodDefinition method) {
String foreignKeyName = "foreignKey" + foreignKey.getName();
method.addLine("ForeignKeyConstraint " + foreignKeyName + " = new ForeignKeyConstraint();");
method.addLine(foreignKeyName + ".setName(\"" + foreignKey.getName() + "\");");
method.addLine(foreignKeyName + ".setTargetTable(\"" + foreignKey.getTargetTable() + "\");");
for (String sourceField : foreignKey.getSourceFields()) {
method.addLine(foreignKeyName + ".addSourceField(\"" + sourceField + "\");");
}
for (String targetField : foreignKey.getTargetFields()) {
method.addLine(foreignKeyName + ".addTargetField(\"" + targetField + "\");");
}
method.addLine("table.addForeignKeyConstraint(" + foreignKeyName + ");");
}
protected NonreflectiveMethodDefinition buildConstructor() {
NonreflectiveMethodDefinition methodDefinition = new NonreflectiveMethodDefinition();
methodDefinition.setName(getClassName());
methodDefinition.setIsConstructor(true);
methodDefinition.addLine("setName(\"" + getTableCreator().getName() + "\");");
methodDefinition.addLine("");
for (TableDefinition table : getTableCreator().getTableDefinitions()) {
methodDefinition.addLine("addTableDefinition(build" + table.getName() + "Table());");
}
return methodDefinition;
}
protected NonreflectiveMethodDefinition buildLoginMethod(DatabaseLogin login) {
NonreflectiveMethodDefinition method = new NonreflectiveMethodDefinition();
method.setName("applyLogin");
String loginClassName = login.getClass().getName();
if (login.getClass().equals(DatabaseLogin.class)) {
loginClassName = Helper.getShortClassName(login);
}
method.addLine(loginClassName + " login = new " + loginClassName + "();");
method.addLine("login.usePlatform(new " + login.getPlatformClassName() + "());");
method.addLine("login.setDriverClass(" + login.getDriverClassName() + ".class);");
method.addLine("login.setConnectionString(\"" + login.getConnectionString() + "\");");
if (login.getUserName() != null) {
method.addLine("login.setUserName(\"" + login.getUserName() + "\");");
}
if (login.getPassword() != null) {
method.addLine("login.setPassword(\"" + login.getPassword() + "\");");
}
method.addLine("");
method.addLine("// Configuration properties.");
method.addLine("login.setUsesNativeSequencing(" + login.shouldUseNativeSequencing() + ");");
if (!login.shouldUseNativeSequencing()) {
method.addLine("login.setSequenceTableName(\"" + ((TableSequence)login.getDefaultSequence()).getTableName() + "\");");
method.addLine("login.setSequenceNameFieldName(\"" + ((TableSequence)login.getDefaultSequence()).getNameFieldName() + "\");");
method.addLine("login.setSequenceCounterFieldName(\"" + ((TableSequence)login.getDefaultSequence()).getCounterFieldName() + "\");");
}
method.addLine("login.setShouldBindAllParameters(" + login.shouldBindAllParameters() + ");");
method.addLine("login.setShouldCacheAllStatements(" + login.shouldCacheAllStatements() + ");");
method.addLine("login.setUsesByteArrayBinding(" + login.shouldUseByteArrayBinding() + ");");
method.addLine("login.setUsesStringBinding(" + login.shouldUseStringBinding() + ");");
method.addLine("if (login.shouldUseByteArrayBinding()) { // Can only be used with binding.");
method.addLine("\tlogin.setUsesStreamsForBinding(" + login.shouldUseStreamsForBinding() + ");");
method.addLine("}");
method.addLine("login.setShouldForceFieldNamesToUpperCase(" + login.shouldForceFieldNamesToUpperCase() + ");");
method.addLine("login.setShouldOptimizeDataConversion(" + login.shouldOptimizeDataConversion() + ");");
method.addLine("login.setShouldTrimStrings(" + login.shouldTrimStrings() + ");");
method.addLine("login.setUsesBatchWriting(" + login.shouldUseBatchWriting() + ");");
method.addLine("if (login.shouldUseBatchWriting()) { // Can only be used with batch writing.");
method.addLine("\tlogin.setUsesJDBCBatchWriting(" + login.shouldUseJDBCBatchWriting() + ");");
method.addLine("}");
method.addLine("login.setUsesExternalConnectionPooling(" + login.shouldUseExternalConnectionPooling() + ");");
method.addLine("login.setUsesExternalTransactionController(" + login.shouldUseExternalTransactionController() + ");");
method.addLine("setLogin(login);");
return method;
}
protected NonreflectiveMethodDefinition buildTableMethod(TableDefinition table) {
NonreflectiveMethodDefinition method = new NonreflectiveMethodDefinition();
method.setName("build" + table.getName() + "Table");
method.setReturnType("TableDefinition");
// Table
method.addLine("TableDefinition table = new TableDefinition();");
method.addLine("table.setName(\"" + table.getName() + "\");");
// Fields
for (FieldDefinition field : table.getFields()) {
method.addLine("");
addFieldLines(field, method);
}
// Constraints
for (ForeignKeyConstraint foreignKey : table.getForeignKeys()) {
method.addLine("");
addForeignKeyLines(foreignKey, method);
}
method.addLine("");
method.addLine("return table;");
return method;
}
/**
* PUBLIC:
* Generate the creator class, output the java source code to the stream or file.
* useUnicode determines if unicode escaped characters for non_ASCII charaters will be used.
*/
public void generate(boolean useUnicode) throws ValidationException {
if (getOutputWriter() == null) {
try {
setOutputWriter(new OutputStreamWriter(new FileOutputStream(getOutputPath() + getOutputFileName())));
} catch (IOException exception) {
throw ValidationException.fileError(exception);
}
}
CodeGenerator generator = new CodeGenerator(useUnicode);
generator.setOutput(getOutputWriter());
generateCreatorClass().write(generator);
try {
getOutputWriter().flush();
getOutputWriter().close();
} catch (IOException exception) {
throw ValidationException.fileError(exception);
}
}
/**
* PUBLIC:
* Generate the project class, output the java source code to the stream or file.
* Unicode escaped characters for non_ASCII charaters will be used.
*/
public void generate() throws ValidationException {
generate(true);
}
/**
* Return a class definition object representing the code to be generated for the table creator.
* This class will have one method per descriptor and its toString can be used to convert it to code.
*/
protected ClassDefinition generateCreatorClass() {
ClassDefinition classDefinition = new ClassDefinition();
classDefinition.setName(getClassName());
classDefinition.setSuperClass("org.eclipse.persistence.tools.schemaframework.TableCreator");
classDefinition.setPackageName(getPackageName());
classDefinition.addImport("org.eclipse.persistence.sessions.*");
classDefinition.addImport("org.eclipse.persistence.tools.schemaframework.*");
classDefinition.setComment("This class was generated by the TopLink table creator generator." + Helper.cr() + "It stores the meta-data (tables) that define the database schema." + Helper.cr() + "@see org.eclipse.persistence.sessions.factories.TableCreatorClassGenerator");
classDefinition.addMethod(buildConstructor());
for (TableDefinition table : getTableCreator().getTableDefinitions()) {
classDefinition.addMethod(buildTableMethod(table));
}
return classDefinition;
}
/**
* PUBLIC:
* Return the name of class to be generated.
* This is the unqualified name.
*/
public String getClassName() {
return className;
}
/**
* PUBLIC:
* Return the file name that the generate .java file will be output to.
*/
public String getOutputFileName() {
return outputFileName;
}
/**
* PUBLIC:
* Return the path that the generate .java file will be output to.
*/
public String getOutputPath() {
return outputPath;
}
/**
* PUBLIC:
* Return the writer the output to.
*/
public Writer getOutputWriter() {
return outputWriter;
}
/**
* PUBLIC:
* Return the package name of class to be generated.
*/
public String getPackageName() {
return packageName;
}
/**
* PUBLIC:
* Return the table creator to generate from.
*/
public TableCreator getTableCreator() {
return tableCreator;
}
/**
* Return the printed version of the primitive value object.
* This must determine the class and use the correct constrcutor arguments.
*/
protected String printString(Object value) {
if ((value == null) || (value == Helper.NULL_VALUE)) {
return "null";
}
if (value instanceof String) {
return "\"" + value + "\"";
}
// This handles most cases.
return "new " + Helper.getShortClassName(value) + "(" + value + ")";
}
protected String removeDots(String packageName) {
StringWriter writer = new StringWriter();
int startIndex = 0;
int dotIndex = packageName.indexOf('.', startIndex);
while (dotIndex >= 0) {
writer.write(packageName.substring(startIndex, dotIndex));
startIndex = dotIndex + 1;
dotIndex = packageName.indexOf('.', startIndex);
}
writer.write(packageName.substring(startIndex));
return writer.toString();
}
/**
* PUBLIC:
* Set the name of class to be generated.
* This can be qualified or unqualified name and will set the file name to match.
*/
public void setClassName(String newClassName) {
int lastDotIndex = newClassName.lastIndexOf('.');
if (lastDotIndex >= 0) {
className = newClassName.substring(lastDotIndex + 1);
setPackageName(newClassName.substring(0, lastDotIndex));
} else {
className = newClassName;
}
setOutputFileName(newClassName);
}
/**
* PUBLIC:
* Set the file name that the generate .java file will be output to.
* If the file does not include .java it will be appended.
*/
public void setOutputFileName(String newOutputFileName) {
if (!newOutputFileName.contains(".java")) {
outputFileName = newOutputFileName + ".java";
} else {
outputFileName = newOutputFileName;
}
}
/**
* PUBLIC:
* Set the path that the generate .java file will be output to.
*/
public void setOutputPath(String newOutputPath) {
outputPath = newOutputPath;
}
/**
* PUBLIC:
* Set the writer the output to.
*/
public void setOutputWriter(Writer outputWriter) {
this.outputWriter = outputWriter;
}
/**
* PUBLIC:
* Set the package name of class to be generated.
*/
public void setPackageName(String newPackageName) {
packageName = newPackageName;
}
/**
* PUBLIC:
* Set the table creator to generate from.
* All of the creator's tables will be stored into the file.
*/
public void setTableCreator(TableCreator tableCreator) {
this.tableCreator = tableCreator;
}
/**
* PUBLIC:
* Generate the source code to a table creator class to the table creator's tables into the writer.
*/
public static void write(TableCreator tableCreator, String creatorClassName, Writer writer) {
TableCreatorClassGenerator generator = new TableCreatorClassGenerator(tableCreator, creatorClassName, writer);
generator.generate();
}
/**
* PUBLIC:
* Generate the source code to a table creator class to the table creator's tables into the file.
*/
public static void write(TableCreator tableCreator, String creatorClassName, String fileName) {
TableCreatorClassGenerator generator = new TableCreatorClassGenerator(tableCreator, creatorClassName, fileName);
generator.generate();
}
}