Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
EclipseLink/Development/DBWS/MetadataGenerationFromDDLMetaModel
Contents
Generating JAXB and JPA Metadata From DDL Parser Meta-model
The EclipseLink DBWS design time component (a.k.a. DBWSBuilder) generates OR and OX projects for use by the runtime component - these project instances are built using DDLParser generated meta-model objects. Since EclipseLink 2.5, DBWS generates and writes out JAXB and JPA metadata (DBWS Metadata Support) based on the OR/OX projects. When considering JAXB/JPA metadata generation consolidation among various components, it would make sense to have the ability to generate metadata directly from the DDLParser generated metamodel, then bootstrap DBWS builder, JPA-RS, etc. from this metadata. This would allow the DDLParser and metadata generation piece proposed here to be standalone components, available to whomever requires this generated metadata.
Basic DDLParser Usage
The DatabaseTypeBuilder
class (part of the DDLParser package) is responsible for generating the required statement to be used to retrieve the DDL from the database, then parsing the returned DDL into the meta-model objects. The type builder can build TableTypes, ProcedureTypes, and PLSQLPackageTypes based on user provided schema(s) and table/procedure/package name(s), and a database connection. The build methods can take a single schema & table/procedure/package name, or lists of each when multiple artifacts are to be parsed.
Table
// use DatabaseTypeBuilder to generate a list of TableTypes DatabaseTypeBuilder dbTypeBuilder = new DatabaseTypeBuilder(); try { List<TableType> dbTables = dbTypeBuilder.buildTables(conn, "SCOTT", "EMPLOYEE_TABLE"); ... } catch (ParseException e) { // handle exception }
Top-level StoredProcedure
// use DatabaseTypeBuilder to generate a list of ProcedureTypes DatabaseTypeBuilder dbTypeBuilder = new DatabaseTypeBuilder(); try { List<ProcedureType> dbProcedures = dbTypeBuilder.buildProcedures(conn, "TOPLEVEL", "GetAllEmployees"); ... } catch (ParseException e) { // handle exception }
Top-level StoredFunction
// use DatabaseTypeBuilder to generate a list of FunctionTypes DatabaseTypeBuilder dbTypeBuilder = new DatabaseTypeBuilder(); try { List<FunctionType> dbFunctions = dbTypeBuilder.buildFunctions(conn, "TOPLEVEL", "GetEmployeeById"); ... } catch (ParseException e) { // handle exception }
PL/SQL Stored Functions/Procedures
Retrieving meta-model instances for PL/SQL procedures and functions involves retrieving the PL/SQL package meta-model, then getting the procedure and/or function objects from it.
// add desired PL/SQL stored function/procedure names List<String> procedurePatterns = new ArrayList<String>(); // PL/SQL stored procedures procedurePatterns.add("COPYTABLE"); procedurePatterns.add("COPYPHONECOLLECTION"); // PL/SQL stored functions procedurePatterns.add("CREATETABLE"); procedurePatterns.add("GETALLTABLES"); // use DatabaseTypeBuilder to generate a list of PLSQLPackageTypes DatabaseTypeBuilder dbTypeBuilder = new DatabaseTypeBuilder(); try { List<ProcedureType> dbProcedures = new ArrayList<ProcedureType>(); // process the package List<PLSQLPackageType> packages = dbTypeBuilder.buildPackages(conn, "SCOTT", "PACKAGE2"); for (PLSQLPackageType pkgType : packages) { // now get the desired procedures/functions from the processed package for (ProcedureType procType : pkgType.getProcedures()) { if (procedurePatterns.contains(procType.getProcedureName())) { dbProcedures.add(procType); } } } ... } catch (ParseException e) { // handle exception }
Multiple PL/SQL Packages
// schema names List<String> schemaNames = new ArrayList<String>(); schemaNames.add("HR"); schemaNames.add("SCOTT"); schemaNames.add("SCOTT"); // package names List<String> packageNames = new ArrayList<String>(); packageNames.add("HR_DATA"); packageNames.add("MATH_FUNCTIONS"); packageNames.add("EMPLOYEE"); // procedure names List<String> procedurePatterns= new ArrayList<String>(); procedurePatterns.add("findAllEmployees"); procedurePatterns.add("findEmployeeByPK"); procedurePatterns.add("getPersonalData"); procedurePatterns.add("removeEmployee"); procedurePatterns.add("calculateMaxAngle"); // use DatabaseTypeBuilder to generate a list of PLSQLPackageTypes DatabaseTypeBuilder dbTypeBuilder = new DatabaseTypeBuilder(); try { // process the packages List<PLSQLPackageType> packages = dbTypeBuilder.buildPackages(conn, schemaNames, packageNames); for (PLSQLPackageType pkgType : packages) { // now get the desired procedures/functions from the processed package for (ProcedureType procType : pkgType.getProcedures()) { if (procedurePatterns.contains(procType.getProcedureName())) { dbProcedures.add(procType); } } } ... } catch (ParseException e) { // handle exception }
JPA Metadata Generation
The EclipseLink JPA meta-model will be utilized to generate the JPA metadata. The proposed JPAMetadataGenerator
class will be responsible for building an instance of org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappings
. The entity mapping writer class (org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappingsWriter
) will then be used to marshal the generated metadata.
JPAMetadataGenerator
The JPA model generator class (org.eclipse.persistence.tools.dbws.metadata.generation.JPAMetadataGenerator
) is responsible for generating the EclipseLink JPA meta-model from a List of DDLParser meta-model objects. The following constructors will be provided:
/** * Default constructor. Sets the default package name to null, and dbPlatform to * org.eclipse.persistence.platform.database.oracle.Oracle11Platform. * * The default package name will be prepended to generated class names for database * artifacts that are not in a PL/SQL package. * * The database platform is used to get class names for database types, i.e. * java.math.BigDecimal for DECIMAL. * * @see org.eclipse.persistence.platform.database.oracle.Oracle11Platform * @see org.eorg.eclipse.persistence.internal.databaseaccess.DatabasePlatform */ public JPAMetadataGenerator() /** * This constructor allows setting the default package name and database platform. * * @param defaultPackage package name to be prepended to generated class names for artifacts * not in a PL/SQL package such as an Entity (to avoid having classes in the default package) * @param platformClassName class name of the DatabasePlatform to be used to get class names * for database types, i.e. java.math.BigDecimal for DECIMAL. * @see org.eorg.eclipse.persistence.internal.databaseaccess.DatabasePlatform */ public JPAMetadataGenerator(String defaultPackage, String platformClassName) /** * This constructor allows setting the default package name and database platform. * * @param defaultPackage package name to be prepended to generated class names for artifacts * not in a PL/SQL package such as an Entity (to avoid having classes in the default package) * @param dbPlatform DatabasePlatform to be used to get class names for database types, i.e. * java.math.BigDecimal for DECIMAL. * @see org.eorg.eclipse.persistence.internal.databaseaccess.DatabasePlatform */ public JPAMetadataGenerator(String defaultPackage, DatabasePlatform dbPlatform)
The generator will have a method that takes a List of org.eclipse.persistence.tools.oracleddl.metadata.CompositeDatabaseType
type instances, and return an org.eclipse.persistence.internal.jpa.metadata.xml.XMLEntityMappings
instance.
/** * Generate an XMLEntityMappings instance based on a given list of meta-model database types. * * @param databaseTypes the list of meta-model database types to be used to generate an XMLEntityMappings * @see org.eclipse.persistence.tools.oracleddl.metadata.CompositeDatabaseType */ public XMLEntityMappings generateXmlEntityMappings(List<CompositeDatabaseType> databaseTypes)
Use Cases
Simple Table
CREATE TABLE TABLETYPE ( EMPNO DECIMAL(4,0) NOT NULL, ENAME VARCHAR(10), HIREDATE DATE, PRIMARY KEY (EMPNO) ) static final String DEFAULT_PKG = "metadatagen"; static final String DB_PLATFORM = "org.eclipse.persistence.platform.database.oracle.Oracle11Platform"; DatabaseTypeBuilder dbTypeBuilder = new DatabaseTypeBuilder (); List dbTables; try { dbTables = dbTypeBuilder.buildTables(conn, "%", "TABLETYPE"); } catch (ParseException e) { // handle parse exception } // instantiate the JPA metadata generator JPAMetadataGenerator gen = new JPAMetadataGenerator(DEFAULT_PKG , DB_PLATFORM); // generate the XMLEntityMappings instance XMLEntityMappings mappings = gen.generateXmlEntityMappings(dbTables);
Simple TopLevel Stored Procedure
JAXB Metadata Generation
- TBD
Open Issues
- What should the default package name for generated Entities (or anything not in a PL/SQL package) be? Ideally the user would be permitted to set this on the generator.
- Query names - what would be the default name for a query generated from a stored procedure, etc.? Perhaps the user could provide a Map of query names > procedure names. Currently, the query name is the stored proc/function name.
- For non-Oracle databases, JDBCHelper returns meta-model objects that extend the DDLParser meta-model - should this functionality be taken into consideration here as well?
- Automatic CRUD operation generation for tables; by default, DBWS generates CRUD query operations for a given database table - is this something we should include by default? Perhaps it could be configurable.
- Relationships - there is currently nothing in place to allow the user to define relationships between tables.