Hi there,
i have crated a eclipse-patch that contains the codegenerator with very
basic functionality.
I have taken care of multi-column primary keys, the connection stuff as
well as the unclosed ResultSets.
The generator is quit basic at the moment and the following will not work:
- column specific getters/setters on specific records
- nested table generation within the database
- relation mapping (foreign key dependencies)
- locking columns
- views
- name prefix for tables, views
- configuration of schemaPattern, catalogName, tablePattern, this is
hardcoded at the moment with (null, null, null) see "// TODO 01" in the
sourcecode.
A additional configuration option was added named "outputFolder" this is
the folder where the generated sourcode will be stored.
I'd be happy if anyone could have a look at it.
Regards
Benjamin
Rainer Döbele schrieb:
Hi Benni,
yes I would be grateful if you could do that.
We just have to make sure that we don't work on the same subject.
The first goal should be to create a connection and generate the database and
table classes.
Thomas is using a BasicDataSource for connection pooling.
However I don't think we need to do that. I'd rather have a simple JDBC
connection like the one we use in our samples.
Further we need to find a solution for detecting the primary key column.
We cannot assume the primary key is always a single column with the same name
throughout the db.
What I also found is that ResultSets obtained for reading meta data are not
always closed.
e.g. ResultSet tables = dbMeta.getTables(...)
should be closed in a finally block.
Rather than trying to get over as much code as possible we should carefully
rethink how we can improve the overall architecture and do several small steps
instead of one big one. I am convinced this will lead to a better solution.
So please let me know until when you think you can come up with the first
classes to integrate.
Regards
Rainer
[email protected] wrote:
Re: Starting with Empire-db code generator
Hi,
I had a look at the classes rainer provided in the repository and at
those of thomas. I think we can reuse a large part of thomas' code,
however we'll have to rewrite some things like the table generation
part
and remove some things like configuration and connection stuff (rainer
already provided that in the repo).
So my suggestion is to migrate thomas' code with its functionality and
behavior as it is for now and adapt/rewrite it in the next steps to our
needs. Please let me know what you think. I'd be happy to start with
the
migration soon.
Regards
Benjamin
Rainer Döbele schrieb:
Hi,
I will have a look at it this weekend.
I am sorry, but I have just been very very busy recently.
Regards
Rainer
Francis De Brabandere wrote:
Re: Starting with Empire-db code generator
What should be done to get this going?
On Thu, Oct 15, 2009 at 1:09 PM, Martijn Dashorst
<[email protected]> wrote:
On Mon, Oct 12, 2009 at 9:28 AM, Rainer Döbele <[email protected]>
wrote:
the current code is IMO not flexible enough and even more
important
it is Thomas' code and I see legal problems in just copying the
code.
As long as Thomas has signed a CLA, wrote the code, and is allowed
to
license it to the ASF, there are no legal problems in copying the
code.
Martijn
--
http://www.somatik.be
Microsoft gives you windows, Linux gives you the whole house.
### Eclipse Workspace Patch 1.0
#P empire-db-codegen
Index: src/main/resources/templates/Database.vm
===================================================================
--- src/main/resources/templates/Database.vm (revision 0)
+++ src/main/resources/templates/Database.vm (revision 0)
@@ -0,0 +1,99 @@
+package $basePackageName;
+
+import java.sql.Connection;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBDatabase;
+import org.apache.empire.db.DBReader;
+import org.apache.empire.db.DBRecord;
+
+import $basePackageName.$tableSubPackage.*;
+
+public class $dbClassName extends DBDatabase {
+
+ private static $dbClassName instance;
+ private static final long serialVersionUID = 1L;
+
+#foreach($table in $database.tables)
+ public final $table.className T_$table.tableName = new
${table.className}(this);
+#end
+
+ /**
+ * Returns the instance of the database.
+ * @return
+ */
+ public static $dbClassName get() {
+ if (instance == null) {
+ instance = new ${dbClassName}();
+ }
+ return instance;
+ }
+
+ /**
+ * Default constructor for the $dbClassName.
+ */
+ private ${dbClassName}() {
+ }
+
+ /**
+ * Convenience method that returns a single DB record based on a given
+ * command (i.e. query). Only use this method for queries that should
only
+ * return a single value.
+ * @param <T> The DB record type.
+ * @param recordType The DB record class.
+ * @param command The command (or query) to execute.
+ * @return
+ */
+ public <T extends DBRecord> T findRecord(Class<T> recordType,
+ DBCommand command, Connection conn) {
+ DBReader reader = new DBReader();
+ T record = null;
+ try {
+ if (reader.getRecordData(command, conn)) {
+ record = recordType.newInstance();
+ reader.initRecord(record.getRowSet(), record);
+ }
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ finally {
+ reader.close();
+ }
+ return record;
+ }
+
+ /**
+ * Convenience method that returns a list of DB records based on a
given
+ * command (i.e. query).
+ * @param <T> The DB record type.
+ * @param recordType The DB record class.
+ * @param command The command (or query) to execute.
+ * @return
+ */
+ public <T extends DBRecord> List<T> findRecords(Class<T> recordType,
+ DBCommand command, Connection conn) {
+ List<T> records = new ArrayList<T>();
+ DBReader reader = new DBReader();
+ try {
+ reader.open(command, conn);
+ while (reader.moveNext()) {
+ T record = recordType.newInstance();
+ reader.initRecord(record.getRowSet(), record);
+ records.add(record);
+ }
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ finally {
+ reader.close();
+ }
+ return records;
+ }
+}
Index: src/main/java/org/apache/empire/db/codegen/mapper/Table.java
===================================================================
--- src/main/java/org/apache/empire/db/codegen/mapper/Table.java
(revision 0)
+++ src/main/java/org/apache/empire/db/codegen/mapper/Table.java
(revision 0)
@@ -0,0 +1,107 @@
+package org.apache.empire.db.codegen.mapper;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.codegen.util.DBUtil;
+import org.apache.empire.db.codegen.util.StringUtils;
+
+public class Table {
+ private String tableName;
+ private List<String> pkCols;
+ private List<Column> columns;
+ private Log log;
+
+ private Map<String, Column> columnMap = new HashMap<String, Column>();
+
+ public Table(String tableName, String schemaPattern, String catalogName,
+ DatabaseMetaData dbMeta, Log log) {
+ this.tableName = tableName.toUpperCase();
+ this.log = log;
+ this.createColumns(dbMeta, schemaPattern, catalogName);
+ }
+
+ public String getTableName() {
+ return tableName.toUpperCase();
+ }
+
+ public List<Column> getColumns() {
+ return columns;
+ }
+
+ public String getClassName() {
+ return StringUtils.javaClassName(this.tableName) + "Table";
+ }
+
+ public String getRecordClassName() {
+ return StringUtils.javaClassName(this.tableName) + "Record";
+ }
+
+ public boolean hasBigDecimalField() {
+ boolean bdField = false;
+ for (Column col : this.columns) {
+ if (col.getEmpireType() == DataType.DECIMAL) {
+ bdField = true;
+ break;
+ }
+ }
+ return bdField;
+ }
+
+ public Column getColumn(String name) {
+ return this.columnMap.get(name.toUpperCase());
+ }
+
+ //
------------------------------------------------------------------------
+ // Private members
+ //
------------------------------------------------------------------------
+ private void createColumns(DatabaseMetaData dbMeta, String
schemaPattern,
+ String catalogName) {
+ this.pkCols = this.findPkColumns(dbMeta, schemaPattern,
catalogName);
+ this.columns = new ArrayList<Column>();
+ ResultSet rs = null;
+ try {
+ rs = dbMeta.getColumns(null, null, tableName, null);
+ boolean isKeyCol;
+ String colName;
+ while (rs.next()) {
+ colName =
rs.getString("COLUMN_NAME").toUpperCase();
+ log.info("\tCOLUMN:\t" + colName);
+ isKeyCol = pkCols.contains(colName);
+
+ Column col = new Column(rs, isKeyCol);
+ this.columns.add(col);
+ this.columnMap.put(col.getName().toUpperCase(),
col);
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ } finally {
+ DBUtil.closeResultSet(rs, log);
+ }
+ }
+
+ private List<String> findPkColumns(DatabaseMetaData dbMeta,
+ String schemaPattern, String catalogName) {
+ List<String> cols = new ArrayList<String>();
+ ResultSet rs = null;
+ try {
+ rs = dbMeta.getPrimaryKeys(catalogName, schemaPattern,
tableName);
+ while (rs.next()) {
+
cols.add(rs.getString("COLUMN_NAME").toUpperCase());
+ }
+
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ } finally {
+ DBUtil.closeResultSet(rs, log);
+ }
+ return cols;
+ }
+}
Index: src/main/java/org/apache/empire/db/codegen/util/FileUtils.java
===================================================================
--- src/main/java/org/apache/empire/db/codegen/util/FileUtils.java
(revision 0)
+++ src/main/java/org/apache/empire/db/codegen/util/FileUtils.java
(revision 0)
@@ -0,0 +1,143 @@
+package org.apache.empire.db.codegen.util;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+public class FileUtils {
+ /**
+ * Recursively cleans (removes) all files under the given
+ * directory. Note that this removes all sub-directories
+ * but not the parent directory.
+ * @param directory
+ */
+ public static void cleanDirectory(File directory) {
+ if (directory.isDirectory()) {
+ String[] children = directory.list();
+ for (int i=0; i<children.length; i++) {
+ File child = new File(directory, children[i]);
+ if (child.isDirectory()) deleteDirectory(child);
+ else child.delete();
+ }
+ }
+ }
+
+ /**
+ * Recursively deletes a directory and everything under it.
+ * @param directory
+ */
+ public static void deleteDirectory(File directory) {
+ if (directory.isDirectory()) {
+ String[] children = directory.list();
+ for (int i=0; i<children.length; i++) {
+ deleteDirectory(new File(directory, children[i]));
+ }
+ }
+ // The directory is now empty so delete it
+ directory.delete();
+ }
+
+ /**
+ * Non-recursive delete for all files in the given directory.
+ * Files in sub-directories not deleted.
+ * @param directory
+ */
+ public static void deleteFiles(File directory) {
+ if (directory.isDirectory()) {
+ String[] children = directory.list();
+ for (int i=0; i<children.length; i++) {
+ new File(directory, children[i]).delete();
+ }
+ }
+ }
+ public static Object readObject(String fileName) {
+ Object o = null;
+ try {
+ ObjectInputStream ois = new ObjectInputStream(
+ new FileInputStream(fileName));
+ o = ois.readObject();
+ ois.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ return o;
+ }
+
+ public static void writeObject(String fileName, Object o) {
+ try {
+ ObjectOutputStream oos = new ObjectOutputStream(
+ new FileOutputStream(fileName));
+ oos.writeObject(o);
+ oos.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ public static String getFileAsString(File file) {
+ StringBuilder sb = new StringBuilder();
+ try {
+ BufferedReader br = new BufferedReader(
+ new FileReader(file));
+ String line;
+ while ( (line = br.readLine()) != null) {
+ sb.append(line).append("\n");
+ }
+ br.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return sb.toString();
+ }
+
+ public static void writeStringToFile(File file, String contents) {
+ try {
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ BufferedWriter bw;
+ bw = new BufferedWriter(new FileWriter(file));
+ bw.write(contents);
+ bw.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ public static void replaceAll(File file, String input, String output) {
+ String fileText = getFileAsString(file);
+ StringBuilder sb = new StringBuilder(fileText);
+ int index = -1;
+ int length = input.length();
+ while ( (index = sb.indexOf(input)) != -1 ) {
+ sb.replace(index, index + length, output);
+ }
+ BufferedWriter bw;
+ try {
+ bw = new BufferedWriter(
+ new FileWriter(file));
+ bw.write(sb.toString());
+ bw.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
Index: src/main/resources/templates/Table.vm
===================================================================
--- src/main/resources/templates/Table.vm (revision 0)
+++ src/main/resources/templates/Table.vm (revision 0)
@@ -0,0 +1,40 @@
+package $tablePackageName;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.DBTableColumn;
+
+import $basePackageName.${dbClassName};
+
+public class ${table.className} extends ${baseTableClassName} {
+ // Primary key column
+ private List<DBTableColumn> keyColumns= new ArrayList<DBTableColumn>();
+
+ // Regular attributes
+#foreach ($col in $table.columns)
+ public final DBTableColumn C_${col.name};
+#end
+
+ public ${table.className}(${dbClassName} db) {
+ super("${table.tableName}", db);
+
+ // all columns
+#foreach ($col in $table.columns)
+ C_${col.name} = super.addColumn("${col.name}",
DataType.${col.empireType}, ${col.colSize}, ${col.required},
${col.defaultValue});
+#end
+
+
+ // configure primary columns
+#foreach ($col in $table.columns)
+#if($col.primaryColumn == true)
+ keyColumns.add(C_${col.name});
+#end
+#end
+ super.setPrimaryKey((DBTableColumn[]) keyColumns.toArray());
+
+ // Set cascade delete
+ super.setCascadeDelete(true);
+ }
+}
Index: src/main/resources/templates/BaseRecord.vm
===================================================================
--- src/main/resources/templates/BaseRecord.vm (revision 0)
+++ src/main/resources/templates/BaseRecord.vm (revision 0)
@@ -0,0 +1,20 @@
+package ${recordPackageName};
+
+import org.apache.empire.db.DBRecord;
+import ${tablePackageName}.${baseTableClassName};
+
+
+public abstract class ${baseRecordClassName}<T extends ${baseTableClassName}>
extends DBRecord {
+ public ${baseRecordClassName}(T table) {
+ super.init(table, DBRecord.REC_EMTPY, null);
+ }
+
+ /**
+ * Returns the table this record is based upon.
+ * @return The table this record is based upon.
+ */
+ @SuppressWarnings("unchecked")
+ public T getDbTable() {
+ return (T)super.getRowSet();
+ }
+}
\ No newline at end of file
Index: src/main/resources/templates/Record.vm
===================================================================
--- src/main/resources/templates/Record.vm (revision 0)
+++ src/main/resources/templates/Record.vm (revision 0)
@@ -0,0 +1,27 @@
+package ${recordPackageName};
+
+#if ($table.hasBigDecimalField())
+import java.math.BigDecimal;
+#end
+
+import ${basePackageName}.${dbClassName};
+import ${recordPackageName}.${baseRecordClassName};
+import ${tablePackageName}.${table.className};
+
+/**
+ * Auto-generated class that represents one record (or row) of data from a
+ * database table. One of these is generated for each table or view in the
+ * database. The interface defines getters for auto-generated data (e.g.
+ * primary key, time stamp field for optimistic locking). It generates both
+ * getter and setter method for all other columns in the table, with the
+ * exception of foreign key references.
+ *
+ * This class provides protected method that subclasses should use to provide
+ * access to related records.
+ */
+public class ${table.recordClassName} extends
${baseRecordClassName}<${table.className}> {
+ public ${table.recordClassName}() {
+ super(${dbClassName}.get().T_${table.tableName});
+ }
+
+}
\ No newline at end of file
Index: config.xml
===================================================================
--- config.xml (revision 826810)
+++ config.xml (working copy)
@@ -23,17 +23,19 @@
<properties>
<!-- provider name must match the property-section containing
the connection data -->
- <jdbcClass>oracle.jdbc.driver.OracleDriver</jdbcClass>
- <jdbcURL>jdbc:oracle:thin:@192.168.0.2:1521:ora10</jdbcURL>
- <jdbcUser>DBSAMPLE</jdbcUser>
- <jdbcPwd>DBSAMPLE</jdbcPwd>
+ <jdbcClass>org.hsqldb.jdbcDriver</jdbcClass>
+
<jdbcURL>jdbc:hsqldb:C:\Users\Hermine7\Desktop\J2HTK4CodeGen\J2HTKDatabase;shutdown=true</jdbcURL>
+ <jdbcUser>sa</jdbcUser>
+ <jdbcPwd></jdbcPwd>
+ <outputFolder>./src/gen/</outputFolder>
+
<!-- generation options -->
<packageName>org.foo.db</packageName>
<dbClassName>MyDB</dbClassName>
- <tableBaseName>MyTable</tableBaseName>
+ <tableBaseName>MyBaseTable</tableBaseName>
<viewBaseName>MyView</viewBaseName>
- <recordBaseName>MyRecord</recordBaseName>
+ <recordBaseName>MyBaseRecord</recordBaseName>
<tableClassPrefix>T</tableClassPrefix>
<viewClassPrefix>V</viewClassPrefix>
<nestTables>True</nestTables>
Index: src/main/resources/templates/BaseTable.vm
===================================================================
--- src/main/resources/templates/BaseTable.vm (revision 0)
+++ src/main/resources/templates/BaseTable.vm (revision 0)
@@ -0,0 +1,10 @@
+package $tablePackageName;
+
+import org.apache.empire.db.DBDatabase;
+import org.apache.empire.db.DBTable;
+
+public class ${baseTableClassName} extends DBTable {
+ public ${baseTableClassName}(String name, DBDatabase db) {
+ super(name, db);
+ }
+}
Index: src/main/java/org/apache/empire/db/codegen/util/DBUtil.java
===================================================================
--- src/main/java/org/apache/empire/db/codegen/util/DBUtil.java (revision 0)
+++ src/main/java/org/apache/empire/db/codegen/util/DBUtil.java (revision 0)
@@ -0,0 +1,20 @@
+package org.apache.empire.db.codegen.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.apache.commons.logging.Log;
+
+public class DBUtil {
+ public static boolean closeResultSet(ResultSet rs, Log log) {
+ boolean b = false;
+ try {
+ if(rs!=null)
+ rs.close();
+ b = true;
+ } catch (SQLException e) {
+ log.error("The resultset could not bel closed!", e);
+ }
+ return b;
+ }
+}
Index: src/main/java/org/apache/empire/db/codegen/CodeGenConfig.java
===================================================================
--- src/main/java/org/apache/empire/db/codegen/CodeGenConfig.java
(revision 826810)
+++ src/main/java/org/apache/empire/db/codegen/CodeGenConfig.java
(working copy)
@@ -20,240 +20,232 @@
import org.apache.empire.xml.XMLConfiguration;
-public class CodeGenConfig extends XMLConfiguration
-{
- private String jdbcClass = "org.hsqldb.jdbcDriver";
+public class CodeGenConfig extends XMLConfiguration {
- private String jdbcURL = "jdbc:hsqldb:file:hsqldb/sample;shutdown=true";
+ private String jdbcClass = "org.hsqldb.jdbcDriver";
- private String jdbcUser = "sa";
+ private String jdbcURL = "jdbc:hsqldb:file:hsqldb/sample;shutdown=true";
- private String jdbcPwd = "";
-
- // generation options
- /**
- * name of the target package
- */
- private String packageName = "org.foo.db";
-
- /**
- * Target name of the generated database class.
- * This class extends DBDatabase.
- */
- private String dbClassName = "MyDB";
- /**
- * Target name of the generated table class.
- * This class extends DBTable and is the base class for all generated
individual table classes.
- */
- private String tableBaseName = "MyTable";
- /**
- * Target name of the generated view class.
- * This class extends DBView and is the base class for all generated
individual view classes.
- */
- private String viewBaseName = "MyView";
- /**
- * Target name of the generated record class.
- * This is a template class that extends DBRecord as follows:<br/>
- * <pre>XXRecord<T extends XXTable> extends DBRecord</pre><br/>
- */
- private String recordBaseName = "MyRecord";
- /**
- * Prefix used for generating table class names.<br/>
- * The Table name is appended after the prefix starting with captial
letter followed by lower case letters.<br/>
- * Occurrence an of underscore indicates a new word which will again start
with a capital letter.<br/>
- * e.g.<br/>
- * <ul>
- * <li>Table "names" -> Class "XXNames"</li>
- * <li>Table "flight_bookings" -> Class "XXFlightBookings"</li>
- * </ul>
- * Where XX is the prefix.
- */
- private String tableClassPrefix = "T";
- /**
- * Prefix used for generating view class names.<br/>
- * The Table name is appended after the prefix starting with captial
letter followed by lower case letters.<br/>
- * Occurrence an of underscore indicates a new word which will again start
with a capital letter.<br/>
- * See naming of table classes above.
- */
- private String viewClassPrefix = "V";
-
- /**
- * if TRUE table classes should be declared as inner classes of
DBDatabase.<br/>
- * if FALSE table classes should be declared as top level classes.
- */
- private boolean nestTables;
- /**
- * if TRUE view classes should be declared as inner classes of
DBDatabase.<br/>
- * if FALSE view classes should be declared as top level classes.
- */
- private boolean nestViews;
- /**
- * if TRUE record classes should have a getter and setter for each
field.<br/>
- * Otherwiese getters / setters are omitted.
- */
- private boolean createRecordProperties;
-
+ private String jdbcUser = "sa";
- /**
- * Initialize the configuration.
- *
- * @param filename the file to read
- *
- * @return true on succes
- */
- public boolean init(String filename)
- {
- // Read the properties file
- if (super.init(filename, false, true) == false)
- return false;
- // Done
- if (readProperties(this, "properties")==false)
- return false;
- // Reader Provider Properties
- return true;
- }
-
- public String getJdbcClass()
- {
- return jdbcClass;
- }
+ private String jdbcPwd = "";
- public void setJdbcClass(String jdbcClass)
- {
- this.jdbcClass = jdbcClass;
- }
+ /**
+ * the folder where the generated classes shall be created
+ */
+ private String outputFolder = "./src/gen/";
- public String getJdbcURL()
- {
- return jdbcURL;
- }
+ // generation options
+ /**
+ * name of the target package
+ */
+ private String packageName = "org.foo.db";
- public void setJdbcURL(String jdbcURL)
- {
- this.jdbcURL = jdbcURL;
- }
+ /**
+ * Target name of the generated database class. This class extends
+ * DBDatabase.
+ */
+ private String dbClassName = "MyDB";
+ /**
+ * Target name of the generated table class. This class extends DBTable
and
+ * is the base class for all generated individual table classes.
+ */
+ private String tableBaseName = "MyTable";
+ /**
+ * Target name of the generated view class. This class extends DBView
and is
+ * the base class for all generated individual view classes.
+ */
+ private String viewBaseName = "MyView";
+ /**
+ * Target name of the generated record class. This is a template class
that
+ * extends DBRecord as follows:<br/>
+ *
+ * <pre>
+ * XXRecord<T extends XXTable> extends DBRecord
+ * </pre>
+ *
+ * <br/>
+ */
+ private String recordBaseName = "MyRecord";
+ /**
+ * Prefix used for generating table class names.<br/>
+ * The Table name is appended after the prefix starting with captial
letter
+ * followed by lower case letters.<br/>
+ * Occurrence of an underscore indicates a new word which will again
start
+ * with a capital letter.<br/>
+ * e.g.<br/>
+ * <ul>
+ * <li>Table "names" -> Class "XXNames"</li>
+ * <li>Table "flight_bookings" -> Class "XXFlightBookings"</li>
+ * </ul>
+ * Where XX is the prefix.
+ */
+ private String tableClassPrefix = "T";
+ /**
+ * Prefix used for generating view class names.<br/>
+ * The Table name is appended after the prefix starting with captial
letter
+ * followed by lower case letters.<br/>
+ * Occurrence of an underscore indicates a new word which will again
start
+ * with a capital letter.<br/>
+ * See naming of table classes above.
+ */
+ private String viewClassPrefix = "V";
- public String getJdbcUser()
- {
- return jdbcUser;
- }
+ /**
+ * if TRUE table classes should be declared as inner classes of
DBDatabase.<br/>
+ * if FALSE table classes should be declared as top level classes.
+ */
+ private boolean nestTables;
+ /**
+ * if TRUE view classes should be declared as inner classes of
DBDatabase.<br/>
+ * if FALSE view classes should be declared as top level classes.
+ */
+ private boolean nestViews;
+ /**
+ * if TRUE record classes should have a getter and setter for each
field.<br/>
+ * Otherwiese getters / setters are omitted.
+ */
+ private boolean createRecordProperties;
- public void setJdbcUser(String jdbcUser)
- {
- this.jdbcUser = jdbcUser;
- }
+ /**
+ * Initialize the configuration.
+ *
+ * @param filename
+ * the file to read
+ *
+ * @return true on succes
+ */
+ public boolean init(String filename) {
+ // Read the properties file
+ if (super.init(filename, false, true) == false)
+ return false;
+ // Done
+ if (readProperties(this, "properties") == false)
+ return false;
+ // Reader Provider Properties
+ return true;
+ }
- public String getJdbcPwd()
- {
- return jdbcPwd;
- }
+ public String getJdbcClass() {
+ return jdbcClass;
+ }
- public void setJdbcPwd(String jdbcPwd)
- {
- this.jdbcPwd = jdbcPwd;
- }
-
- // ------- generation options -------
-
- public String getPackageName()
- {
- return packageName;
- }
+ public void setJdbcClass(String jdbcClass) {
+ this.jdbcClass = jdbcClass;
+ }
- public void setPackageName(String packageName)
- {
- this.packageName = packageName;
- }
+ public String getJdbcURL() {
+ return jdbcURL;
+ }
- public String getDbClassName()
- {
- return dbClassName;
- }
+ public void setJdbcURL(String jdbcURL) {
+ this.jdbcURL = jdbcURL;
+ }
- public void setDbClassName(String dbClassName)
- {
- this.dbClassName = dbClassName;
- }
+ public String getJdbcUser() {
+ return jdbcUser;
+ }
- public String getTableBaseName()
- {
- return tableBaseName;
- }
+ public void setJdbcUser(String jdbcUser) {
+ this.jdbcUser = jdbcUser;
+ }
- public void setTableBaseName(String tableBaseName)
- {
- this.tableBaseName = tableBaseName;
- }
+ public String getJdbcPwd() {
+ return jdbcPwd;
+ }
- public String getViewBaseName()
- {
- return viewBaseName;
- }
+ public void setJdbcPwd(String jdbcPwd) {
+ this.jdbcPwd = jdbcPwd;
+ }
- public void setViewBaseName(String viewBaseName)
- {
- this.viewBaseName = viewBaseName;
- }
+ public String getOutputFolder() {
+ return outputFolder;
+ }
- public String getRecordBaseName()
- {
- return recordBaseName;
- }
+ public void setOutputFolder(String outputFolder) {
+ this.outputFolder = outputFolder;
+ }
- public void setRecordBaseName(String recordBaseName)
- {
- this.recordBaseName = recordBaseName;
- }
+ // ------- generation options -------
- public String getTableClassPrefix()
- {
- return tableClassPrefix;
- }
+ public String getPackageName() {
+ return packageName;
+ }
- public void setTableClassPrefix(String tableClassPrefix)
- {
- this.tableClassPrefix = tableClassPrefix;
- }
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
- public String getViewClassPrefix()
- {
- return viewClassPrefix;
- }
+ public String getDbClassName() {
+ return dbClassName;
+ }
- public void setViewClassPrefix(String viewClassPrefix)
- {
- this.viewClassPrefix = viewClassPrefix;
- }
+ public void setDbClassName(String dbClassName) {
+ this.dbClassName = dbClassName;
+ }
- public boolean isNestTables()
- {
- return nestTables;
- }
+ public String getTableBaseName() {
+ return tableBaseName;
+ }
- public void setNestTables(boolean nestTables)
- {
- this.nestTables = nestTables;
- }
+ public void setTableBaseName(String tableBaseName) {
+ this.tableBaseName = tableBaseName;
+ }
- public boolean isNestViews()
- {
- return nestViews;
- }
+ public String getViewBaseName() {
+ return viewBaseName;
+ }
- public void setNestViews(boolean nestViews)
- {
- this.nestViews = nestViews;
- }
+ public void setViewBaseName(String viewBaseName) {
+ this.viewBaseName = viewBaseName;
+ }
- public boolean isCreateRecordProperties()
- {
- return createRecordProperties;
- }
+ public String getRecordBaseName() {
+ return recordBaseName;
+ }
- public void setCreateRecordProperties(boolean createRecordProperties)
- {
- this.createRecordProperties = createRecordProperties;
- }
-
-
+ public void setRecordBaseName(String recordBaseName) {
+ this.recordBaseName = recordBaseName;
+ }
+
+ public String getTableClassPrefix() {
+ return tableClassPrefix;
+ }
+
+ public void setTableClassPrefix(String tableClassPrefix) {
+ this.tableClassPrefix = tableClassPrefix;
+ }
+
+ public String getViewClassPrefix() {
+ return viewClassPrefix;
+ }
+
+ public void setViewClassPrefix(String viewClassPrefix) {
+ this.viewClassPrefix = viewClassPrefix;
+ }
+
+ public boolean isNestTables() {
+ return nestTables;
+ }
+
+ public void setNestTables(boolean nestTables) {
+ this.nestTables = nestTables;
+ }
+
+ public boolean isNestViews() {
+ return nestViews;
+ }
+
+ public void setNestViews(boolean nestViews) {
+ this.nestViews = nestViews;
+ }
+
+ public boolean isCreateRecordProperties() {
+ return createRecordProperties;
+ }
+
+ public void setCreateRecordProperties(boolean createRecordProperties) {
+ this.createRecordProperties = createRecordProperties;
+ }
+
}
Index: src/main/java/org/apache/empire/db/codegen/mapper/Column.java
===================================================================
--- src/main/java/org/apache/empire/db/codegen/mapper/Column.java
(revision 0)
+++ src/main/java/org/apache/empire/db/codegen/mapper/Column.java
(revision 0)
@@ -0,0 +1,257 @@
+package org.apache.empire.db.codegen.mapper;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.codegen.util.StringUtils;
+
+public class Column {
+ private String name;
+ private int sqlType;
+ private int colSize; // max length if string, precision is numeric
+ private int decimalDigits; // max decimal digits allowed (real numbers)
+ private boolean required;
+ private String defaultValue;
+ private boolean pkCol;
+
+ // Java transformation
+ private String javaName;
+ private DataType empireType;
+ private String empireTypeString;
+ private String originalJavaTypeString;
+ private String javaTypeString;
+
+ private boolean convertToBoolean;
+ private String trueValue;
+ private String falseValue;
+
+ private boolean convertToEnum;
+
+ public String getJavaName() {
+ return javaName;
+ }
+
+ public void setJavaName(String javaName) {
+ this.javaName = javaName;
+ }
+
+ public String getJavaTypeString() {
+ return javaTypeString;
+ }
+
+ public String getEmpireTypeString() {
+ return empireTypeString;
+ }
+
+ public DataType getEmpireType() {
+ return empireType;
+ }
+
+ public Column(ResultSet rs) {
+ this(rs, false);
+ }
+
+ public Column(ResultSet rs, boolean primaryKey) {
+
+ this.pkCol = primaryKey;
+ try {
+ this.name = rs.getString("COLUMN_NAME").toUpperCase();
+ this.sqlType = rs.getInt("DATA_TYPE");
+ this.empireType = this.deriveJavaInfo();
+ this.colSize = rs.getInt("COLUMN_SIZE");
+ this.decimalDigits = rs.getInt("DECIMAL_DIGITS");
+ String nullable = rs.getString("IS_NULLABLE");
+ if (nullable.equalsIgnoreCase("NO"))
+ this.required = true;
+ else
+ this.required = false;
+ this.defaultValue = rs.getString("COLUMN_DEF");
+
+ this.originalJavaTypeString = this.javaTypeString;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Column) {
+ Column that = (Column) obj;
+ if (this.name.equals(that.name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String getName() {
+ return name.toUpperCase();
+ }
+
+ public int getSqlType() {
+ return sqlType;
+ }
+
+ public int getColSize() {
+ return colSize;
+ }
+
+ public int getDecimalDigits() {
+ return decimalDigits;
+ }
+
+ public boolean isRequired() {
+ return required;
+ }
+
+ public String getDefaultValue() {
+ if (defaultValue == null)
+ return "null";
+
+ return "\"" + defaultValue + "\"";
+ }
+
+ public boolean isPrimaryColumn() {
+ return this.pkCol;
+ }
+
+ public boolean isBoolean() {
+ if (this.javaTypeString.equalsIgnoreCase("Boolean"))
+ return true;
+ return false;
+ }
+
+ private DataType deriveJavaInfo() {
+ this.javaName = StringUtils.deriveAttributeName(this.name);
+ DataType empireType = DataType.UNKNOWN;
+ switch (this.sqlType) {
+ case Types.INTEGER:
+ case Types.SMALLINT:
+ case Types.TINYINT:
+ case Types.BIGINT:
+ empireType = DataType.INTEGER;
+ empireTypeString = "DataType.INTEGER";
+ javaTypeString = "Long";
+ break;
+ case Types.VARCHAR:
+ empireType = DataType.TEXT;
+ empireTypeString = "DataType.TEXT";
+ javaTypeString = "String";
+ break;
+ case Types.DATE:
+ empireType = DataType.DATE;
+ empireTypeString = "DataType.DATE";
+ javaTypeString = "Date";
+ break;
+ case Types.TIMESTAMP:
+ case Types.TIME:
+ empireType = DataType.DATETIME;
+ empireTypeString = "DataType.DATETIME";
+ javaTypeString = "Date";
+ break;
+ case Types.CHAR:
+ empireType = DataType.CHAR;
+ empireTypeString = "DataType.CHAR";
+ javaTypeString = "String";
+ break;
+ case Types.DOUBLE:
+ case Types.FLOAT:
+ case Types.REAL:
+ empireType = DataType.DOUBLE;
+ empireTypeString = "DataType.DOUBLE";
+ javaTypeString = "Double";
+ break;
+ case Types.DECIMAL:
+ case Types.NUMERIC:
+ empireType = DataType.DECIMAL;
+ empireTypeString = "DataType.DECIMAL";
+ javaTypeString = "BigDecimal";
+ break;
+ case Types.BIT:
+ case Types.BOOLEAN:
+ empireType = DataType.BOOL;
+ empireTypeString = "DataType.BOOL";
+ javaTypeString = "Boolean";
+ break;
+ case Types.CLOB:
+ case Types.LONGVARCHAR:
+ empireType = DataType.CLOB;
+ empireTypeString = "DataType.CLOB";
+ javaTypeString = "String";
+ break;
+ case Types.BINARY:
+ case Types.VARBINARY:
+ case Types.LONGVARBINARY:
+ case Types.BLOB:
+ empireType = DataType.BLOB;
+ empireTypeString = "DataType.BLOB";
+ javaTypeString = "Byte[]";
+ break;
+ default:
+ empireType = DataType.UNKNOWN;
+ empireTypeString = "DataType.UNKNOWN";
+ javaTypeString = "Byte[]";
+ System.out.println("SQL column type " + this.sqlType
+ + " not supported.");
+ }
+
+ return empireType;
+ }
+
+ public boolean isConvertToBoolean() {
+ return convertToBoolean;
+ }
+
+ public String getTrueValue() {
+ return trueValue;
+ }
+
+ public String getFalseValue() {
+ return falseValue;
+ }
+
+ public String getOriginalJavaTypeString() {
+ return originalJavaTypeString;
+ }
+
+ public boolean isConvertToEnum() {
+ return convertToEnum;
+ }
+
+ public String getJavaAccessorName() {
+ return StringUtils.deriveAccessorName(javaName,
this.javaTypeString
+ .equalsIgnoreCase("boolean"));
+ }
+
+ public String getJavaMutatorName() {
+ return StringUtils.deriveMutatorName(javaName);
+ }
+
+ public String getReturnExpression() {
+ if (this.convertToBoolean) {
+ StringBuilder sb = new StringBuilder(this.javaName);
+ sb.append(".equalsIgnoreCase(\"");
+ sb.append(this.trueValue).append("\")");
+ return sb.toString();
+ } else if (this.convertToEnum) {
+ return this.javaTypeString + ".fromDbString(" +
this.javaName + ")";
+ } else {
+ return this.javaName;
+ }
+ }
+
+ public String getSetExpression() {
+ if (this.convertToBoolean) {
+ StringBuilder sb = new StringBuilder(this.javaName);
+ sb.append(" ? \"").append(this.trueValue).append("\" ");
+ sb.append(" :
\"").append(this.falseValue).append("\")");
+ return sb.toString();
+ } else if (this.convertToEnum) {
+ return this.javaName + ".toDbString()";
+ } else {
+ return this.javaName;
+ }
+ }
+}
Index: src/main/java/org/apache/empire/db/codegen/CodeGen.java
===================================================================
--- src/main/java/org/apache/empire/db/codegen/CodeGen.java (revision
826810)
+++ src/main/java/org/apache/empire/db/codegen/CodeGen.java (working copy)
@@ -18,119 +18,252 @@
*/
package org.apache.empire.db.codegen;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
import java.sql.Connection;
-import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
-import java.sql.ResultSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.empire.commons.ErrorObject;
+import org.apache.empire.db.codegen.mapper.Database;
+import org.apache.empire.db.codegen.mapper.Table;
+import org.apache.empire.db.codegen.util.FileUtils;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
-public class CodeGen
-{
- private static final Log log = LogFactory.getLog(CodeGen.class);
+public class CodeGen {
+ // the templates used for the code generation
+ private static final String DATABASE_TEMPLATE =
"./src/main/resources/templates/Database.vm";
+ private static final String BASE_TABLE_TEMPLATE =
"./src/main/resources/templates/BaseTable.vm";
+ private static final String TABLE_TEMPLATE =
"./src/main/resources/templates/Table.vm";
+ private static final String BASE_RECORD_TEMPLATE =
"./src/main/resources/templates/BaseRecord.vm";
+ private static final String RECORD_TEMPLATE =
"./src/main/resources/templates/Record.vm";
- private static CodeGenConfig config = new CodeGenConfig();
+ private static final Log log = LogFactory.getLog(CodeGen.class);
- /**
- * <PRE>
- * This is the entry point of the Empire-DB Sample Application
- * Please check the config.xml configuration file for Database and
Connection settings.
- * </PRE>
- * @param args arguments
- */
- public static void main(String[] args)
- {
- Connection conn = null;
- try
- {
- // Init Configuration
- config.init((args.length > 0 ? args[0] : "config.xml" ));
+ private static CodeGenConfig config = new CodeGenConfig();
- // Enable Exceptions
- ErrorObject.setExceptionsEnabled(true);
+ private static File baseDir, tableDir, recordDir;
- // Get a JDBC Connection
- conn = getJDBCConnection();
-
- // List options
- log.info("Database connection successful. Config options are:");
- log.info("PackageName="+config.getPackageName());
- log.info("DbClassName="+config.getDbClassName());
- log.info("TableBaseName="+config.getTableBaseName());
- log.info("ViewBaseName="+config.getViewBaseName());
- log.info("RecordBaseName="+config.getRecordBaseName());
- log.info("TableClassPrefix="+config.getTableClassPrefix());
- log.info("ViewClassPrefi="+config.getViewClassPrefix());
- log.info("NestTable="+config.isNestTables());
- log.info("NestViews="+config.isNestViews());
-
log.info("CreateRecordPropertie="+config.isCreateRecordProperties());
-
- // Get Metadata
- DatabaseMetaData dmd = conn.getMetaData();
-
- // Process Metadata
- // ....
- ResultSet rs = dmd.getCatalogs();
- while (rs.next()) {
- System.out.println(rs.getString(1));
- }
- rs.close();
-
- } catch(Exception e) {
- // Error
- System.out.println(e.toString());
- e.printStackTrace();
- } finally {
- // done
- if (conn!=null)
- close(conn);
- }
- }
-
- /**
- * <PRE>
- * Opens and returns a JDBC-Connection.
- * JDBC url, user and password for the connection are obained from the
SampleConfig bean
- * Please use the config.xml file to change connection params.
- * </PRE>
- */
- private static Connection getJDBCConnection()
- {
- // Establish a new database connection
- Connection conn = null;
- log.info("Connecting to Database'" + config.getJdbcURL() + "' / User="
+ config.getJdbcUser());
- try
- {
- // Connect to the databse
- Class.forName(config.getJdbcClass()).newInstance();
- conn = DriverManager.getConnection(config.getJdbcURL(),
config.getJdbcUser(), config.getJdbcPwd());
- log.info("Connected successfully");
- // set the AutoCommit to false this session. You must commit
- // explicitly now
- conn.setAutoCommit(true);
- log.info("AutoCommit is " + conn.getAutoCommit());
+ /**
+ * <PRE>
+ * This is the entry point of the Empire-DB Sample Application
+ * Please check the config.xml configuration file for Database and
Connection settings.
+ * </PRE>
+ *
+ * @param args
+ * arguments
+ */
+ public static void main(String[] args) {
+ Connection conn = null;
+ try {
+ // Init Configuration
+ config.init((args.length > 0 ? args[0] : "config.xml"));
- } catch (Exception e)
- {
- log.fatal("Failed to connect directly to '" + config.getJdbcURL()
+ "' / User=" + config.getJdbcUser(), e);
- throw new RuntimeException(e);
- }
- return conn;
- }
-
- /**
- * Closes a JDBC-Connection.
- */
- private static void close(Connection conn)
- {
- log.info("Closing database connection");
- try {
- conn.close();
- } catch (Exception e) {
- log.fatal("Error closing connection", e);
- }
- }
-
+ // Enable Exceptions
+ ErrorObject.setExceptionsEnabled(true);
+
+ // Get a JDBC Connection
+ conn = getJDBCConnection();
+
+ // List options
+ log.info("Database connection successful. Config
options are:");
+ log.info("OutputFolder=" + config.getOutputFolder());
+ log.info("PackageName=" + config.getPackageName());
+ log.info("DbClassName=" + config.getDbClassName());
+ log.info("TableBaseName=" + config.getTableBaseName());
+ log.info("ViewBaseName=" + config.getViewBaseName());
+ log.info("RecordBaseName=" +
config.getRecordBaseName());
+ log.info("TableClassPrefix=" +
config.getTableClassPrefix());
+ log.info("ViewClassPrefi=" +
config.getViewClassPrefix());
+ log.info("NestTable=" + config.isNestTables());
+ log.info("NestViews=" + config.isNestViews());
+ log.info("CreateRecordPropertie="
+ + config.isCreateRecordProperties());
+
+ // TODO 01: (Benjamin V.): the parameter for the
catalog,
+ // schemaPattern
+ // and tablePattern should be configurable via the
config.xml
+ generateCode(new Database(conn, log, null, null, null));
+
+ } catch (Exception e) {
+ // Error
+ System.out.println(e.toString());
+ e.printStackTrace();
+ } finally {
+ // done
+ if (conn != null)
+ close(conn);
+ }
+ }
+
+ /**
+ * <PRE>
+ * Opens and returns a JDBC-Connection.
+ * JDBC url, user and password for the connection are obained from the
SampleConfig bean
+ * Please use the config.xml file to change connection params.
+ * </PRE>
+ */
+ private static Connection getJDBCConnection() {
+ // Establish a new database connection
+ Connection conn = null;
+ log.info("Connecting to Database'" + config.getJdbcURL() + "' /
User="
+ + config.getJdbcUser());
+ try {
+ // Connect to the databse
+ Class.forName(config.getJdbcClass()).newInstance();
+ conn = DriverManager.getConnection(config.getJdbcURL(),
config
+ .getJdbcUser(), config.getJdbcPwd());
+ log.info("Connected successfully");
+ // set the AutoCommit to false this session. You must
commit
+ // explicitly now
+ conn.setAutoCommit(false);
+ log.info("AutoCommit is " + conn.getAutoCommit());
+
+ } catch (Exception e) {
+ log.fatal("Failed to connect directly to '" +
config.getJdbcURL()
+ + "' / User=" + config.getJdbcUser(),
e);
+ throw new RuntimeException(e);
+ }
+ return conn;
+ }
+
+ /**
+ * Closes a JDBC-Connection.
+ */
+ private static void close(Connection conn) {
+ log.info("Closing database connection");
+ try {
+ conn.close();
+ } catch (Exception e) {
+ log.fatal("Error closing connection", e);
+ }
+ }
+
+ /**
+ * Generates the source code for the persistence layer.
+ */
+ public static void generateCode(Database db) {
+ // Prepare directories for generated source files
+ initDirectories();
+
+ // Create the DB class
+ createDatabaseClass(db);
+
+ // Create base table class
+ createBaseTableClass(db);
+
+ // Create base record class
+ createBaseRecordClass(db);
+
+ // Create table classes, record interfaces and record classes
+ for (Table table : db.getTables()) {
+ createTableClass(db, table);
+ createRecordClass(db, table);
+ }
+ }
+
+ private static void initDirectories() {
+ // Create the directory structure for the generated source code.
+ baseDir = new File(config.getOutputFolder());
+ if (!baseDir.exists()) {
+ baseDir.mkdirs();
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(config.getOutputFolder()).append("/");
+ sb.append(config.getPackageName().replaceAll("\\.", "/"));
+ baseDir = new File(sb.toString());
+ if (!baseDir.exists()) {
+ baseDir.mkdirs();
+ }
+
+ // Clean out the directory so old code is wiped out.
+ FileUtils.cleanDirectory(baseDir);
+
+ // Create the table package directory
+ tableDir = new File(baseDir, "tables");
+ tableDir.mkdir();
+
+ // Create the record package directory
+ recordDir = new File(baseDir, "records");
+ recordDir.mkdir();
+ }
+
+ private static void createDatabaseClass(Database db) {
+ File file = new File(baseDir, config.getDbClassName() +
".java");
+ VelocityContext context = new VelocityContext();
+ context.put("basePackageName", config.getPackageName());
+ context.put("dbClassName", config.getDbClassName());
+ context.put("tableSubPackage", "tables");
+ context.put("database", db);
+ writeFile(file, DATABASE_TEMPLATE, context);
+ }
+
+ private static void createBaseTableClass(Database db) {
+ File file = new File(tableDir, config.getTableBaseName() +
".java");
+ VelocityContext context = new VelocityContext();
+ context.put("tablePackageName", config.getPackageName() +
".tables");
+ context.put("baseTableClassName", config.getTableBaseName());
+ writeFile(file, BASE_TABLE_TEMPLATE, context);
+ }
+
+ private static void createTableClass(Database db, Table table) {
+ File file = new File(tableDir, table.getClassName() + ".java");
+ VelocityContext context = new VelocityContext();
+ context.put("basePackageName", config.getPackageName());
+ context.put("tablePackageName", config.getPackageName() +
".tables");
+ context.put("baseTableClassName", config.getTableBaseName());
+ context.put("dbClassName", config.getDbClassName());
+ context.put("table", table);
+ writeFile(file, TABLE_TEMPLATE, context);
+ }
+
+ private static void createBaseRecordClass(Database db) {
+ File file = new File(recordDir, config.getRecordBaseName() +
".java");
+ VelocityContext context = new VelocityContext();
+ context.put("baseRecordClassName", config.getRecordBaseName());
+ context.put("basePackageName", config.getPackageName());
+ context.put("tablePackageName", config.getPackageName() +
".tables");
+ context.put("recordPackageName", config.getPackageName() +
".records");
+ context.put("baseTableClassName", config.getTableBaseName());
+ writeFile(file, BASE_RECORD_TEMPLATE, context);
+ }
+
+ private static void createRecordClass(Database db, Table table) {
+ File file = new File(recordDir, table.getRecordClassName() +
".java");
+ VelocityContext context = new VelocityContext();
+ context.put("basePackageName", config.getPackageName());
+ context.put("tablePackageName", config.getPackageName() +
".tables");
+ context.put("recordPackageName", config.getPackageName() +
".records");
+ context.put("baseRecordClassName", config.getRecordBaseName());
+ context.put("dbClassName", config.getDbClassName());
+ context.put("table", table);
+ writeFile(file, RECORD_TEMPLATE, context);
+ }
+
+ private static void writeFile(File file, String templatePath,
+ VelocityContext context) {
+ try {
+ Template template = Velocity.getTemplate(templatePath);
+ Writer writer = new FileWriter(file);
+ template.merge(context, writer);
+ writer.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (ResourceNotFoundException e) {
+ e.printStackTrace();
+ } catch (ParseErrorException e) {
+ e.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
}
Index: src/main/java/org/apache/empire/db/codegen/mapper/Database.java
===================================================================
--- src/main/java/org/apache/empire/db/codegen/mapper/Database.java
(revision 0)
+++ src/main/java/org/apache/empire/db/codegen/mapper/Database.java
(revision 0)
@@ -0,0 +1,73 @@
+package org.apache.empire.db.codegen.mapper;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.empire.db.codegen.util.DBUtil;
+
+public class Database {
+ private DatabaseMetaData metaData;
+ private String catalogName;
+ private String schemaPattern;
+ private String tablePattern;
+ private Connection con;
+ private Log log;
+
+ private Map<String, Table> tableMap = new HashMap<String, Table>();
+
+ public Database(Connection con, Log log, String schemaPattern,
+ String catalogName, String tablePattern) {
+
+ this.log = log;
+ this.con = con;
+ this.schemaPattern = schemaPattern;
+ this.catalogName = catalogName;
+ this.tablePattern = tablePattern;
+ try {
+ this.metaData = this.con.getMetaData();
+ } catch (SQLException e) {
+ throw new RuntimeException("Unable to retrieve database
metadata!",
+ e);
+ }
+
+ populateTableMetaData();
+ }
+
+ /**
+ * Populates meta data for tables in the database.
+ *
+ */
+ public void populateTableMetaData() {
+ DatabaseMetaData dbMeta = this.metaData;
+ ResultSet tables = null;
+ try {
+ tables = dbMeta.getTables(catalogName, schemaPattern,
tablePattern,
+ new String[] { "TABLE" });
+ while (tables.next()) {
+ String tableName =
tables.getString("TABLE_NAME");
+ System.out.println("TABLE:\t" + tableName);
+ Table table = new Table(tableName,
schemaPattern, catalogName,
+ dbMeta, log);
+ this.tableMap.put(tableName.toUpperCase(),
table);
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ } finally {
+ DBUtil.closeResultSet(tables, log);
+ }
+ }
+
+ public Collection<Table> getTables() {
+ return tableMap.values();
+ }
+
+ public Table getTable(String name) {
+ return this.tableMap.get(name.toUpperCase());
+ }
+}
Index: src/main/java/org/apache/empire/db/codegen/util/StringUtils.java
===================================================================
--- src/main/java/org/apache/empire/db/codegen/util/StringUtils.java
(revision 0)
+++ src/main/java/org/apache/empire/db/codegen/util/StringUtils.java
(revision 0)
@@ -0,0 +1,86 @@
+package org.apache.empire.db.codegen.util;
+
+public class StringUtils {
+ /**
+ * Derives a java class name from a database table name.
+ * @param tableName
+ * @return
+ */
+ public static String javaClassName(String name) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(Character.toUpperCase(name.charAt(0)));
+ boolean upperCase = false;
+ for (int i=1; i<name.length(); i++) {
+ char c = name.charAt(i);
+ if (c == '_') {
+ upperCase = true;
+ continue;
+ }
+ if (upperCase) sb.append(Character.toUpperCase(c));
+ else sb.append(Character.toLowerCase(c));
+ upperCase = false;
+ }
+ return sb.toString();
+ }
+ /**
+ * Derives a java attribute name from a database column name.
+ * @param colName
+ * @return
+ */
+ public static String deriveAttributeName(String colName) {
+ String name = javaClassName(colName);
+ StringBuilder sb = new StringBuilder();
+ sb.append(Character.toLowerCase(name.charAt(0)));
+ sb.append(name.substring(1));
+ return sb.toString();
+ }
+ /**
+ * Derives an attribute name from the given class name.
+ * @param className
+ * @return
+ */
+ public static String deriveAttributeNameFromClass(String className) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(Character.toLowerCase(className.charAt(0)));
+ sb.append(className.substring(1));
+ return sb.toString();
+ }
+ /**
+ * Derives the accessor method name based on the attribute name.
+ * @param attribute
+ * @param isBoolean
+ * @return
+ */
+ public static String deriveAccessorName(String attribute, boolean
isBoolean) {
+ StringBuilder sb = new StringBuilder();
+ if (isBoolean) sb.append("is");
+ else sb.append("get");
+ sb.append(Character.toUpperCase(attribute.charAt(0)));
+ sb.append(attribute.substring(1));
+ return sb.toString();
+ }
+ /**
+ * Derives the mutator method name based on the attribute name.
+ * @param attribute
+ * @return
+ */
+ public static String deriveMutatorName(String attribute) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("set");
+ sb.append(Character.toUpperCase(attribute.charAt(0)));
+ sb.append(attribute.substring(1));
+ return sb.toString();
+ }
+
+ public static StringBuilder replaceAll(StringBuilder sb,
+ String oldValue, String newValue) {
+ int strIndex = sb.indexOf(oldValue);
+ int endIndex;
+ while (strIndex > -1) {
+ endIndex = strIndex + oldValue.length();
+ sb.replace(strIndex, endIndex, newValue);
+ strIndex = sb.indexOf(oldValue, strIndex);
+ }
+ return sb;
+ }
+}