All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pm.pride.util.generator.EntityGenerator Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2001-2018 The PriDE team
 * All rights reserved. This toolkit and the accompanying materials 
 * are made available under the terms of the GNU Lesser General Public
 * License (LGPL) which accompanies this distribution, and is available
 * at http://pride.sourceforge.net/LGPL.html
 * 
 * Contributors:
 *     Jan Lessner, S&N AG
 *     Matthias Bartels, arvato direct services
 *******************************************************************************/
package pm.pride.util.generator;

/**
 * Generator class to generate entity types from database tables
 *
 * @author Matthias Bartels
 */
import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;

import pm.pride.DatabaseFactory;
import pm.pride.RecordDescriptor;
import pm.pride.ResourceAccessor;
import pm.pride.ResourceAccessor.Config;
import pm.pride.ResourceAccessorJSE;


public class EntityGenerator {

	// Types of generation work products
	public static final String HYBRID = "-h";
	public static final String BEAN = "-b";
	
	protected String className;
	protected String entityClassName;
	protected String baseClassName;
	protected String generationType;
	protected String[] tableNames;
	protected ClassLoader classLoader;
	protected List flatTableColumns;
	protected TableDescription[] tableDesc;
	protected boolean generateAbstractClass;
	protected List flatTableColumnList;
	protected ResourceAccessor resourceAccessor;
	protected String db;

	public void postInit(String[] tableNames, String className,
							   String generationType, String baseClassName)
		throws Exception {
		postInit(tableNames, className, generationType, baseClassName, ClassLoader.getSystemClassLoader());
	}
	
	public void postInit(String[] tableNames, String className,
							   String generationType, String baseClassName, ClassLoader classLoader)
		throws Exception {
		this.generationType = generationType;
		this.tableNames = tableNames;
		this.className = className;
		this.baseClassName = baseClassName;
		this.entityClassName = generateDBA() ? generationType : className;
		this.classLoader = classLoader;
	}

	protected boolean generateBean() {
		return generationType.equals(BEAN);
	}
	
	protected boolean generateHybrid() {
		return generationType.equals(HYBRID);
	}
	
	protected boolean generateDBA() {
		return !generationType.equals(BEAN) && !generationType.equals(HYBRID);
	}
	
	protected void createResourceAccessor() throws Exception {
		if (System.getProperty(Config.DB) == null) {
			throw new IllegalArgumentException("Database URL must be defined by system property " + Config.DB);
		}
		resourceAccessor = ResourceAccessorJSE.fromSystemProps();
	}

	public RecordDescriptor extractRecordDescriptor(String className) throws SQLException {
		try {
			Class c = Class.forName(className);
			Field f = c.getDeclaredField("red");
			f.setAccessible(true);
			return (RecordDescriptor)f.get(null);
		}
		catch(ClassNotFoundException cnfx) {
			throw new SQLException("Base class " + className + " not found.");
		}
		catch(NoSuchFieldException nsfx) {
			throw new SQLException("Base class " + className + " not suitable. Must have a static member of type RecordDescriptor");
		}
		catch(IllegalAccessException iax) {
			throw new SQLException("RecordDescriptor in base class " + className + " not accessible");
		}
	}
	
	/** Retrieve the fields being mapped by a specified class.
	 * Retrieval is performed by reflection, assuming that the
	 * class contains a static {@link RecordDescriptor} field "red"
	 * which the field names can be retrieved from by
	 * {@link RecordDescriptor#getFieldNames}. If you override the
	 * template method {@link #writeRecordDescriptor} to create
	 * record descriptor definitions differently, make sure to also
	 * adapt this function accordingly.
* ATTENTION: This function tries to override standard security restrictions * to access the protected record descriptor member. This may cause * security exceptions. * * @param className The name of the class to retrieve the mapped fields from * @return The mapped fields */ public Set extractMappedFields(String className) throws SQLException { HashSet fields = new HashSet<>(); if (className != null) { RecordDescriptor desc = extractRecordDescriptor(className); String fieldsStr = desc.getFieldNames(null); StringTokenizer tokenizer = new StringTokenizer(fieldsStr, ","); while (tokenizer.hasMoreTokens()) fields.add(tokenizer.nextToken()); } return fields; } /** Retrieve the value type mapped by a specified class. * Retrieval is performed by reflection, assuming that the * class contains a static {@link RecordDescriptor} field "red" * which the value type name can be retrieved from by * {@link RecordDescriptor#getObjectType}. * * @param className The name of the class to retrieve the value type from * @return The name of the value type */ public String extractBeanClass(String className) throws SQLException { RecordDescriptor desc = extractRecordDescriptor(className); return desc.getObjectType().getName(); } /** Creates the entity type by successivly calling the * write... functions */ public String create() throws Exception { createResourceAccessor(); db = DatabaseFactory.getDatabase().getDBName(); Connection con = getDBConnection(); StringBuffer buffer = new StringBuffer(); if (con != null) { tableDesc = getTableDescription(con); flatTableColumnList = flattenTableColumns(tableDesc); writePackage(tableDesc, className, baseClassName, generationType, buffer); writeHeader(tableDesc, className, baseClassName, generationType, buffer); writeConstants(tableDesc, className, baseClassName, generationType, buffer); writeRecordDescriptor(tableDesc, className, baseClassName, generationType, buffer); writePrimaryKey(tableDesc, className, baseClassName, generationType, buffer); writeEntityReference(tableDesc, className, baseClassName, generationType, buffer); writeAttributes(tableDesc, className, baseClassName, generationType, buffer); writeGetMethods(tableDesc, className, baseClassName, generationType, buffer); writeSetMethods(tableDesc, className, baseClassName, generationType, buffer); writeFooter(tableDesc, className, baseClassName, generationType, buffer); con.close(); con = null; } else { buffer.append("Aborting.... due to initialization problem"); } return buffer.toString(); } /** Opens up a database connection according to the * database driver, database name, user, and password specified by system properties */ public Connection getDBConnection() throws Exception { return resourceAccessor.getConnection(db); } /** Generates a table description */ public TableDescription[] getTableDescription(Connection con) throws SQLException { TableDescription[] tableDesc = new TableDescription[tableNames.length]; for (int i = 0; i < tableNames.length; i++) { tableDesc[i] = new TableDescription(con, tableNames[i]); if (tableDesc[i].isPartial() || i > 0) { generateAbstractClass = true; } } return tableDesc; } /** Prints the package name to standard out */ public void writePackage (TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) { buffer.append(getPackage(className) + "\n"); buffer.append("\n"); } /** Prints the author tag to standard out, using the current * database user and database name as an identificatio */ public void writeAuthor (TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) throws Exception { String userName = System.getProperty("user.name"); if (userName != null) buffer.append(" * @author " + userName + "\n"); else buffer.append(" * @author " + resourceAccessor.getUserName(db) + "@" + db + "\n"); } /** Determine the base class for the class to generate. When generating * a hybrid type, the base class is {@link pm.pride.MappedObject}, * for adapters it is {@link pm.pride.ObjectAdapter} and for beans * it is nothing. If a base class is passed, it is takes as is. In case of * bean generation, the base class is assumed to specify the base adapter * class and the baes bean class is extracted by reflection. */ protected String getBaseClassName(String baseClassName, String generationType) throws SQLException { if (baseClassName == null) { if (generateHybrid()) return "MappedObject"; else if (generateDBA()) return "ObjectAdapter"; else return null; } else { if (generateBean()) return extractBeanClass(baseClassName); else return baseClassName; } } /** Prints the class header to standard out */ public void writeHeader (TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) throws Exception { if (!generationType.equals(BEAN)) { buffer.append("import java.sql.SQLException;" + "\n"); buffer.append("import pm.pride.*;" + "\n"); buffer.append("\n"); } buffer.append("/**" + "\n"); writeAuthor(desc, className, baseClassName, generationType, buffer); buffer.append(" */" + "\n"); if (generateAbstractClass) { buffer.append("abstract "); } buffer.append("public "); buffer.append("class " + getSimpleClassName(className) + " "); String actualBaseClassName = getBaseClassName(baseClassName, generationType); if (actualBaseClassName != null) buffer.append("extends " + actualBaseClassName + " "); if (baseClassName == null && !generateDBA()) buffer.append("implements Cloneable, java.io.Serializable "); buffer.append("{\n"); } public String toColumnConstant(TableColumn column) { return "COL_" + column.getNameUpper(); } public void writeConstants (TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) throws SQLException { if (generationType.equals(BEAN)) return; if (!generateAbstractClass) buffer.append(" public static final String TABLE = \"" + getCommaSeparatedTableNames() + "\";\n"); Set baseClassFields = extractMappedFields(baseClassName); for (TableColumn tableColumn: flatTableColumnList) { if (baseClassFields.contains(tableColumn.getName())) continue; buffer.append(" public static final String " + toColumnConstant(tableColumn) + " = \""); String qualifiedColumnName = (desc.length > 1) ? tableColumn.getTableName() + "." + tableColumn.getName() : tableColumn.getName(); buffer.append(qualifiedColumnName + "\";\n"); } buffer.append("\n"); } /** Prints the record descriptor and its access function to standard out */ public void writeRecordDescriptor (TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) throws SQLException { if (generateBean()) return; Set baseClassFields = extractMappedFields(baseClassName); buffer.append(" protected static final RecordDescriptor red = new RecordDescriptor" + "\n"); buffer.append(" ("); buffer.append(getSimpleClassName(generationType.equals(HYBRID) ? className : generationType)); buffer.append(".class, "); buffer.append(generateAbstractClass ? "null, " : "TABLE, "); buffer.append(baseClassName != null ? baseClassName + ".red" : "null"); buffer.append(", new String[][] {" + "\n"); for (TableColumn tableColumn: flatTableColumnList) { if (baseClassFields.remove(tableColumn.getName())) continue; StringBuffer sb = new StringBuffer(); sb.append(" { "); sb.append(toColumnConstant(tableColumn)); sb.append(", \"get"); sb.append(tableColumn.getNameCamelCaseFirstUp()); sb.append("\", \"set"); sb.append(tableColumn.getNameCamelCaseFirstUp()); sb.append("\" },"); buffer.append(sb.toString() + "\n"); } buffer.append(" });" + "\n\n"); buffer.append(" public RecordDescriptor getDescriptor() { return red; }" + "\n"); buffer.append("\n"); } public void writeEntityReference(TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) { if (!generateDBA()) return; buffer.append(" " + getSimpleClassName(className) + "(" + getSimpleClassName(generationType) + " entity) { "); buffer.append("super(entity);"); buffer.append(" }\n\n"); } private boolean hasPrimaryKey(TableDescription tdesc) { for(TableColumn current: tdesc.getColumnList()) { if (current.isPrimaryKeyField()) return true; } return false; } /** Prints the primary key definition and its access function to standard out */ public void writePrimaryKey (TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) { if (generateBean()) return; if (desc.length == 1) { if (hasPrimaryKey(desc[0])) { buffer.append(" private static String[] keyFields = new String[] { "); for(TableColumn current: desc[0].getColumnList()) { if (current.isPrimaryKeyField()) buffer.append( toColumnConstant(current) + ","); } buffer.deleteCharAt(buffer.length()-1); buffer.append(" };" + "\n"); buffer.append(" public String[] getKeyFields() { return keyFields; }" + "\n"); } buffer.append("\n"); } } /** Prints the data members to standard out */ public void writeAttributes (TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) throws SQLException { if (generateDBA()) return; Set baseClassFields = extractMappedFields(baseClassName); for (TableColumn tableColumn: flatTableColumnList) { if (baseClassFields.contains(tableColumn.getName())) continue; buffer.append(" private " + tableColumn.getType() + " " + tableColumn.getNameCamelCaseFirstLow() + ";" + "\n"); } buffer.append("\n"); } /** Prints the geter methods for all members to standard out */ public void writeGetMethods (TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) throws SQLException { if (generateDBA()) return; Set baseClassFields = extractMappedFields(baseClassName); buffer.append(" // Read access functions" + "\n"); for (TableColumn tableColumn: flatTableColumnList) { if (baseClassFields.contains(tableColumn.getName())) continue; buffer.append(" public " + tableColumn.getType() + " get" + tableColumn.getNameCamelCaseFirstUp() + "() { return " + tableColumn.getNameCamelCaseFirstLow() + "; }" + "\n"); } buffer.append("\n"); } /** Prints the seter methods for all members to standard out */ public void writeSetMethods (TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) throws SQLException { if (generateDBA()) return; Set baseClassFields = extractMappedFields(baseClassName); buffer.append(" // Write access functions" + "\n"); for (TableColumn tableColumn: flatTableColumnList) { if (baseClassFields.contains(tableColumn.getName())) continue; buffer.append(" public void set" + tableColumn.getNameCamelCaseFirstUp() + "(" + tableColumn.getType() + " " + tableColumn.getNameCamelCaseFirstLow() + ") { this." + tableColumn.getNameCamelCaseFirstLow() + " = " + tableColumn.getNameCamelCaseFirstLow() + "; }" + "\n"); } buffer.append("\n"); } public void writeToStringMethod(TableDescription[] desc, String className, String generationType, StringBuffer buffer) { if (!generationType.equals(BEAN) && !generationType.equals(HYBRID)) return; // Something intelligent would be nice but is not yet implemented } public void writeClone(TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) { if (generateDBA()) return; if (baseClassName != null) return; buffer.append(" public Object clone() throws CloneNotSupportedException {\n" + " return super.clone();\n" + " }\n" + "\n"); } /** Prints a re-constructor to restore an existing records from its primary key fields * In case of a bean class, this is just a constructor with the primary key fields */ public void writeReconstructor(TableDescription desc, String className, String baseClassName, StringBuffer buffer) { if (!desc.hasPrimaryKey() || generateDBA()) return; buffer.append("\n // Re-constructor\n"); buffer.append(" public " + getSimpleClassName(className) + "("); for (TableColumn current: desc.getColumnList()) { if (current.isPrimaryKeyField()) buffer.append((current.getType() != null? current.getType(): "Object") + " " + current.getName() + ", "); } buffer.delete(buffer.lastIndexOf(","), buffer.length()); buffer.append(")"); if (generateHybrid()) { buffer.append(" throws SQLException"); } buffer.append(" {\n"); if (baseClassName != null) buffer.append(" super("); for (TableColumn current: desc.getColumnList()) { if (current.isPrimaryKeyField()) { if (baseClassName == null) buffer.append(" set" + current.getNameCamelCaseFirstUp() + "(" + current.getName() + ");\n"); else buffer.append(current.getName() + ", "); } } if (baseClassName != null) { buffer.delete(buffer.lastIndexOf(","), buffer.length()); buffer.append(");\n"); } if (generateHybrid() && baseClassName == null) { buffer.append(" findx();\n"); } buffer.append(" }\n"); } /** Prints the footer to standard out, i.e. a reconstructor, a default constructor, * a toString method, a clone method, and the closing bracket */ public void writeFooter(TableDescription[] desc, String className, String baseClassName, String generationType, StringBuffer buffer) { if (desc.length == 1) { if (desc[0].getColumnList().size() > 0) writeReconstructor(desc[0], className, baseClassName, buffer); buffer.append("\n"); if (!generateDBA()) { buffer.append(" public " + getSimpleClassName(className) + "() {}\n\n"); } } writeToStringMethod(desc, className, generationType, buffer); writeClone(desc, className, baseClassName, generationType, buffer); buffer.append("}" + "\n"); buffer.append("\n" + "\n"); } protected String getTableIdType(final TableDescription tabCols) { String idType; List tableList = tabCols.getColumnList(); if (tableList.size() > 0) { TableColumn current = (TableColumn) tableList.get(0); idType = current.getType(); } else idType = "String"; return idType; } protected String getPackage(String className) { String pack = ""; if (className.indexOf(".") != -1) pack = "package " + className.substring(0, className.lastIndexOf(".")) + ";"; return pack; } protected String getSimpleClassName(String className) { if (className.indexOf(".") != -1) return className.substring(className.lastIndexOf(".") + 1); else return className; } protected String getCommaSeparatedTableNames() { StringBuffer buf = new StringBuffer(); for (TableDescription desc: this.tableDesc) { buf.append(","); buf.append(desc.getTableName()); } return buf.toString().substring(1); } protected List flattenTableColumns(TableDescription[] tableDescriptions) { List usedColumnNames = new LinkedList<>(); List notUniqueColumnNames = new LinkedList<>(); List flatTableColumnList = new ArrayList<>(); for (TableDescription tableDescription: tableDescriptions) { for (TableColumn tableColumn: tableDescription.getColumnList()) { flatTableColumnList.add(tableColumn); if (usedColumnNames.contains(tableColumn.getName())) { notUniqueColumnNames.add(tableColumn.getName()); } else { usedColumnNames.add(tableColumn.getName()); } } } for (TableColumn tableColumn: flatTableColumnList) { if (notUniqueColumnNames.contains(tableColumn.getName())) { tableColumn.makeUnique(); } } return flatTableColumnList; } /** * put your documentation comment here * @param args * @exception SQLException */ public EntityGenerator (String[] args) throws Exception { if (args.length < 1) { System.out.println("Usage: EntityGenerator tablename(s) [class] [beanclass | -b | -h] [baseclass]"); System.exit(0); } String tableName = args[0]; String className = null; String baseClassName = null; String generationType = HYBRID; String[] tableNames = null; if (tableName.indexOf(",") != -1) { StringTokenizer st = new StringTokenizer(tableName, ","); tableNames = new String[st.countTokens()]; for (int i = 0; i < tableNames.length; i++) { tableNames[i] = st.nextToken(); } } else { tableNames = new String[] { tableName }; } if (args.length > 1) className = args[1]; else { for (int i = 0; i < tableNames.length; i++) { if (className == null) { className = new String(""); } className += tableNames[i]; } className = className.substring(0,1).toUpperCase()+className.substring(1); } if (args.length > 2) { if (args[1].equals(BEAN)) generationType = BEAN; else if (!args[1].equals(HYBRID)) generationType = args[2]; } if (args.length > 3) baseClassName = args[3]; postInit(tableNames, className, generationType, baseClassName); } public void createAndPrint() throws Exception { System.out.println(create()); } public static void main (String[] args) throws Exception { new EntityGenerator(args).createAndPrint(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy