1616package com .mongodb .internal .async .function ;
1717
1818import com .mongodb .annotations .NotThreadSafe ;
19+ import com .mongodb .assertions .Assertions ;
20+ import com .mongodb .connection .AsyncCompletionHandler ;
1921import com .mongodb .internal .async .SingleResultCallback ;
22+ import com .mongodb .internal .async .function .CallbackChain .Element ;
2023import com .mongodb .lang .Nullable ;
2124
2225import java .util .function .Supplier ;
2326
27+ import static com .mongodb .assertions .Assertions .assertNotNull ;
28+ import static com .mongodb .assertions .Assertions .assertNull ;
29+
2430/**
2531 * A decorator that implements automatic repeating of an {@link AsyncCallbackRunnable}.
2632 * {@link AsyncCallbackLoop} may execute the original asynchronous function multiple times sequentially,
3945 */
4046@ NotThreadSafe
4147public final class AsyncCallbackLoop implements AsyncCallbackRunnable {
42- @ Nullable
43- private final CallbackChain chain ;
4448 private final LoopState state ;
45- private final AsyncCallbackRunnable body ;
49+ private final Body body ;
4650
4751 /**
4852 * @param state The {@link LoopState} to be deemed as initial for the purpose of the new {@link AsyncCallbackLoop}.
@@ -53,43 +57,67 @@ public AsyncCallbackLoop(final LoopState state, final AsyncCallbackRunnable body
5357 }
5458
5559 public AsyncCallbackLoop (final boolean optimized , final LoopState state , final AsyncCallbackRunnable body ) {
56- this .chain = optimized ? new CallbackChain () : null ;
5760 this .state = state ;
58- this .body = body ;
61+ this .body = new Body ( optimized , body ) ;
5962 }
6063
6164 @ Override
6265 public void run (final SingleResultCallback <Void > callback ) {
6366 body .run (new LoopingCallback (callback ));
6467 }
6568
69+ private final class Body {
70+ private final AsyncCallbackRunnable wrapped ;
71+ @ Nullable
72+ private final CallbackChain chain ;
73+
74+ private Body (final boolean optimized , final AsyncCallbackRunnable body ) {
75+ this .wrapped = body ;
76+ this .chain = optimized ? new CallbackChain () : null ;
77+ }
78+
79+ @ Nullable
80+ Element run (final LoopingCallback loopingCallback ) {
81+ Element [] mutableElement = new Element [1 ];
82+ wrapped .run ((r , t ) -> {
83+ Element nextCallbackToComplete = loopingCallback .onResult (r , t );
84+ if (!CallbackChain .execute (chain , nextCallbackToComplete )) {
85+ mutableElement [0 ] = nextCallbackToComplete ;
86+ }
87+ });
88+ return mutableElement [0 ];
89+ }
90+ }
91+
6692 /**
6793 * This callback is allowed to be completed more than once.
6894 */
6995 @ NotThreadSafe
70- private class LoopingCallback implements SingleResultCallback < Void > {
96+ private class LoopingCallback {
7197 private final SingleResultCallback <Void > wrapped ;
7298
7399 LoopingCallback (final SingleResultCallback <Void > callback ) {
74100 wrapped = callback ;
75101 }
76102
77- @ Override
78- public void onResult (@ Nullable final Void result , @ Nullable final Throwable t ) {
103+ @ Nullable
104+ public Element onResult (@ Nullable final Void result , @ Nullable final Throwable t ) {
79105 if (t != null ) {
80106 wrapped .onResult (null , t );
107+ return null ;
81108 } else {
82109 boolean continueLooping ;
83110 try {
84111 continueLooping = state .advance ();
85112 } catch (Throwable e ) {
86113 wrapped .onResult (null , e );
87- return ;
114+ return null ;
88115 }
89116 if (continueLooping ) {
90- CallbackChain . execute ( chain , () -> body .run (this ) );
117+ return () -> body .run (this );
91118 } else {
92119 wrapped .onResult (result , null );
120+ return null ;
93121 }
94122 }
95123 }
0 commit comments