You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@empire-db.apache.org by do...@apache.org on 2020/10/07 12:30:30 UTC
[empire-db] branch master updated: EMPIREDB-334 Improve
customizablity of data model code generation
This is an automated email from the ASF dual-hosted git repository.
doebele pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/empire-db.git
The following commit(s) were added to refs/heads/master by this push:
new ef77ca0 EMPIREDB-334 Improve customizablity of data model code generation
ef77ca0 is described below
commit ef77ca02614684714d32871aa427396385296cb6
Author: Rainer Döbele <do...@apache.org>
AuthorDate: Wed Oct 7 14:30:23 2020 +0200
EMPIREDB-334 Improve customizablity of data model code generation
---
.../apache/empire/db/codegen/CodeGenConfig.java | 31 ++++++++++-
.../apache/empire/db/codegen/CodeGenParser.java | 64 ++++++++++++++++------
.../apache/empire/db/codegen/CodeGenWriter.java | 61 +++++++++++++++------
.../apache/empire/db/codegen/WriterService.java | 28 +++++++---
.../src/main/resources/templates/BaseRecord.vm | 5 +-
.../src/main/resources/templates/Database.vm | 11 +++-
.../src/main/resources/templates/Table.vm | 5 +-
.../src/main/resources/templates/View.vm | 4 +-
8 files changed, 159 insertions(+), 50 deletions(-)
diff --git a/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenConfig.java b/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenConfig.java
index 92f7d93..848cbf2 100644
--- a/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenConfig.java
+++ b/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenConfig.java
@@ -61,6 +61,10 @@ public class CodeGenConfig extends XMLConfiguration {
* flag whether to parse and generate views
*/
private boolean generateViews = true;
+ /**
+ * flag whether to parse and generate views
+ */
+ private boolean generateRecords = true;
/**
* Name of the timestamp column used for optimistic locking (may be null)
* e.g. "UPDATE_TIMESTAMP";
@@ -223,7 +227,12 @@ public class CodeGenConfig extends XMLConfiguration {
/**
* true if names of foreign-key-relations should be preserved
*/
- private boolean preserveRelationNames = false;
+ private boolean preserveRelationNames = false;
+
+ /**
+ * classname of the writerService
+ */
+ private String writerServiceClass;
/**
* Initialize the configuration.
@@ -333,6 +342,16 @@ public class CodeGenConfig extends XMLConfiguration {
this.generateViews = generateViews;
}
+ public boolean isGenerateRecords()
+ {
+ return generateRecords;
+ }
+
+ public void setGenerateRecords(boolean generateRecords)
+ {
+ this.generateRecords = generateRecords;
+ }
+
public String getTimestampColumn() {
return timestampColumn;
}
@@ -516,7 +535,15 @@ public class CodeGenConfig extends XMLConfiguration {
this.preserveRelationNames = preserveRelationNames;
}
- private String fallback(String packageName, String defaultSubpackage){
+ public String getWriterServiceClass() {
+ return writerServiceClass;
+ }
+
+ public void setWriterServiceClass(String writerServiceClass) {
+ this.writerServiceClass = writerServiceClass;
+ }
+
+ private String fallback(String packageName, String defaultSubpackage){
String pkg = packageName;
if( pkg == null && this.packageName != null){
pkg = this.packageName + "." + defaultSubpackage;
diff --git a/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenParser.java b/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenParser.java
index 4f2b112..5fc8a5a 100644
--- a/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenParser.java
+++ b/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenParser.java
@@ -25,6 +25,7 @@ import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
@@ -117,7 +118,7 @@ public class CodeGenParser {
* JDBC url, user and password for the connection are obained from the SampleConfig bean
* Please use the config.xml file to change connection params.
*/
- private Connection openJDBCConnection(CodeGenConfig config) throws SQLException{
+ protected Connection openJDBCConnection(CodeGenConfig config) throws SQLException{
log.info("Connecting to Database'" + config.getJdbcURL() + "' / User=" + config.getJdbcUser());
Connection conn = null;
try {
@@ -129,13 +130,33 @@ public class CodeGenParser {
log.info("Connected successfully");
return conn;
}
+
+ /**
+ * Returns whether to add the table or ignore it
+ * @param tableName
+ */
+ protected boolean isPopulateTable(String tableName)
+ {
+ if (tableName.indexOf('$') >= 0)
+ return false;
+ return true;
+ }
+
+ /**
+ * Returns whether to add the column or ignore it
+ * @param columnName
+ */
+ protected boolean isPopulateColumn(String columnName)
+ {
+ return true;
+ }
/**
* Queries the metadata of the database for tables and vies and populates the
* database with those
* @throws SQLException
*/
- private void populateDatabase(DBDatabase db) throws SQLException {
+ protected void populateDatabase(DBDatabase db) throws SQLException {
ResultSet tables = null;
ArrayList<String> populatedTables=new ArrayList<String>();
try{
@@ -160,13 +181,16 @@ public class CodeGenParser {
// Add all tables and views
while (tables.next()) {
String tableName = tables.getString("TABLE_NAME");
+ if (!isPopulateTable(tableName)) {
+ log.info("Ignoring table " + tableName);
+ continue;
+ }
+ // show
String tableType = tables.getString("TABLE_TYPE");
- // Ignore system tables containing a '$' symbol (required for Oracle!)
- if (tableName.indexOf('$') >= 0) {
- log.info("Ignoring system table " + tableName);
- continue;
- }
- log.info(tableType + ": " + tableName);
+ String tableSchema = tables.getString("TABLE_SCHEM");
+ String templ = StringUtils.isNotEmpty(tableSchema) ? "{0}: {1} ({2})" : "{0}: {1}";
+ log.info(MessageFormat.format(templ, tableType, tableName, tableSchema));
+ // Table or View
if(tableType.equalsIgnoreCase("VIEW")){
InMemoryView view = new InMemoryView(tableName, db);
populateView(view);
@@ -196,7 +220,7 @@ public class CodeGenParser {
}
}
- private void gatherRelations(DBDatabase db, DatabaseMetaData dbMeta, ArrayList<String> tables) throws SQLException{
+ protected void gatherRelations(DBDatabase db, DatabaseMetaData dbMeta, ArrayList<String> tables) throws SQLException{
ResultSet relations = null;
String fkTableName, pkTableName, fkColName, pkColName, relName;
DBTableColumn fkCol, pkCol;
@@ -268,7 +292,7 @@ public class CodeGenParser {
}
}
- private String getCatalogs(DatabaseMetaData dbMeta) throws SQLException {
+ protected String getCatalogs(DatabaseMetaData dbMeta) throws SQLException {
String retVal = "";
ResultSet rs = dbMeta.getCatalogs();
while (rs.next()) {
@@ -280,7 +304,7 @@ public class CodeGenParser {
return retVal;
}
- private String getSchemata(DatabaseMetaData dbMeta) throws SQLException {
+ protected String getSchemata(DatabaseMetaData dbMeta) throws SQLException {
String retVal = "";
ResultSet rs = dbMeta.getSchemas();
while (rs.next()) {
@@ -296,7 +320,7 @@ public class CodeGenParser {
* table with that information
* @throws SQLException
*/
- private void populateTable(DBTable t) throws SQLException {
+ protected void populateTable(DBTable t) throws SQLException {
List<String> pkCols = this.findPkColumns(t.getName());
String lockColName = config.getTimestampColumn();
DBColumn[] keys = new DBColumn[pkCols.size()];
@@ -306,6 +330,8 @@ public class CodeGenParser {
int i=0;
while (rs.next()) {
DBTableColumn c = addColumn(t, rs, lockColName);
+ if (c==null)
+ continue;
// check if it is a KeyColumn
if (pkCols.contains(c.getName()))
keys[i++] = c;
@@ -328,7 +354,7 @@ public class CodeGenParser {
* table with that information
* @throws SQLException
*/
- private void populateView(InMemoryView v) throws SQLException {
+ protected void populateView(InMemoryView v) throws SQLException {
ResultSet rs = null;
try {
rs = dbMeta.getColumns(config.getDbCatalog(), config.getDbSchema(),
@@ -346,7 +372,7 @@ public class CodeGenParser {
* table.
* @throws SQLException
*/
- private List<String> findPkColumns(String tableName) throws SQLException {
+ protected List<String> findPkColumns(String tableName) throws SQLException {
List<String> cols = new ArrayList<String>();
ResultSet rs = null;
try {
@@ -365,9 +391,15 @@ public class CodeGenParser {
* Adds DBColumn object to the given DBTable. The DBColumn is created from
* the given ResultSet
*/
- private DBTableColumn addColumn(DBTable t, ResultSet rs, String lockColName)
+ protected DBTableColumn addColumn(DBTable t, ResultSet rs, String lockColName)
throws SQLException {
- String name = rs.getString("COLUMN_NAME");
+
+ String name = rs.getString("COLUMN_NAME");
+ if (!isPopulateColumn(name)) {
+ log.info("Ignoring column " + name);
+ return null;
+ }
+
DataType empireType = getEmpireDataType(rs.getInt("DATA_TYPE"));
double colSize = getColumnSize(empireType, rs.getInt("DATA_TYPE"), rs.getInt("COLUMN_SIZE"));
diff --git a/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenWriter.java b/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenWriter.java
index b9eafb9..220b06d 100644
--- a/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenWriter.java
+++ b/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/CodeGenWriter.java
@@ -89,24 +89,23 @@ public class CodeGenWriter {
/**
* Constructor
*/
- public CodeGenWriter(CodeGenConfig config) {
- this.writerService = new WriterService(config);
+ public CodeGenWriter(CodeGenConfig config, WriterService writerService) {
+ this.writerService = writerService;
this.config = config;
- this.engine = new VelocityEngine();
+ this.engine = new VelocityEngine();
// we have to keep this in sync with our logging system
// http://velocity.apache.org/engine/releases/velocity-1.5/developer-guide.html#simpleexampleofacustomlogger
- engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM,
- new CommonsLogLogChute());
+ engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new CommonsLogLogChute());
if(config.getTemplateFolder() == null){
engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
engine.setProperty("classpath." + RuntimeConstants.RESOURCE_LOADER + ".class", ClasspathResourceLoader.class.getName());
- }else{
+ } else {
File templateFolder = new File(config.getTemplateFolder());
if(!templateFolder.canRead()){
throw new RuntimeException("Provided template folder missing or not readable: " + config.getTemplateFolder());
}
}
-
+ // init engine
try {
engine.init();
} catch (Exception e) {
@@ -116,6 +115,14 @@ public class CodeGenWriter {
}
/**
+ * Overload using standard WriterService
+ * @param config
+ */
+ public CodeGenWriter(CodeGenConfig config) {
+ this(config, new WriterService(config));
+ }
+
+ /**
* Generates the java code files for the database
*
* @param db
@@ -131,25 +138,35 @@ public class CodeGenWriter {
generatedFiles.add(this.createDatabaseClass(db));
// Create base table class
- generatedFiles.add(this.createBaseTableClass(db));
+ if (config.getTableBaseName().equals("DBTable")==false) {
+ generatedFiles.add(this.createBaseTableClass(db));
+ }
+
+ // Create base record class
+ if (config.isGenerateRecords()) {
+ generatedFiles.add(this.createBaseRecordClass(db));
+ }
// Create base view class
- generatedFiles.add(this.createBaseViewClass(db));
-
- // Create base record class
- generatedFiles.add(this.createBaseRecordClass(db));
+ if (config.isGenerateViews() && config.getViewBaseName().equals("DBView")==false) {
+ generatedFiles.add(this.createBaseViewClass(db));
+ }
+
// Create table classes, record interfaces and record classes
for (DBTable table : db.getTables()) {
if (!config.isNestTables()) {
// if table nesting is disabled, create separate table classes
generatedFiles.add(this.createTableClass(db, table));
}
- generatedFiles.add(this.createRecordClass(db, table));
+ if (config.isGenerateRecords()) {
+ // generate record
+ generatedFiles.add(this.createRecordClass(db, table));
+ }
}
// Create view classes
for (DBView view : db.getViews()) {
- if (!config.isNestViews()) {
+ if (config.isGenerateViews() && !config.isNestViews()) {
// if table nesting is disabled, create separate table classes
generatedFiles.add(this.createViewClass(db, view));
}
@@ -170,15 +187,23 @@ public class CodeGenWriter {
// Clean out the directory so old code is wiped out.
FileUtils.cleanDirectory(this.baseDir);
-
+
+ boolean createTables = (!config.isNestTables() || !config.getTableBaseName().equals("DBTable"));
+ boolean createViews = config.isGenerateViews() && (!config.isNestViews() || !config.getViewBaseName().equals("DBView"));
+ boolean craeteRecords = config.isGenerateRecords();
+
+ // createViews
+ if (!createViews)
+ config.setViewPackageName(config.getPackageName());
+
// Create the table package directory
- this.tableDir = FileUtils.getFileFromPackage(targetDir, config.getTablePackageName());
+ this.tableDir = (createTables ? FileUtils.getFileFromPackage(targetDir, config.getTablePackageName()) : null);
// Create the record package directory
- this.recordDir = FileUtils.getFileFromPackage(targetDir, config.getRecordPackageName());
+ this.recordDir = (craeteRecords ? FileUtils.getFileFromPackage(targetDir, config.getRecordPackageName()) : null);
// Create the record package directory
- this.viewDir = FileUtils.getFileFromPackage(targetDir, config.getViewPackageName());
+ this.viewDir = (createViews ? FileUtils.getFileFromPackage(targetDir, config.getViewPackageName()) : null);
}
private File createDatabaseClass(DBDatabase db) {
diff --git a/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/WriterService.java b/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/WriterService.java
index cb1fb1f..bb158b1 100644
--- a/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/WriterService.java
+++ b/empire-db-codegen/src/main/java/org/apache/empire/db/codegen/WriterService.java
@@ -57,7 +57,7 @@ public class WriterService {
* the method names.
* @return the DBRecord method's names
*/
- private Set<String> loadDBRecordMethodNames()
+ protected Set<String> loadDBRecordMethodNames()
{
Method[] dbrecMethods = DBRecord.class.getMethods();
Set<String> names = new HashSet<String>(dbrecMethods.length);
@@ -267,7 +267,7 @@ public class WriterService {
/**
* Returns the default value of the given DBColumn.
*/
- public String getDefaultValue(DBColumn c)
+ protected String getDefaultValue(DBColumn c)
{
DBTableColumn dbC = (DBTableColumn) c;
Object val = dbC.getDefaultValue();
@@ -286,7 +286,7 @@ public class WriterService {
/**
* Derives a java class name from a database table name.
*/
- private String deriveClassName(String name)
+ protected String deriveClassName(String name)
{
// PreserverCharacterCase
if (config.isPreserverCharacterCase()) {
@@ -328,7 +328,7 @@ public class WriterService {
* @param isBoolean
* @return
*/
- private String deriveAccessorName(String attribute, Class<?> type)
+ protected String deriveAccessorName(String attribute, Class<?> type)
{
return deriveRecordMethodName(attribute, type, true);
}
@@ -339,7 +339,7 @@ public class WriterService {
* so that getter and setter have matching suffixes if one or
* the other conflicts with an existing method.
*/
- private String deriveRecordMethodName(String attribute, Class<?> type, boolean isGetter) {
+ protected String deriveRecordMethodName(String attribute, Class<?> type, boolean isGetter) {
attribute = deriveAttributeName(attribute);
StringBuilder attributeName = new StringBuilder();
attributeName.append(Character.toUpperCase(attribute.charAt(0)));
@@ -374,7 +374,7 @@ public class WriterService {
return attributeName.toString();
}
- private String getGetterPrefix(Class<?> type){
+ protected String getGetterPrefix(Class<?> type){
if (type == boolean.class || type == Boolean.class)
{
return "is";
@@ -391,7 +391,7 @@ public class WriterService {
* @param attribute
* @return
*/
- private String deriveMutatorName(String attribute, Class<?> type)
+ protected String deriveMutatorName(String attribute, Class<?> type)
{
return deriveRecordMethodName(attribute, type, false);
}
@@ -402,8 +402,20 @@ public class WriterService {
* @param attribute
* @return
*/
- private String deriveAttributeName(String column)
+ protected String deriveAttributeName(String column)
{
+ // find invalid chars
+ char[] invalidChars = new char[] { '$','#' };
+ for (int i=0; i<invalidChars.length; i++)
+ { // Remove
+ char c = invalidChars[i];
+ if (column.indexOf(c)>=0)
+ column=StringUtils.remove(column, c);
+ }
+ // replace dash
+ if (column.indexOf('-')>=0)
+ column=column.replace('-','_');
+ // replace space
return column.replace(' ', '_');
}
diff --git a/empire-db-codegen/src/main/resources/templates/BaseRecord.vm b/empire-db-codegen/src/main/resources/templates/BaseRecord.vm
index 06b0563..b23f7e4 100644
--- a/empire-db-codegen/src/main/resources/templates/BaseRecord.vm
+++ b/empire-db-codegen/src/main/resources/templates/BaseRecord.vm
@@ -19,8 +19,11 @@
package ${recordPackageName};
import org.apache.empire.db.DBRecord;
+#if($baseTableClassName.equals('DBTable'))
+import org.apache.empire.db.DBTable;
+#else
import ${tablePackageName}.${baseTableClassName};
-
+#end
public abstract class ${baseRecordClassName}<T extends ${baseTableClassName}> extends DBRecord {
diff --git a/empire-db-codegen/src/main/resources/templates/Database.vm b/empire-db-codegen/src/main/resources/templates/Database.vm
index aafa65c..bfb7184 100644
--- a/empire-db-codegen/src/main/resources/templates/Database.vm
+++ b/empire-db-codegen/src/main/resources/templates/Database.vm
@@ -28,18 +28,23 @@ import org.apache.empire.db.DBDatabase;
#if($preserveRelationNames == true)
import org.apache.empire.db.DBRelation;
#end
+#if($nestTables==true && $baseTableClassName.equals('DBTable'))
+import org.apache.empire.db.DBTable;
+#end
#if($nestTables == true)
import org.apache.empire.db.DBTableColumn;
#end
+#if($nestViews==true && $baseViewClassName.equals('DBView'))
+import org.apache.empire.db.DBView;
+#end
#if($nestViews == true)
import org.apache.empire.exceptions.NotImplementedException;
#end
-#if($nestTables==false || !($tablePackageName.equalsIgnoreCase($basePackageName)))
+#if($nestTables==false && !($tablePackageName.equalsIgnoreCase($basePackageName)))
import $tablePackageName.*;
-// $tablePackageName vs $basePackageName
#end
-#if($nestViews==false || ($viewPackageName!=$basePackageName))
+#if($nestViews==false && !($viewPackageName.equalsIgnoreCase($basePackageName)))
import $viewPackageName.*;
#end
diff --git a/empire-db-codegen/src/main/resources/templates/Table.vm b/empire-db-codegen/src/main/resources/templates/Table.vm
index 4f8d382..aac0b1c 100644
--- a/empire-db-codegen/src/main/resources/templates/Table.vm
+++ b/empire-db-codegen/src/main/resources/templates/Table.vm
@@ -19,6 +19,9 @@
#if($nestTables == false)
package $tablePackageName;
+#if($baseTableClassName.equals('DBTable'))
+import org.apache.empire.db.DBTable;
+#end
import org.apache.empire.data.DataType;
import org.apache.empire.db.DBTableColumn;
import $basePackageName.${dbClassName};
@@ -50,8 +53,8 @@ public class $parser.getTableClassName($table.name) extends ${baseTableClassName
#end
+#if($table.keyColumns && $table.keyColumns.size()>0)
// configure key columns (primary key)
-#if($table.keyColumns.size()>0)
#if($table.keyColumns.size()==1)
setPrimaryKey(${parser.getColumnName($table.keyColumns[0])});
#else
diff --git a/empire-db-codegen/src/main/resources/templates/View.vm b/empire-db-codegen/src/main/resources/templates/View.vm
index 0c875b9..9400c34 100644
--- a/empire-db-codegen/src/main/resources/templates/View.vm
+++ b/empire-db-codegen/src/main/resources/templates/View.vm
@@ -20,12 +20,14 @@
#if($nestViews == false)
package $viewPackageName;
+#if($baseViewClassName.equals('DBView'))
+import org.apache.empire.db.DBView;
+#end
import org.apache.empire.data.DataType;
import org.apache.empire.db.DBCommandExpr;
import org.apache.empire.exceptions.NotImplementedException;
import $basePackageName.${dbClassName};
-
#end
#if($nestViews == true)