Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

first rough proposal for events #876

Merged
merged 24 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2456ae4
first rough proposal for events
gavinking Oct 24, 2024
3deeca1
Update api/src/main/java/jakarta/data/event/LifecycleEvent.java
gavinking Oct 24, 2024
fd3d56f
Update api/src/main/java/jakarta/data/event/PostDeleteEvent.java
gavinking Oct 24, 2024
53be717
Update api/src/main/java/jakarta/data/event/PostInsertEvent.java
gavinking Oct 24, 2024
2c45034
Update api/src/main/java/jakarta/data/event/PreUpdateEvent.java
gavinking Oct 24, 2024
cd98c23
Update api/src/main/java/jakarta/data/event/PostUpdateEvent.java
gavinking Oct 24, 2024
5d767d5
Update api/src/main/java/jakarta/data/repository/Update.java
gavinking Oct 24, 2024
206746d
Update api/src/main/java/jakarta/data/event/PreDeleteEvent.java
gavinking Oct 24, 2024
290be6b
Update api/src/main/java/jakarta/data/repository/Insert.java
gavinking Oct 24, 2024
e4eae35
Update api/src/main/java/jakarta/data/repository/Delete.java
gavinking Oct 24, 2024
7ec7359
Update api/src/main/java/jakarta/data/event/PreInsertEvent.java
gavinking Oct 24, 2024
3f5bad5
Update spec/src/main/asciidoc/jakarta-ee.adoc
gavinking Oct 25, 2024
71eab88
set expectations around the entity() method of LifecycleEvent
gavinking Nov 20, 2024
32e548a
Update api/src/main/java/jakarta/data/event/PreUpdateEvent.java
gavinking Nov 21, 2024
5ca2a9d
Update api/src/main/java/jakarta/data/event/PostDeleteEvent.java
gavinking Nov 21, 2024
965aa3a
Update api/src/main/java/jakarta/data/event/PostDeleteEvent.java
gavinking Nov 21, 2024
bc49d2d
Update api/src/main/java/jakarta/data/event/PostInsertEvent.java
gavinking Nov 21, 2024
64492bd
Update api/src/main/java/jakarta/data/event/PreInsertEvent.java
gavinking Nov 21, 2024
68d88a3
Update api/src/main/java/jakarta/data/event/PreDeleteEvent.java
gavinking Nov 21, 2024
9c0d3c4
Update api/src/main/java/jakarta/data/event/PostInsertEvent.java
gavinking Nov 21, 2024
40bbaab
Update api/src/main/java/jakarta/data/event/PostUpdateEvent.java
gavinking Nov 21, 2024
19f408f
Update api/src/main/java/jakarta/data/event/PreDeleteEvent.java
gavinking Nov 21, 2024
ab12abe
Update api/src/main/java/jakarta/data/event/PostUpdateEvent.java
gavinking Nov 21, 2024
fd91006
add language about transactional and async observers
gavinking Nov 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions api/src/main/java/jakarta/data/event/LifecycleEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 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;
gavinking marked this conversation as resolved.
Show resolved Hide resolved

/**
* <p>Abstract supertype of events relating to lifecycle methods.</p>
* <p>In Jakarta EE, a bean may observe such events via CDI:</p>
* <pre>
* void onInsertBook(&#64;Observes PostInsertEvent&lt;Book&gt; bookInsertion) {
* Book book = bookInsertion.entity();
* ...
* }
* </pre>
* <p>As usual for a CDI event, an observer of a {@code LifecycleEvent}
* is notified synchronously and immediately by default. An observer may
* elect to receive notifications during a phase of the transaction
* completion cycle by explicitly specifying a {@code TransactionPhase},
* for example:</p>
* <ul>
* <li>{@code @Observes(during=BEFORE_COMPLETION)} to be notified just
* before transaction completion, or</li>
* <li>{@code @Observes(during=AFTER_SUCCESS)} to be notified after
* successful completion of the transaction.</li>
* </ul>
* <p>An observer may choose to be notified asynchronously using
* {@code @ObservesAsync}. However, the mutable state held by the
* {@link #entity} is not in general safe for concurrent access,
* and so portable applications must not use {@code @ObservesAsync}
* to observe a {@code LifecycleEvent}. If the state of an entity is
* accessed from an asynchronous observer method for a lifecycle
* event, the resulting behavior is undefined and unportable.</p>
Comment on lines +29 to +46
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added this new language.

I've also addressed all suggestions from @njr-11.

*
*
* @param <E> the entity type
*/
public abstract class LifecycleEvent<E> {
private final E entity;

public LifecycleEvent(E entity) {
this.entity = entity;
}

/**
* The entity which is being processed by the lifecycle method.
* <ul>
* <li>For a {@code Pre} event, this is always the instance
* which was passed as an argument to the lifecycle
* method, and its state reflects the state of the
* entity before execution of the lifecycle method.</li>
* <li>For a {@code Post} event, it may or may not be
* identical to the object passed as an argument
* to the lifecycle method, and it may or may not be
* identical to the instance returned by the lifecycle
* method, if any. If the state of the entity changes
* as a result of execution of the lifecycle method,
* those changes may or may not be reflected in the
* entity returned by this method.</li>
* </ul>
* <p>
* Thus, a portable application should not assume that the
* state of the entity in a {@code Post} event faithfully
* reflects the current state of the corresponding record
* in the database.
* <p>
* A portable application must not mutate the state of the
* entity instance returned by this method. If the state
* of the entity instance is mutated while event listeners
* are being notified, the resulting behavior is undefined
* and unportable.
*/
public E entity() {
return entity;
}
}
30 changes: 30 additions & 0 deletions api/src/main/java/jakarta/data/event/PostDeleteEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 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 a {@link jakarta.data.repository.Delete}
* lifecycle method is called, after each record is deleted from the datastore.
*
* @param <E> the entity type
*/
public class PostDeleteEvent<E> extends LifecycleEvent<E> {
public PostDeleteEvent(E entity) {
super(entity);
}
njr-11 marked this conversation as resolved.
Show resolved Hide resolved
}
30 changes: 30 additions & 0 deletions api/src/main/java/jakarta/data/event/PostInsertEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 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}
* lifecycle method is called, after each record is inserted into the datastore.
*
* @param <E> the entity type
*/
public class PostInsertEvent<E> extends LifecycleEvent<E> {
public PostInsertEvent(E entity) {
super(entity);
}
njr-11 marked this conversation as resolved.
Show resolved Hide resolved
}
30 changes: 30 additions & 0 deletions api/src/main/java/jakarta/data/event/PostUpdateEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 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}
* lifecycle method is called, after each entity is updated in the datastore.
*
* @param <E> the entity type
*/
public class PostUpdateEvent<E> extends LifecycleEvent<E> {
public PostUpdateEvent(E entity) {
super(entity);
}
njr-11 marked this conversation as resolved.
Show resolved Hide resolved
}
30 changes: 30 additions & 0 deletions api/src/main/java/jakarta/data/event/PreDeleteEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 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 a {@link jakarta.data.repository.Delete}
* lifecycle method is called, but before each record is deleted from the datastore.
*
* @param <E> the entity type
*/
public class PreDeleteEvent<E> extends LifecycleEvent<E> {
public PreDeleteEvent(E entity) {
super(entity);
}
njr-11 marked this conversation as resolved.
Show resolved Hide resolved
}
30 changes: 30 additions & 0 deletions api/src/main/java/jakarta/data/event/PreInsertEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 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}
* lifecycle method is called, but before each record is inserted into the datastore.
*
* @param <E> the entity type
*/
public class PreInsertEvent<E> extends LifecycleEvent<E> {
public PreInsertEvent(E entity) {
super(entity);
}
njr-11 marked this conversation as resolved.
Show resolved Hide resolved
}
30 changes: 30 additions & 0 deletions api/src/main/java/jakarta/data/event/PreUpdateEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 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}
* lifecycle method is called, but before each entity is updated in the datastore.
*
* @param <E> the entity type
*/
public class PreUpdateEvent<E> extends LifecycleEvent<E> {
public PreUpdateEvent(E entity) {
super(entity);
}
njr-11 marked this conversation as resolved.
Show resolved Hide resolved
}
5 changes: 5 additions & 0 deletions api/src/main/java/jakarta/data/repository/Delete.java
Original file line number Diff line number Diff line change
Expand Up @@ -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}.
* </p>
* <p>
* An event of type {@link jakarta.data.event.PreDeleteEvent} must be raised by the annotated lifecycle
* method before each record is deleted. An event of type {@link jakarta.data.event.PostDeleteEvent}
* must be raised by the annotated lifecycle method after each record is successfully deleted.
* </p>
*
* <p>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
Expand Down
5 changes: 5 additions & 0 deletions api/src/main/java/jakarta/data/repository/Insert.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
* </p>
* <p>
* An event of type {@link jakarta.data.event.PreInsertEvent} must be raised by the annotated lifecycle
* method before each record is inserted. An event of type {@link jakarta.data.event.PostInsertEvent}
* must be raised by the annotated lifecycle method after each record is successfully inserted.
* </p>
* <p>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.
Expand Down
5 changes: 5 additions & 0 deletions api/src/main/java/jakarta/data/repository/Update.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
* </p>
* <p>
* An event of type {@link jakarta.data.event.PreUpdateEvent} must be raised by the annotated lifecycle
* method before each record is updated. An event of type {@link jakarta.data.event.PostUpdateEvent}
* must be raised by the annotated lifecycle method after each record is successfully updated.
* </p>
* <p>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.
Expand Down
7 changes: 7 additions & 0 deletions spec/src/main/asciidoc/jakarta-ee.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
gavinking marked this conversation as resolved.
Show resolved Hide resolved

A repository implementation may raise CDI events.
In the Jakarta EE environment, the repository implementation is required to 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.
Expand Down