From 618d14800a82df16e20579152437015300d4dc95 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 8 Aug 2023 20:24:17 +0200 Subject: [PATCH] add SchemaManager see #399 --- .../persistence/EntityManagerFactory.java | 12 ++ .../jakarta/persistence/SchemaManager.java | 86 ++++++++++++++ .../SchemaValidationException.java | 55 +++++++++ spec/src/main/asciidoc/appendixes.adoc | 2 + ...titymanagers-and-persistence-contexts.adoc | 108 ++++++++++++++++++ .../main/asciidoc/ch08-entity-packaging.adoc | 4 +- .../ch09-container-provider-contracts.adoc | 4 +- 7 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 api/src/main/java/jakarta/persistence/SchemaManager.java create mode 100644 api/src/main/java/jakarta/persistence/SchemaValidationException.java diff --git a/api/src/main/java/jakarta/persistence/EntityManagerFactory.java b/api/src/main/java/jakarta/persistence/EntityManagerFactory.java index faf7f36b..ec99b7df 100644 --- a/api/src/main/java/jakarta/persistence/EntityManagerFactory.java +++ b/api/src/main/java/jakarta/persistence/EntityManagerFactory.java @@ -11,6 +11,7 @@ */ // Contributors: +// Gavin King - 3.2 // Linda DeMichiel - 2.1 // Linda DeMichiel - 2.0 @@ -167,6 +168,17 @@ public interface EntityManagerFactory extends AutoCloseable { */ public PersistenceUnitUtil getPersistenceUnitUtil(); + /** + * Return interface providing access to schema management + * operations for the persistence unit. + * @return SchemaManager interface + * @throws IllegalStateException if the entity manager factory + * has been closed + * + * @since 3.2 + */ + public SchemaManager getSchemaManager(); + /** * Define the query, typed query, or stored procedure query as * a named query such that future query objects can be created diff --git a/api/src/main/java/jakarta/persistence/SchemaManager.java b/api/src/main/java/jakarta/persistence/SchemaManager.java new file mode 100644 index 00000000..081ab94b --- /dev/null +++ b/api/src/main/java/jakarta/persistence/SchemaManager.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2008, 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Gavin King - 3.2 + +package jakarta.persistence; + +import java.util.Map; + +/** + * Allows programmatic {@linkplain #create schema creation}, + * {@linkplain #validate schema validation}, + * {@linkplain #truncate data cleanup}, and + * {@linkplain #drop schema cleanup} for entities belonging + * to a certain persistence unit. + * + *

Properties are inherited from the {@link EntityManagerFactory}, + * that is, they may be specified via {@code persistence.xml} or + * {@link Persistence#createEntityManagerFactory(String, Map)}. + * + * @see EntityManagerFactory#getSchemaManager() + * + * @since 3.2 + */ +public interface SchemaManager { + /** + * Create database objects mapped by entities belonging to the + * persistence unit. + * + *

If a DDL operation fails, the behavior is undefined. + * A provider may throw an exception, or it may ignore the problem + * and continue. + * + * @param createSchemas if {@code true}, attempt to create schemas, + * otherwise, assume the schemas already exist + */ + void create(boolean createSchemas); + + /** + * Drop database objects mapped by entities belonging to the + * persistence unit, undoing the effects of the + * {@linkplain #create(boolean) previous creation}. + * + *

If a DDL operation fails, the behavior is undefined. + * A provider may throw an exception, or it may ignore the problem + * and continue. + * + * @param dropSchemas if {@code true}, drop schemas, + * otherwise, leave them be + */ + void drop(boolean dropSchemas); + + /** + * Validate that the database objects mapped by entities belonging + * to the persistence unit have the expected definitions. + * + *

The persistence provider is not required to perform + * any specific validation, so the semantics of this operation are + * entirely provider-specific. + * + * @throws SchemaValidationException if a database object is missing or + * does not have the expected definition + */ + void validate() throws SchemaValidationException; + + /** + * Truncate the database tables mapped by entities belonging to + * the persistence unit, and then re-import initial data from any + * configured SQL scripts for data loading. + * + *

If a SQL operation fails, the behavior is undefined. + * A provider may throw an exception, or it may ignore the problem + * and continue. + */ + void truncate(); +} diff --git a/api/src/main/java/jakarta/persistence/SchemaValidationException.java b/api/src/main/java/jakarta/persistence/SchemaValidationException.java new file mode 100644 index 00000000..69164ef4 --- /dev/null +++ b/api/src/main/java/jakarta/persistence/SchemaValidationException.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008, 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Gavin King - 3.2 + +package jakarta.persistence; + +/** + * Thrown when {@link SchemaManager#validate() schema validation} fails. + * + * @see SchemaManager#validate() + * + * @since 3.2 + */ +public class SchemaValidationException extends Exception { + private final Exception[] failures; + + /** + * An array of problems detected while validating the schema. + * + *

A persistence provider might choose to fail fast upon + * encountering a problem with one database object, in which + * case there is only one problem reported here. Alternatively, + * a provider might choose to continue validating the remaining + * database objects, in which case multiple problems might be + * reported, each as a separate exception instance. + */ + public Exception[] getFailures() { + return failures; + } + + /** + * Constructs a new instance with a message and, optionally, + * an array of exceptions, each representing a problem detected + * while validating the schema. + * @param message an overall message + * @param failures an array of exceptions, each representing a + * separate problem + */ + public SchemaValidationException(String message, Exception... failures) { + super(message); + this.failures = failures == null ? new Exception[0] : failures; + } + +} diff --git a/spec/src/main/asciidoc/appendixes.adoc b/spec/src/main/asciidoc/appendixes.adoc index f4d11a68..3c2ef6f6 100644 --- a/spec/src/main/asciidoc/appendixes.adoc +++ b/spec/src/main/asciidoc/appendixes.adoc @@ -112,6 +112,8 @@ Added `||` string concatenation operator Added support for specifying null precedence when ordering JPQL and criteria queries +Introduced SchemaManager API + Added _getSingleResultOrNull()_ to _Query_, _TypedQuery_, _StoredProcedureQuery_ Added new operations to _PersistenceUnitUtil_ diff --git a/spec/src/main/asciidoc/ch07-entitymanagers-and-persistence-contexts.adoc b/spec/src/main/asciidoc/ch07-entitymanagers-and-persistence-contexts.adoc index a824428d..eead4d25 100644 --- a/spec/src/main/asciidoc/ch07-entitymanagers-and-persistence-contexts.adoc +++ b/spec/src/main/asciidoc/ch07-entitymanagers-and-persistence-contexts.adoc @@ -358,6 +358,17 @@ public interface EntityManagerFactory extends AutoCloseable { */ public PersistenceUnitUtil getPersistenceUnitUtil(); + /** + * Return interface providing access to schema management + * operations for the persistence unit. + * @return SchemaManager interface + * @throws IllegalStateException if the entity manager factory + * has been closed + * + * @since 3.2 + */ + public SchemaManager getSchemaManager(); + /** * Define the query, typed query, or stored procedure query as * a named query such that future query objects can be created @@ -1525,4 +1536,101 @@ public interface PersistenceUnitUtil extends PersistenceUtil { */ public Object getIdentifier(Object entity); } +---- + +=== SchemaManager Interface [[a12178]] + +The _SchemaManager_ interface allows programmatic control over schema +generation and cleanup at runtime. This differs from the functionality +described in <> which allows schema generation before or during +the application deployment and initialization process. Similarly, the +_generateSchema_ method described in <> is intended to be called +before the _EntityManagerFactory_ is available. By contrast, an instance +of _SchemaManager_ is only available after an _EntityManagerFactory_ has +already been created. + +For example, _SchemaManager_ is especially useful in tests. + +The methods of _SchemaManager_ correspond to values of the property +_jakarta.persistence.schema-generation.scripts.action_. The methods +_create()_, _drop()_, and _validate()_ correspond to the actions +_create_, _drop_, and _validate_. The method _truncate()_ has no +corresponding action. + +Thus, the behavior of the _SchemaManager_ may be controlled via the +properties defined in <> and <>. + +[source,java] +---- +package jakarta.persistence; + +import java.util.Map; + +/** + * Allows programmatic {@linkplain #create schema creation}, + * {@linkplain #validate schema validation}, + * {@linkplain #truncate data cleanup}, and + * {@linkplain #drop schema cleanup} for entities belonging + * to a certain persistence unit. + * + *

Properties are inherited from the {@link EntityManagerFactory}, + * that is, they may be specified via {@code persistence.xml} or + * {@link Persistence#createEntityManagerFactory(String, Map)}. + * + * @see EntityManagerFactory#getSchemaManager() + * + * @since 3.2 + */ +public interface SchemaManager { + /** + * Create database objects mapped by entities belonging to the + * persistence unit. + * + *

If a DDL operation fails, the behavior is undefined. + * A provider may throw an exception, or it may ignore the problem + * and continue. + * + * @param createSchemas if {@code true}, attempt to create schemas, + * otherwise, assume the schemas already exist + */ + void create(boolean createSchemas); + + /** + * Drop database objects mapped by entities belonging to the + * persistence unit, undoing the effects of the + * {@linkplain #create(boolean) previous creation}. + * + *

If a DDL operation fails, the behavior is undefined. + * A provider may throw an exception, or it may ignore the problem + * and continue. + * + * @param dropSchemas if {@code true}, drop schemas, + * otherwise, leave them be + */ + void drop(boolean dropSchemas); + + /** + * Validate that the database objects mapped by entities belonging + * to the persistence unit have the expected definitions. + * + *

The persistence provider is not required to perform + * any specific validation, so the semantics of this operation are + * entirely provider-specific. + * + * @throws SchemaValidationException if a database object is missing or + * does not have the expected definition + */ + void validate() throws SchemaValidationException; + + /** + * Truncate the database tables mapped by entities belonging to + * the persistence unit, and then re-import initial data from any + * configured SQL scripts for data loading. + * + *

If a SQL operation fails, the behavior is undefined. + * A provider may throw an exception, or it may ignore the problem + * and continue. + */ + void truncate(); +} ---- \ No newline at end of file diff --git a/spec/src/main/asciidoc/ch08-entity-packaging.adoc b/spec/src/main/asciidoc/ch08-entity-packaging.adoc index 3ffaa887..89047810 100644 --- a/spec/src/main/asciidoc/ch08-entity-packaging.adoc +++ b/spec/src/main/asciidoc/ch08-entity-packaging.adoc @@ -526,8 +526,8 @@ properties used in the _persistence.xml_ file. The _jakarta.persistence.schema-generation.database.action_ property specifies the action to be taken by the persistence provider with regard to the database artifacts. The values for this property are _none_, _create_, -_drop-and-create_, _drop_. If this property is not specified, it is -assumed that schema generation is not needed or will be initiated by +_drop-and-create_, _drop_, _validate_. If this property is not specified, +it is assumed that schema generation is not needed or will be initiated by other means, and, by default, no schema generation actions will be taken on the database. (See <>.) * _jakarta.persistence.schema-generation.scripts.action_ + diff --git a/spec/src/main/asciidoc/ch09-container-provider-contracts.adoc b/spec/src/main/asciidoc/ch09-container-provider-contracts.adoc index ed2525b9..951d285f 100644 --- a/spec/src/main/asciidoc/ch09-container-provider-contracts.adoc +++ b/spec/src/main/asciidoc/ch09-container-provider-contracts.adoc @@ -139,7 +139,7 @@ If a provider does not qualify as the provider for the named persistence unit, it must return _null_ when _createEntityManagerFactory_ is invoked on it. -==== Schema Generation +==== Schema Generation [[a12803]] In Java SE environments, the _Persistence.generateSchema_ method may be used by the application to @@ -389,7 +389,7 @@ deploying the persistence unit The _jakarta.persistence.schema-generation.database.action_ property specifies the action to be taken by the persistence provider with regard to the database artifacts. The values for this property are _"none"_, -_"create"_, _"drop-and-create"_, _"drop"_. If the +_"create"_, _"drop-and-create"_, _"drop"_, _"validate"_. If the _jakarta.persistence.schema-generation.database.action_ property is not specified, no schema generation actions must be taken on the database. * _jakarta.persistence.schema-generation.scripts.action_ +