jsr338-experts@jpa-spec.java.net

[jsr338-experts] Re: schema generation proposed changes

From: Linda DeMichiel <linda.demichiel_at_oracle.com>
Date: Sun, 29 Jul 2012 18:37:36 -0700

It is there for flexibility - to allow for the case where the platform provider may want
to offer pre-deployment options that allow these phases to be separated. For example,
if DDL files were packaged with the app, a platform provider might want to handle that
as a separate phase which might plausibly involve administrative intervention in the workflow.


On 7/29/2012 6:24 PM, Steve Ebersole wrote:
> That is what I was thinking at first, but then I was confused by the need for PersistenceProvider.generateSchema.
> Assuming the normal split audience between Persistence and PersistenceProvider, what are the cases you envision for EE
> containers needing to call PersistenceProvider.generateSchema in this way?
>
> On Sun 29 Jul 2012 08:20:02 PM CDT, Linda DeMichiel wrote:
>> Hi Steve,
>>
>> Just to be clear that we're on the same page here....
>>
>> The generateSchema methods are there for people who want the separate
>> stage
>> in the process -- perhaps to create DDL files, iterate over them
>> offline, and then
>> later cause the schema generation in the database.
>>
>> The other option described by the proposal is that schema generation
>> occurs
>> as a phase in the EMF creation itself. In this case, the mapping
>> information
>> would presumably only be parsed once.
>>
>> I'm assuming that the persistence provider could implement both paths
>> by delegating
>> to some common piece of code, but I didn't see that we needed to spec
>> that.
>>
>> -Linda
>>
>> p.s. I'm happy to have better names suggested. The name
>> generateSchema like
>> the term "schema generation" (which seems to be in common usage here) is
>> suboptimal IMO because in many cases the database schema per se is not
>> being
>> created as part of the process, only tables and other artifacts that live
>> in the schema.
>>
>>
>>
>> On 7/29/2012 2:16 PM, Steve Ebersole wrote:
>>> I have a concern about the API here. Specifically:
>>>
>>> public void generateSchema(PersistenceUnitInfo info, Map map)
>>> public void generateSchema(String persistenceUnitName, Map properties)
>>>
>>> The concern is that we will potentially be parsing the mapping
>>> information twice per deployment: once to comply with the
>>> "generate schema" call and then again to build the EMF. Unless
>>> providers stash away the "parsed" information in a static
>>> context, which is rather dubious IMHO. Yes, this works in the case
>>> when the caller only wants the schema generation to
>>> happen.
>>>
>>> I think it is more a general concern with the bootstrapping process.
>>>
>>> This actually falls into a discussion Scott Marlow and I have been
>>> having about provider bootstrapping. The discussion
>>> started out in regards to container bootstrapping specifically, but I
>>> think it is generally applicable to SE
>>> bootstrapping as well. The idea Scott and I decided to implement
>>> specific to JBoss/Hibernate integration is a 2-step
>>> bootstrapping process. Not sure if that is something that we want to
>>> address in 2.1, but I think it really needs to be
>>> addressed at some point. Scott had planned on writing up a proposal
>>> for this so I don;t want to steal his thunder, but I
>>> did want to raise this concern in regards to this proposal. The basic
>>> premise behind the 2-step process is that the
>>> first step returns a delegate capable of building an
>>> EntityManagerFactory given the current set of inputs (Map and
>>> persistenceUnitName/persistenceUnitInfo); that first step would have
>>> certain restrictions on what it could do and what
>>> it could access. In this scenario, we could ask this "delegate
>>> capable of building an EntityManagerFactory" to
>>> "generateSchema".
>>>
>>> This works with both cases of the schema generation happening as part
>>> of the EMF starting and in the case of the caller
>>> only wanting schema generation to happen. And more specifically in
>>> that first case it works without double parsing the
>>> mapping information.
>>>
>>> I really do understand the desire to avoid API changes. But I also
>>> know that sometimes they do need to change. I think
>>> this is a good example of that. The initial bootstrapping API was
>>> never designed with this new feature in mind (how
>>> could it have been). In fact, in the EE case this 2-step process
>>> makes sense even without considering this new feature.
>>>
>>>
>>> Also, trying to look forward again, even though we currently only
>>> support create/drop the initial discussion discussed
>>> "schema migration" as well. I wonder if in anticipation of that
>>> possibly being added in a later spec revision we might
>>> want to name these methods something other than "generate" (really it
>>> does not even fit in the DROP case). Maybe
>>> "manageSchema"?
>>>
>>>
>>> On 07/23/2012 06:55 PM, Linda DeMichiel wrote:
>>>> Here's an updated version of my earlier schema generation proposal,
>>>> broken out as to proposed spec changes. You should hopefully find
>>>> this considerably more flexible and detailed than the earlier draft.
>>>>
>>>> -Linda
>>>>
>>>> ----------------------------
>>>>
>>>> Proposed spec changes:
>>>>
>>>>
>>>> New Section: Schema Generation [to follow section 9.3]
>>>>
>>>> Schema generation may either happen prior to application deployment or
>>>> when the entity manager factory is created as part of the application
>>>> deployment and initialization process.
>>>>
>>>> * In Java EE environments, the container may call the
>>>> PersistenceProvider generateSchema method separately from and/or
>>>> prior to the creation of the entity manager factory for the
>>>> persistence unit, or the container may pass additional
>>>> information to the createContainerEntityManagerFactory call to
>>>> cause schema generation to happen as part of the entity manager
>>>> factory creation and application initialization process. The
>>>> information passed to these methods determines whether the
>>>> generation of schemas and/or tables occurs directly in the target
>>>> database, or whether DDL scripts for schema generation are
>>>> created, or both.
>>>>
>>>> * In Java SE environments, the application may call the Persistence
>>>> generateSchema method separately from and/or prior to the creation
>>>> of the entity manager factory or may pass information to the
>>>> createEntityManagerFactory method to cause schema generation to
>>>> occur as part of the entity manager factory creation.
>>>>
>>>>
>>>> The application may provide DDL scripts to be used for schema
>>>> generation, and package these scripts as part of the persistence unit
>>>> or specify URLs corresponding to the location of such scripts. In
>>>> Java EE environments, such scripts may be executed by the container,
>>>> or the container may direct the persistence provider to execute the
>>>> scripts; in Java SE environments, the execution of the scripts is the
>>>> responsibility of the persistence provider. In the absence of the
>>>> specification of scripts, schema generation, if requested, will be
>>>> determined by the object/relational metadata of the persistence unit.
>>>>
>>>>
>>>> The following standard properties are defined for use in schema
>>>> generation. In Java EE environments these properties are passed by
>>>> the container in the Map argument to the PersistenceProvider
>>>> generateSchema method or createContainerEntityManagerFactory method.
>>>> In Java SE environments, they are passed in the Map argument to the
>>>> Persistence generateSchema or createEntityManagerFactory method.
>>>>
>>>>
>>>> javax.persistence.schema-generation-target:
>>>>
>>>> The schema-generation-target property specifies whether the schema
>>>> is to be created in the database, whether scripts are to be
>>>> generated, or both.
>>>>
>>>> values for this property: DATABASE, SCRIPTS, DATABASE_AND_SCRIPTS
>>>> [Open Issue: introduce for these enum or use strings? Better names??]
>>>>
>>>>
>>>> javax.persistence.schema-generation-action:
>>>>
>>>> The schema-generation-action property is used to specify the action
>>>> to be taken by the persistence provider. If the
>>>> schema-generation-target property is not specified, no action must
>>>> be taken.
>>>>
>>>> values for this property: NONE, CREATE, DROP_AND_CREATE, DROP
>>>> [Open Issue: enum strings ("none", "create", "drop-and-create",...)
>>>>
>>>>
>>>> javax.persistence.create-database-schemas
>>>>
>>>> In Java EE environments, it is anticipated that the Java EE
>>>> platform provider may wish to control the creation of database
>>>> schemas rather than delegate this task to the persistence provider.
>>>> The create-database-schemas property specifies whether the
>>>> persistence provider is to create the database schema(s) in
>>>> addition to creating database objects such as tables, sequences,
>>>> constraints, etc. The value of this boolean property should be set
>>>> to true if the persistence provider is to create schemas in the
>>>> database or to generate DDL which is to contain "CREATE SCHEMA"
>>>> commands. If this property is not supplied, the provider should
>>>> not attempt to create database schemas. This property may be
>>>> specified in Java SE environments as well.
>>>>
>>>>
>>>> javax.persistence.ddl-create-script-target,
>>>> javax.persistence.ddl-drop-script-target:
>>>>
>>>> If scripts are to be generated, the target locations for the
>>>> writing of these scripts must be specified. These targets may take
>>>> the form of either Writers or strings designating URLs. The
>>>> persistence provider must produce both create and drop scripts if
>>>> the corresponding DDL targets are specified. This is independent
>>>> of whether a drop action is included in the value passed for the
>>>> schema-generation-action property. If the schema-generation-target
>>>> property specifies scripts and script targets are not specified,
>>>> the IllegalArgumentException should be thrown by the provider.
>>>>
>>>> ddl-create-script-target: a Writer configured for the persistence
>>>> provider for output of the DDL script or a string specifying
>>>> the URL for the DDL script. This property should only be
>>>> specified if scripts are to be generated.
>>>>
>>>> ddl-drop-script-target: a Writer configured for the persistence
>>>> provider for output of the DDL script or a string specifying the
>>>> URL for the DDL script. This property should only be specified
>>>> if scripts are to be generated.
>>>> [Suggestions for better names ??]
>>>>
>>>>
>>>> javax.persistence.database-product-name,
>>>> javax.persistence.database-product-version,
>>>>
>>>> If scripts are to be generated by the persistence provider and a
>>>> connection to the target database is not supplied, the
>>>> javax.persistence.database-product-name property must be
>>>> specified. The value of this property should be the value
>>>> returned for the target database by the JDBC DatabaseMetaData
>>>> method getDatabaseProductName. If sufficient database version
>>>> information is not included in the result of this method, the
>>>> database-product-version property should also be specified, and
>>>> should contain the value returned by the JDBC
>>>> getDatabaseProductVersion method.
>>>>
>>>>
>>>>
>>>> javax.persistence.ddl-create-script-source,
>>>> javax.persistence.ddl-drop-script-source:
>>>>
>>>> The ddl-create-script-source and ddl-drop-script-source properties
>>>> are used for script execution. In Java EE container environments,
>>>> it is generally expected that the container will be responsible
>>>> for executing DDL scripts, although the container is permitted to
>>>> delegate this task to the persistence provider. If DDL scripts
>>>> are to be used in Java SE environments or if the Java EE container
>>>> delegates the execution of scripts to the persistence provider,
>>>> these properties must be specified. The script sources may take
>>>> the form of either Readers or strings designating URLs.
>>>>
>>>> ddl-create-script-source: a Reader configured for reading of the
>>>> DDL script or a string specifying the URL for the DDL script.
>>>>
>>>> ddl-drop-script-source: a Reader configured for reading of the DDL
>>>> script or a string specifying the URL for the DDL script.
>>>> [Suggestions for better names ??]
>>>>
>>>>
>>>>
>>>> javax.persistence.sql-load-script-source:
>>>>
>>>> A data load script may be supplied as part of the persistence
>>>> unit. In Java EE container environments, it is generally expected
>>>> that the container will be responsible for executing data load
>>>> scripts, although the container is permitted to delegate this task
>>>> to the persistence provider. If a load script is to be used in
>>>> Java SE environments or if the Java EE container delegates the
>>>> execution of the load script to the persistence provider, this
>>>> property must be specified. The script source may take the form
>>>> of either a Reader or a string designating a URL.
>>>>
>>>> sql-load-script-source: a Reader configured for reading of the SQL
>>>> load script for database initialization or a string specifying
>>>> the URL for the script.
>>>>
>>>>
>>>>
>>>> javax.persistence.schema-generation-connection:
>>>>
>>>> JDBC connection to be used for schema generation. This is intended
>>>> for use in Java EE environments, where the platform provider may
>>>> want to control the database privileges that are available to the
>>>> persistence provider. This connection is provided by the container,
>>>> and should be closed by the container when the schema generation
>>>> request or entity manager factory creation completes. The
>>>> connection provided must have credentials sufficient for the
>>>> persistence provider to carry out the requested actions. If this
>>>> property is not specified, the persistence provider should use the
>>>> DataSource that has otherwise been provided.
>>>>
>>>>
>>>>
>>>> 9.4.1 PersistenceProvider Interface:
>>>>
>>>> New method:
>>>>
>>>> /**
>>>> * Create database schemas and/or tables and/or create DDL
>>>> * scripts as determined by the supplied properties
>>>> *
>>>> * @param info metadata for use by the persistence provider
>>>> * @param map properties for schema generation; these
>>>> * may also contain provider-specific properties
>>>> * @throws PersistenceException if insufficient or inconsistent
>>>> * configuration information is provided or if schema
>>>> * generation otherwise fails.
>>>> */
>>>> public void generateSchema(PersistenceUnitInfo info, Map map)
>>>>
>>>>
>>>> 9.6 Persistence Class
>>>>
>>>> New method:
>>>>
>>>> /**
>>>> * Create database schemas and/or tables and/or create DDL
>>>> * scripts as determined by the supplied properties
>>>> *
>>>> * @param persistenceUnitName the name of the persistence unit
>>>> * @param map properties for schema generation; these may also
>>>> * contain provider-specific properties. The values of
>>>> * these properties override any values that may have been
>>>> * configured elsewhere.
>>>> * @throws PersistenceException if insufficient or inconsistent
>>>> * configuration information is provided or if schema
>>>> * generation otherwise fails.
>>>> */
>>>> public void generateSchema(String persistenceUnitName, Map properties)
>>>>
>>>>
>>>> -----------------------
>>>>
>>>> Section 8.2.1 persistence.xml file
>>>>
>>>> To be added to section 8.2.1:
>>>>
>>>> Scripts for use in schema generation and bulk loading of data may be
>>>> packaged as part of the persistence unit.
>>>>
>>>>
>>>> To be added to Section 8.2.1.9 (properties):
>>>>
>>>> Scripts for use in schema generation are specified using the
>>>> ddl-create-script and ddl-drop-script elements. A script to specify
>>>> SQL for the bulk loading of data may be specified by the
>>>> sql-load-script element. These scripts may be packaged as part of the
>>>> persistence unit or designated by URL strings.
>>>>
>>>> <xsd:element name="database-scripts" type="database-scripts-type"
>>>> minOccurs="0"/>
>>>>
>>>> <xsd:complexType name="database-scripts-type">
>>>> <xsd:sequence>
>>>> <xsd:element name="ddl-create-script" type="xsd:string"/>
>>>> <xsd:element name="ddl-drop-script" type="xsd:string" minOccurs="0"/>
>>>> <xsd:element name="sql-load-script" type="xsd:string" minOccurs="0"/>
>>>> </xsd:sequence>
>>>> </xsd:complexType>
>>>>
>>>> [Open Issue: do we want to require a drop-script if a create-script
>>>> has been provided?]
>>>>
>>>> -----------
>>>>
>>>> Chapter 11:
>>>>
>>>> New annotations for use in schema generation:
>>>>
>>>> @Target({}) @Retention(RUNTIME)
>>>> public @interface Index {
>>>> String name() default "";
>>>> String columnList();
>>>> boolean unique() default false; // should this be here or just use
>>>> UniqueConstraints?
>>>> }
>>>>
>>>> columnList syntax follows that of the OrderBy annotation:
>>>>
>>>> columnList::= indexColumn [, indexColumn]*
>>>> indexColumn::= columnName [ASC | DESC]
>>>>
>>>> If ASC or DESC is not specified, ASC is assumed
>>>>
>>>> Index[] indexes() default {};
>>>> is to be added to Table, SecondaryTable, CollectionTable, JoinTable,
>>>> and
>>>> TableGenerator
>>>>
>>>>
>>>>
>>>> /**
>>>> * Provides for defining a foreign key constraint or for overriding
>>>> * or disabling the persistence provider's default foreign key
>>>> * definition.
>>>> */
>>>> @Target({}) @Retention(RUNTIME)
>>>> public @interface ForeignKey {
>>>> String name() default "";
>>>> String foreignKeyDefinition() default "";
>>>> boolean disableForeignKey() default false;
>>>> }
>>>>
>>>>
>>>> The syntax used in the foreignKeyDefinition element should follow the
>>>> SQL syntax used by the target database for foreign key constraints.
>>>> E.g., this would likely be similar to the following:
>>>>
>>>> FOREIGN KEY ( <COLUMN expression> {, <COLUMN expression>}... )
>>>> REFERENCES <TABLE identifier> [ ( <COLUMN expression> {, <COLUMN
>>>> expression>}... ) ]
>>>> [ ON UPDATE <referential action> ]
>>>> [ ON DELETE <referential action> ]
>>>>
>>>> If disableForeignKey is specified as true, the provider must not
>>>> generate
>>>> a foreign key constraint.
>>>>
>>>>
>>>> The following is to be added to JoinColumn, JoinColumns,
>>>> MapKeyJoinColumn,
>>>> MapKeyJoinColumns, PrimaryKeyJoinColumn and PrimaryKeyJoinColumns:
>>>>
>>>> ForeignKey foreignKey() default @ForeignKey();
>>>>
>>>>