Skip to content

Commit 8df012c

Browse files
committed
[#2651] Implemented Reactive versions of PostAction, PreAction and JdbcSelectWithActions
1 parent 9930760 commit 8df012c

16 files changed

+1348
-17
lines changed

hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionFactoryImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
import org.hibernate.reactive.boot.spi.ReactiveMetadataImplementor;
1414
import org.hibernate.reactive.mutiny.Mutiny;
1515
import org.hibernate.reactive.mutiny.impl.MutinySessionFactoryImpl;
16+
import org.hibernate.reactive.sql.exec.internal.ReactiveJdbcSelectWithActions;
1617
import org.hibernate.reactive.stage.Stage;
1718
import org.hibernate.reactive.stage.impl.StageSessionFactoryImpl;
19+
import org.hibernate.sql.exec.spi.JdbcSelectWithActionsBuilder;
1820

1921
/**
2022
* A Hibernate {@link org.hibernate.SessionFactory} that can be
@@ -42,4 +44,9 @@ public <T> T unwrap(Class<T> type) {
4244
}
4345
return super.unwrap( type );
4446
}
47+
48+
public JdbcSelectWithActionsBuilder getJdbcSelectWithActionsBuilder(){
49+
return new ReactiveJdbcSelectWithActions.Builder();
50+
}
51+
4552
}
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.sql.exec.internal;
7+
8+
import org.hibernate.LockOptions;
9+
import org.hibernate.dialect.lock.spi.LockTimeoutType;
10+
import org.hibernate.dialect.lock.spi.LockingSupport;
11+
import org.hibernate.internal.util.collections.CollectionHelper;
12+
import org.hibernate.reactive.logging.impl.Log;
13+
import org.hibernate.reactive.logging.impl.LoggerFactory;
14+
import org.hibernate.reactive.pool.ReactiveConnection;
15+
import org.hibernate.reactive.sql.exec.internal.lock.ReactiveConnectionLockTimeoutStrategyBuilder;
16+
import org.hibernate.reactive.sql.exec.internal.lock.ReactiveFollowOnLockingAction;
17+
import org.hibernate.reactive.sql.exec.internal.lock.ReactiveLockTimeoutHandler;
18+
import org.hibernate.reactive.sql.exec.spi.ReactiveJdbcSelect;
19+
import org.hibernate.reactive.sql.exec.spi.ReactivePostAction;
20+
import org.hibernate.reactive.sql.exec.spi.ReactivePreAction;
21+
import org.hibernate.sql.ast.spi.LockingClauseStrategy;
22+
import org.hibernate.sql.ast.tree.select.QuerySpec;
23+
import org.hibernate.sql.exec.internal.JdbcOperationQuerySelect;
24+
import org.hibernate.sql.exec.internal.JdbcSelectWithActions;
25+
import org.hibernate.sql.exec.spi.ExecutionContext;
26+
import org.hibernate.sql.exec.spi.JdbcSelect;
27+
import org.hibernate.sql.exec.spi.JdbcSelectWithActionsBuilder;
28+
import org.hibernate.sql.exec.spi.LoadedValuesCollector;
29+
import org.hibernate.sql.exec.spi.PostAction;
30+
import org.hibernate.sql.exec.spi.PreAction;
31+
import org.hibernate.sql.exec.spi.SecondaryAction;
32+
import org.hibernate.sql.exec.spi.StatementAccess;
33+
34+
import java.lang.invoke.MethodHandles;
35+
import java.sql.Connection;
36+
import java.util.ArrayList;
37+
import java.util.Collections;
38+
import java.util.List;
39+
import java.util.concurrent.CompletionStage;
40+
41+
import static org.hibernate.reactive.util.impl.CompletionStages.loop;
42+
import static org.hibernate.reactive.util.impl.CompletionStages.nullFuture;
43+
44+
/**
45+
* Reactive version of {@link JdbcSelectWithActions}
46+
*/
47+
public class ReactiveJdbcSelectWithActions extends JdbcSelectWithActions implements ReactiveJdbcSelect {
48+
public static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() );
49+
50+
@Override
51+
public void performPreActions(
52+
StatementAccess jdbcStatementAccess,
53+
Connection jdbcConnection,
54+
ExecutionContext executionContext) {
55+
throw LOG.nonReactiveMethodCall( "reactivePerformPreActions()" );
56+
57+
}
58+
59+
@Override
60+
public void performPostAction(
61+
boolean succeeded,
62+
StatementAccess jdbcStatementAccess,
63+
Connection jdbcConnection,
64+
ExecutionContext executionContext) {
65+
throw LOG.nonReactiveMethodCall( "reactivePerformPostActions()" );
66+
}
67+
68+
public ReactiveJdbcSelectWithActions(
69+
JdbcOperationQuerySelect primaryOperation,
70+
LoadedValuesCollector loadedValuesCollector,
71+
PreAction[] preActions,
72+
PostAction[] postActions) {
73+
super( primaryOperation, loadedValuesCollector, preActions, postActions );
74+
}
75+
76+
public ReactiveJdbcSelectWithActions(
77+
JdbcOperationQuerySelect primaryAction,
78+
LoadedValuesCollector loadedValuesCollector) {
79+
super( primaryAction, loadedValuesCollector );
80+
}
81+
82+
@Override
83+
public CompletionStage<Void> reactivePerformPreActions(
84+
ReactiveConnection connection,
85+
ExecutionContext executionContext) {
86+
if ( preActions == null ) {
87+
return nullFuture();
88+
}
89+
90+
return loop( preActions, preAction ->
91+
( (ReactivePreAction) preAction ).reactivePerformPreAction( connection, executionContext )
92+
);
93+
}
94+
95+
@Override
96+
public CompletionStage<Void> reactivePerformPostActions(
97+
boolean succeeded,
98+
ReactiveConnection connection,
99+
ExecutionContext executionContext) {
100+
if ( postActions != null ) {
101+
return loop(
102+
postActions, postAction -> {
103+
if ( succeeded || postAction.shouldRunAfterFail() ) {
104+
return ( (ReactivePostAction) postAction ).reactivePerformReactivePostAction(
105+
connection,
106+
executionContext
107+
);
108+
}
109+
return nullFuture();
110+
}
111+
).thenAccept( unused -> {
112+
if ( loadedValuesCollector != null ) {
113+
loadedValuesCollector.clear();
114+
}
115+
} );
116+
}
117+
else {
118+
if ( loadedValuesCollector != null ) {
119+
loadedValuesCollector.clear();
120+
}
121+
return nullFuture();
122+
}
123+
}
124+
125+
public static class Builder implements JdbcSelectWithActionsBuilder {
126+
private JdbcOperationQuerySelect primaryAction;
127+
private LoadedValuesCollector loadedValuesCollector;
128+
protected List<PreAction> preActions;
129+
protected List<PostAction> postActions;
130+
protected LockTimeoutType lockTimeoutType;
131+
protected LockingSupport lockingSupport;
132+
protected LockOptions lockOptions;
133+
protected QuerySpec lockingTarget;
134+
protected LockingClauseStrategy lockingClauseStrategy;
135+
boolean isFollonOnLockStrategy;
136+
137+
@Override
138+
public Builder setPrimaryAction(JdbcSelect primaryAction) {
139+
assert primaryAction instanceof JdbcOperationQuerySelect;
140+
this.primaryAction = (JdbcOperationQuerySelect) primaryAction;
141+
return this;
142+
}
143+
144+
@SuppressWarnings("UnusedReturnValue")
145+
@Override
146+
public Builder setLoadedValuesCollector(LoadedValuesCollector loadedValuesCollector) {
147+
this.loadedValuesCollector = loadedValuesCollector;
148+
return this;
149+
}
150+
151+
@Override
152+
public Builder setLockTimeoutType(LockTimeoutType lockTimeoutType) {
153+
this.lockTimeoutType = lockTimeoutType;
154+
return this;
155+
}
156+
157+
@Override
158+
public Builder setLockingSupport(LockingSupport lockingSupport) {
159+
this.lockingSupport = lockingSupport;
160+
return this;
161+
}
162+
163+
@Override
164+
public Builder setLockOptions(LockOptions lockOptions) {
165+
this.lockOptions = lockOptions;
166+
return this;
167+
}
168+
169+
@Override
170+
public Builder setLockingTarget(QuerySpec lockingTarget) {
171+
this.lockingTarget = lockingTarget;
172+
return this;
173+
}
174+
175+
@Override
176+
public Builder setLockingClauseStrategy(LockingClauseStrategy lockingClauseStrategy) {
177+
this.lockingClauseStrategy = lockingClauseStrategy;
178+
return this;
179+
}
180+
181+
@Override
182+
public Builder setIsFollowOnLockStrategy(boolean isFollonOnLockStrategy) {
183+
this.isFollonOnLockStrategy = isFollonOnLockStrategy;
184+
return this;
185+
}
186+
187+
@Override
188+
public JdbcSelect build() {
189+
if ( lockTimeoutType == LockTimeoutType.CONNECTION ) {
190+
addSecondaryActionPair(
191+
new ReactiveLockTimeoutHandler(
192+
lockOptions.getTimeout(),
193+
ReactiveConnectionLockTimeoutStrategyBuilder.build( lockingSupport.getConnectionLockTimeoutStrategy() )
194+
)
195+
);
196+
}
197+
if ( isFollonOnLockStrategy ) {
198+
ReactiveFollowOnLockingAction.apply( lockOptions, lockingTarget, lockingClauseStrategy, this );
199+
}
200+
201+
if ( preActions == null && postActions == null ) {
202+
assert loadedValuesCollector == null;
203+
return primaryAction;
204+
}
205+
final PreAction[] preActions = toPreActionArray( this.preActions );
206+
final PostAction[] postActions = toPostActionArray( this.postActions );
207+
return new ReactiveJdbcSelectWithActions( primaryAction, loadedValuesCollector, preActions, postActions );
208+
}
209+
210+
/**
211+
* Appends the {@code actions} to the growing list of pre-actions,
212+
* executed (in order) after all currently registered actions.
213+
*
214+
* @return {@code this}, for method chaining.
215+
*/
216+
@Override
217+
public Builder appendPreAction(PreAction... actions) {
218+
if ( preActions == null ) {
219+
preActions = new ArrayList<>();
220+
}
221+
Collections.addAll( preActions, actions );
222+
return this;
223+
}
224+
225+
/**
226+
* Prepends the {@code actions} to the growing list of pre-actions
227+
*
228+
* @return {@code this}, for method chaining.
229+
*/
230+
@Override
231+
public Builder prependPreAction(PreAction... actions) {
232+
if ( preActions == null ) {
233+
preActions = new ArrayList<>();
234+
}
235+
// todo (DatabaseOperation) : should we invert the order of the incoming actions?
236+
Collections.addAll( preActions, actions );
237+
return this;
238+
}
239+
240+
/**
241+
* Appends the {@code actions} to the growing list of post-actions
242+
*
243+
* @return {@code this}, for method chaining.
244+
*/
245+
@Override
246+
public Builder appendPostAction(PostAction... actions) {
247+
if ( postActions == null ) {
248+
postActions = new ArrayList<>();
249+
}
250+
Collections.addAll( postActions, actions );
251+
return this;
252+
}
253+
254+
/**
255+
* Prepends the {@code actions} to the growing list of post-actions
256+
*
257+
* @return {@code this}, for method chaining.
258+
*/
259+
@Override
260+
public Builder prependPostAction(PostAction... actions) {
261+
if ( postActions == null ) {
262+
postActions = new ArrayList<>();
263+
}
264+
// todo (DatabaseOperation) : should we invert the order of the incoming actions?
265+
Collections.addAll( postActions, actions );
266+
return this;
267+
}
268+
269+
/**
270+
* Adds a secondary action pair.
271+
* Assumes the {@code action} implements both {@linkplain PreAction} and {@linkplain PostAction}.
272+
*
273+
* @return {@code this}, for method chaining.
274+
*
275+
* @apiNote Prefer {@linkplain #addSecondaryActionPair(PreAction, PostAction)} to avoid
276+
* the casts needed here.
277+
* @see #prependPreAction
278+
* @see #appendPostAction
279+
*/
280+
@Override
281+
public Builder addSecondaryActionPair(SecondaryAction action) {
282+
return addSecondaryActionPair( (PreAction) action, (PostAction) action );
283+
}
284+
285+
/**
286+
* Adds a PreAction/PostAction pair.
287+
*
288+
* @return {@code this}, for method chaining.
289+
*
290+
* @see #prependPreAction
291+
* @see #appendPostAction
292+
*/
293+
@Override
294+
public Builder addSecondaryActionPair(PreAction preAction, PostAction postAction) {
295+
prependPreAction( preAction );
296+
appendPostAction( postAction );
297+
return this;
298+
}
299+
300+
static PreAction[] toPreActionArray(List<PreAction> actions) {
301+
if ( CollectionHelper.isEmpty( actions ) ) {
302+
return null;
303+
}
304+
return actions.toArray( new PreAction[0] );
305+
}
306+
307+
static PostAction[] toPostActionArray(List<PostAction> actions) {
308+
if ( CollectionHelper.isEmpty( actions ) ) {
309+
return null;
310+
}
311+
return actions.toArray( new PostAction[0] );
312+
}
313+
314+
}
315+
}

0 commit comments

Comments
 (0)