diff --git a/api/src/main/java/jakarta/data/event/LifecycleEvent.java b/api/src/main/java/jakarta/data/event/LifecycleEvent.java new file mode 100644 index 000000000..6ceb08e10 --- /dev/null +++ b/api/src/main/java/jakarta/data/event/LifecycleEvent.java @@ -0,0 +1,29 @@ +package jakarta.data.event; + +/** + *

Abstract supertype of events relating to lifecycle methods.

+ *

In Jakarta EE, a bean may observe such events via CDI:

+ *
+ * void onInsertBook(@Observes PostInsertEvent<Book> bookInsertion) {
+ *     Book book = bookInsertion.entity();
+ *     ...
+ * }
+ * 
+ * + * @param the entity type + */ +public abstract class LifecycleEvent { + private final E entity; + + public LifecycleEvent(E entity) { + this.entity = entity; + } + + /** + * The entity instance which was passed as an argument to + * the lifecycle method. + */ + public E entity() { + return entity; + } +} diff --git a/api/src/main/java/jakarta/data/event/PostDeleteEvent.java b/api/src/main/java/jakarta/data/event/PostDeleteEvent.java new file mode 100644 index 000000000..0d1d65e13 --- /dev/null +++ b/api/src/main/java/jakarta/data/event/PostDeleteEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023,2024 Contributors to the Eclipse Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.event; + +/** + * An event that occurs when an {@link jakarta.data.repository.Delete} + * method is called, and after the record was deleted from the datastore. + * + * @param the entity type + */ +public class PostDeleteEvent extends LifecycleEvent { + public PostDeleteEvent(E entity) { + super(entity); + } +} diff --git a/api/src/main/java/jakarta/data/event/PostInsertEvent.java b/api/src/main/java/jakarta/data/event/PostInsertEvent.java new file mode 100644 index 000000000..d86689364 --- /dev/null +++ b/api/src/main/java/jakarta/data/event/PostInsertEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023,2024 Contributors to the Eclipse Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.event; + +/** + * An event that occurs when an {@link jakarta.data.repository.Insert} + * method is called, and after the record was inserted into the datastore. + * + * @param the entity type + */ +public class PostInsertEvent extends LifecycleEvent { + public PostInsertEvent(E entity) { + super(entity); + } +} diff --git a/api/src/main/java/jakarta/data/event/PostUpdateEvent.java b/api/src/main/java/jakarta/data/event/PostUpdateEvent.java new file mode 100644 index 000000000..173f82814 --- /dev/null +++ b/api/src/main/java/jakarta/data/event/PostUpdateEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023,2024 Contributors to the Eclipse Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.event; + +/** + * An event that occurs when an {@link jakarta.data.repository.Update} + * method is called, and after the entity was updated in the datastore. + * + * @param the entity type + */ +public class PostUpdateEvent extends LifecycleEvent { + public PostUpdateEvent(E entity) { + super(entity); + } +} diff --git a/api/src/main/java/jakarta/data/event/PreDeleteEvent.java b/api/src/main/java/jakarta/data/event/PreDeleteEvent.java new file mode 100644 index 000000000..0e4668a3e --- /dev/null +++ b/api/src/main/java/jakarta/data/event/PreDeleteEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023,2024 Contributors to the Eclipse Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.event; + +/** + * An event that occurs when an {@link jakarta.data.repository.Delete} + * method is called, but before the record is deleted from the datastore. + * + * @param the entity type + */ +public class PreDeleteEvent extends LifecycleEvent { + public PreDeleteEvent(E entity) { + super(entity); + } +} diff --git a/api/src/main/java/jakarta/data/event/PreInsertEvent.java b/api/src/main/java/jakarta/data/event/PreInsertEvent.java new file mode 100644 index 000000000..68cfabedc --- /dev/null +++ b/api/src/main/java/jakarta/data/event/PreInsertEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023,2024 Contributors to the Eclipse Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.event; + +/** + * An event that occurs when an {@link jakarta.data.repository.Insert} + * method is called, but before the record is inserted into the datastore. + * + * @param the entity type + */ +public class PreInsertEvent extends LifecycleEvent { + public PreInsertEvent(E entity) { + super(entity); + } +} diff --git a/api/src/main/java/jakarta/data/event/PreUpdateEvent.java b/api/src/main/java/jakarta/data/event/PreUpdateEvent.java new file mode 100644 index 000000000..3e4b5adae --- /dev/null +++ b/api/src/main/java/jakarta/data/event/PreUpdateEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023,2024 Contributors to the Eclipse Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package jakarta.data.event; + +/** + * An event that occurs when an {@link jakarta.data.repository.Update} + * method is called, but before the entity is updated in the datastore. + * + * @param the entity type + */ +public class PreUpdateEvent extends LifecycleEvent { + public PreUpdateEvent(E entity) { + super(entity); + } +} diff --git a/api/src/main/java/jakarta/data/repository/Delete.java b/api/src/main/java/jakarta/data/repository/Delete.java index f2d1a8e36..c3ca93355 100644 --- a/api/src/main/java/jakarta/data/repository/Delete.java +++ b/api/src/main/java/jakarta/data/repository/Delete.java @@ -59,6 +59,11 @@ * if the entity with a matching identifier does not have a matching version, the annotated method must raise * {@link jakarta.data.exceptions.OptimisticLockingFailureException}. *

+ *

+ * An event of type {@link jakarta.data.event.PreDeleteEvent} must be raised by the annotated method before the record + * is deleted. An event of type {@link jakarta.data.event.PostDeleteEvent} must be raised by the annotated method after + * the record was successfully deleted. + *

* *

Alternatively, the {@code Delete} annotation may be used to annotate a repository method with no parameter of * entity type. Then the repository method is interpreted as a parameter-based automatic query method. The entity type diff --git a/api/src/main/java/jakarta/data/repository/Insert.java b/api/src/main/java/jakarta/data/repository/Insert.java index 5112adf7c..e40f961f5 100644 --- a/api/src/main/java/jakarta/data/repository/Insert.java +++ b/api/src/main/java/jakarta/data/repository/Insert.java @@ -66,6 +66,11 @@ * then the annotated method must raise {@link jakarta.data.exceptions.EntityExistsException}. * If the database follows the BASE model, or uses an append model to write data, this exception is not thrown. *

+ *

+ * An event of type {@link jakarta.data.event.PreInsertEvent} must be raised by the annotated method before the record + * is inserted. An event of type {@link jakarta.data.event.PostInsertEvent} must be raised by the annotated method after + * the record was successfully inserted. + *

*

Annotations such as {@code @Find}, {@code @Query}, {@code @Insert}, {@code @Update}, {@code @Delete}, and * {@code @Save} are mutually-exclusive. A given method of a repository interface may have at most one {@code @Find} * annotation, lifecycle annotation, or query annotation. diff --git a/api/src/main/java/jakarta/data/repository/Update.java b/api/src/main/java/jakarta/data/repository/Update.java index 3045ec97f..f8315ef0d 100644 --- a/api/src/main/java/jakarta/data/repository/Update.java +++ b/api/src/main/java/jakarta/data/repository/Update.java @@ -67,6 +67,11 @@ * If the database follows the BASE model, or uses an append model to write data, the annotated method behaves the same * as the {@code @Insert} method. *

+ *

+ * An event of type {@link jakarta.data.event.PreUpdateEvent} must be raised by the annotated method before the record + * is updated. An event of type {@link jakarta.data.event.PostUpdateEvent} must be raised by the annotated method after + * the record was successfully updated. + *

*

Annotations such as {@code @Find}, {@code @Query}, {@code @Insert}, {@code @Update}, {@code @Delete}, and * {@code @Save} are mutually-exclusive. A given method of a repository interface may have at most one {@code @Find} * annotation, lifecycle annotation, or query annotation. diff --git a/spec/src/main/asciidoc/jakarta-ee.adoc b/spec/src/main/asciidoc/jakarta-ee.adoc index bc51e27b8..8d2b6da91 100644 --- a/spec/src/main/asciidoc/jakarta-ee.adoc +++ b/spec/src/main/asciidoc/jakarta-ee.adoc @@ -67,6 +67,8 @@ This section discusses interoperability with related Jakarta EE footnote:[Jakart Contexts and Dependency Injection footnote:[Jakarta Contexts and Dependency Injection 4.1, https://jakarta.ee/specifications/cdi/4.1/] (CDI) is a specification in the Jakarta EE Core profile that provides a powerful and flexible dependency injection framework for Java applications. CDI provides a programming model based around decoupled components with container-managed lifecycles and container-injected dependencies, enabling loose coupling and promoting modular and reusable code. +==== CDI Dependency Injection + In the Jakarta EE environment, CDI allows implementations of Jakarta Data repositories to be made available for injection via the `@Inject` annotation. The following example illustrates this integration: @@ -115,6 +117,11 @@ This fragment shows how the application might request injection of a `CarReposit This integration between CDI and Jakarta Data allows for seamless management of repository instances within Jakarta EE applications. +==== CDI Events + +A repository implementation may raise CDI events. +In the Jakarta EE environment, the repository implementation is required the raise the event types defined in the package `jakarta.data.event` when lifecycle methods annotated `@Insert`, `@Update`, or `@Delete` are invoked, as specified by the API documentation of these annotations. + ==== CDI Extensions for Jakarta Data providers In environments where CDI Full or CDI Lite is available, Jakarta Data providers can make use of a CDI extension--an implementation of `jakarta.enterprise.inject.spi.Extension` or `jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension`--to discover interfaces annotated with `@Repository` and make their implementations available for injection.