31
31
* @param <T> subscribed type (input)
32
32
* @param <U> published type (output)
33
33
*/
34
- public abstract class BaseProcessor <T , U > implements Processor <T , U >, Subscription {
34
+ public abstract class BaseProcessor <T , U > implements Processor <T , U >, Subscription , StrictProcessor {
35
35
36
36
private Subscription subscription ;
37
37
private final SingleSubscriberHolder <U > subscriber ;
38
38
private final RequestedCounter requested ;
39
+ private final RequestedCounter ableToSubmit ;
40
+ private final ReentrantLock subscriptionLock = new ReentrantLock ();
39
41
private final AtomicBoolean ready ;
40
42
private final AtomicBoolean subscribed ;
41
- private ReentrantLock publisherSequentialLock = new ReentrantLock ();
42
43
private volatile boolean done ;
43
44
private Throwable error ;
45
+ private boolean strictMode = DEFAULT_STRICT_MODE ;
46
+
44
47
45
48
/**
46
49
* Generic processor used for the implementation of {@link Multi} and {@link Single}.
47
50
*/
48
51
protected BaseProcessor () {
49
- requested = new RequestedCounter ();
52
+ requested = new RequestedCounter (strictMode );
53
+ ableToSubmit = new RequestedCounter (strictMode );
50
54
ready = new AtomicBoolean ();
51
55
subscribed = new AtomicBoolean ();
52
56
subscriber = new SingleSubscriberHolder <>();
53
57
}
54
58
59
+ @ Override
60
+ public BaseProcessor <T , U > strictMode (boolean strictMode ) {
61
+ this .strictMode = strictMode ;
62
+ return this ;
63
+ }
64
+
55
65
@ Override
56
66
public void request (long n ) {
57
- StreamValidationUtils .checkRequestParam (n , this ::failAndCancel );
58
- requested .increment (n , this ::failAndCancel );
59
- tryRequest (subscription );
67
+ ableToSubmit .increment (n , this ::failAndCancel );
68
+ subscriptionLock (() -> {
69
+ if (subscription != null && !subscriber .isClosed ()) {
70
+ subscription .request (n );
71
+ } else {
72
+ requested .increment (n , this ::failAndCancel );
73
+ }
74
+ });
60
75
if (done ) {
61
76
tryComplete ();
62
77
}
@@ -74,39 +89,27 @@ public void cancel() {
74
89
75
90
@ Override
76
91
public void onSubscribe (Subscription s ) {
77
- try {
78
- // https://github.com/reactive-streams/reactive-streams-jvm#1.3
79
- publisherSequentialLock .lock ();
80
- // https://github.com/reactive-streams/reactive-streams-jvm#2.13
81
- Objects .requireNonNull (s );
92
+ Objects .requireNonNull (s );
93
+ subscriptionLock (() -> {
82
94
if (subscription == null ) {
83
95
this .subscription = s ;
84
96
tryRequest (s );
85
97
} else {
86
- // https://github.com/reactive-streams/reactive-streams-jvm#2.5
87
98
s .cancel ();
88
99
}
89
- } finally {
90
- publisherSequentialLock .unlock ();
91
- }
100
+ });
92
101
}
93
102
94
103
@ Override
95
104
public void onNext (T item ) {
105
+ if (done ) {
106
+ throw new IllegalStateException ("Subscriber is closed!" );
107
+ }
108
+ Objects .requireNonNull (item );
96
109
try {
97
- publisherSequentialLock .lock ();
98
- if (done ) {
99
- throw new IllegalStateException ("Subscriber is closed!" );
100
- }
101
- // https://github.com/reactive-streams/reactive-streams-jvm#2.13
102
- Objects .requireNonNull (item );
103
- try {
104
- hookOnNext (item );
105
- } catch (Throwable ex ) {
106
- failAndCancel (ex );
107
- }
108
- } finally {
109
- publisherSequentialLock .unlock ();
110
+ hookOnNext (item );
111
+ } catch (Throwable ex ) {
112
+ failAndCancel (ex );
110
113
}
111
114
}
112
115
@@ -116,7 +119,6 @@ public void onNext(T item) {
116
119
* @param ex Exception to be reported downstream
117
120
*/
118
121
protected void fail (Throwable ex ) {
119
- // https://github.com/reactive-streams/reactive-streams-jvm#2.13
120
122
Objects .requireNonNull (ex );
121
123
done = true ;
122
124
if (error == null ) {
@@ -147,19 +149,20 @@ public void onComplete() {
147
149
}
148
150
149
151
@ Override
150
- public void subscribe (Subscriber <? super U > s ) {
151
- try {
152
- publisherSequentialLock .lock ();
152
+ public void subscribe (Subscriber <? super U > sub ) {
153
+ subscriptionLock (() -> {
154
+ var s = sub ;
155
+ if (strictMode ) {
156
+ s = SequentialSubscriber .create (sub );
157
+ }
153
158
if (subscriber .register (s )) {
154
159
ready .set (true );
155
160
s .onSubscribe (this );
156
161
if (done ) {
157
162
tryComplete ();
158
163
}
159
164
}
160
- } finally {
161
- publisherSequentialLock .unlock ();
162
- }
165
+ });
163
166
}
164
167
165
168
/**
@@ -172,31 +175,13 @@ protected Optional<Subscription> getSubscription() {
172
175
return Optional .ofNullable (subscription );
173
176
}
174
177
175
- /**
176
- * Processor's {@link SingleSubscriberHolder}.
177
- *
178
- * @return {@link SingleSubscriberHolder}
179
- */
180
- protected SingleSubscriberHolder <U > getSubscriber () {
181
- return subscriber ;
182
- }
183
-
184
- /**
185
- * Returns {@link RequestedCounter} with information about requested vs. submitted items.
186
- *
187
- * @return {@link RequestedCounter}
188
- */
189
- protected RequestedCounter getRequestedCounter () {
190
- return requested ;
191
- }
192
-
193
178
/**
194
179
* Submit an item to the subscriber.
195
180
*
196
181
* @param item item to be submitted
197
182
*/
198
183
protected void submit (U item ) {
199
- if (requested .tryDecrement ()) {
184
+ if (ableToSubmit .tryDecrement ()) {
200
185
try {
201
186
subscriber .get ().onNext (item );
202
187
} catch (InterruptedException ex ) {
@@ -257,10 +242,10 @@ protected void hookOnCancel(Flow.Subscription subscription) {
257
242
*/
258
243
protected final void doSubscribe (Publisher <U > delegate ) {
259
244
if (subscribed .compareAndSet (false , true )) {
260
- delegate .subscribe (new Subscriber <U >() {
245
+ delegate .subscribe (new Subscriber <>() {
261
246
@ Override
262
247
public void onSubscribe (Subscription subscription ) {
263
- tryRequest (subscription );
248
+ tryRequest (ableToSubmit , subscription );
264
249
}
265
250
266
251
@ Override
@@ -311,11 +296,37 @@ protected void tryComplete() {
311
296
* @param subscription {@link Flow.Subscription} to make a request from
312
297
*/
313
298
protected void tryRequest (Subscription subscription ) {
314
- if (subscription != null && !subscriber .isClosed ()) {
315
- long n = requested .get ();
316
- if (n > 0 ) {
317
- subscription .request (n );
299
+ tryRequest (requested , subscription );
300
+ }
301
+
302
+ private void tryRequest (RequestedCounter counter , Subscription subscription ) {
303
+ if (subscription == null || subscriber .isClosed ()) {
304
+ return ;
305
+ }
306
+
307
+ long n ;
308
+ try {
309
+ counter .lock ();
310
+ n = counter .get ();
311
+ if (n < 1 ) {
312
+ return ;
318
313
}
314
+ subscription .request (n );
315
+ } finally {
316
+ counter .unlock ();
317
+ }
318
+ }
319
+
320
+ private void subscriptionLock (Runnable guardedBlock ) {
321
+ if (!strictMode ) {
322
+ guardedBlock .run ();
323
+ return ;
324
+ }
325
+ try {
326
+ subscriptionLock .lock ();
327
+ guardedBlock .run ();
328
+ } finally {
329
+ subscriptionLock .unlock ();
319
330
}
320
331
}
321
332
}
0 commit comments