2018-10-29 17:19:37 +08:00
|
|
|
/*
|
2021-01-08 17:55:38 +01:00
|
|
|
* Copyright (C) 2009-2021 Lightbend Inc. <https://www.lightbend.com>
|
2015-03-30 14:22:12 +02:00
|
|
|
*/
|
2018-03-13 23:45:55 +09:00
|
|
|
|
2014-11-19 12:56:55 +01:00
|
|
|
package akka.stream.impl
|
2014-11-17 22:50:15 +01:00
|
|
|
|
|
|
|
|
import scala.util.control.NonFatal
|
2020-04-27 20:32:18 +08:00
|
|
|
|
2016-02-22 20:18:15 +01:00
|
|
|
import org.reactivestreams.{ Subscriber, Subscription }
|
2014-11-17 22:50:15 +01:00
|
|
|
|
2020-04-27 20:32:18 +08:00
|
|
|
import akka.annotation.InternalApi
|
|
|
|
|
import akka.stream.SubscriptionWithCancelException
|
|
|
|
|
|
2014-11-19 12:56:55 +01:00
|
|
|
/**
|
|
|
|
|
* INTERNAL API
|
|
|
|
|
*/
|
2017-03-16 21:04:07 +02:00
|
|
|
@InternalApi private[stream] object ReactiveStreamsCompliance {
|
2014-08-21 16:07:09 +02:00
|
|
|
|
|
|
|
|
final val CanNotSubscribeTheSameSubscriberMultipleTimes =
|
|
|
|
|
"can not subscribe the same subscriber multiple times (see reactive-streams specification, rules 1.10 and 2.12)"
|
|
|
|
|
|
|
|
|
|
final val SupportsOnlyASingleSubscriber =
|
2021-11-19 14:39:02 +01:00
|
|
|
"only supports one subscriber (which is allowed, see reactive-streams specification, rule 1.11)"
|
2014-08-21 16:07:09 +02:00
|
|
|
|
|
|
|
|
final val NumberOfElementsInRequestMustBePositiveMsg =
|
|
|
|
|
"The number of requested elements must be > 0 (see reactive-streams specification, rule 3.9)"
|
|
|
|
|
|
2015-03-03 10:57:25 +01:00
|
|
|
final val SubscriberMustNotBeNullMsg = "Subscriber must not be null, rule 1.9"
|
2014-08-21 16:07:09 +02:00
|
|
|
|
2015-03-03 10:57:25 +01:00
|
|
|
final val ExceptionMustNotBeNullMsg = "Exception must not be null, rule 2.13"
|
|
|
|
|
|
|
|
|
|
final val ElementMustNotBeNullMsg = "Element must not be null, rule 2.13"
|
|
|
|
|
|
|
|
|
|
final val SubscriptionMustNotBeNullMsg = "Subscription must not be null, rule 2.13"
|
2014-11-17 22:50:15 +01:00
|
|
|
|
2014-12-08 23:10:04 +01:00
|
|
|
final def numberOfElementsInRequestMustBePositiveException: Throwable =
|
|
|
|
|
new IllegalArgumentException(NumberOfElementsInRequestMustBePositiveMsg)
|
|
|
|
|
|
|
|
|
|
final def canNotSubscribeTheSameSubscriberMultipleTimesException: Throwable =
|
|
|
|
|
new IllegalStateException(CanNotSubscribeTheSameSubscriberMultipleTimes)
|
|
|
|
|
|
2015-03-03 10:57:25 +01:00
|
|
|
final def subscriberMustNotBeNullException: Throwable =
|
|
|
|
|
new NullPointerException(SubscriberMustNotBeNullMsg)
|
|
|
|
|
|
|
|
|
|
final def exceptionMustNotBeNullException: Throwable =
|
|
|
|
|
new NullPointerException(ExceptionMustNotBeNullMsg)
|
|
|
|
|
|
|
|
|
|
final def elementMustNotBeNullException: Throwable =
|
|
|
|
|
new NullPointerException(ElementMustNotBeNullMsg)
|
|
|
|
|
|
|
|
|
|
final def subscriptionMustNotBeNullException: Throwable =
|
|
|
|
|
new NullPointerException(SubscriptionMustNotBeNullMsg)
|
|
|
|
|
|
|
|
|
|
final def rejectDuplicateSubscriber[T](subscriber: Subscriber[T]): Unit = {
|
|
|
|
|
// since it is already subscribed it has received the subscription first
|
|
|
|
|
// and we can emit onError immediately
|
2014-12-08 23:10:04 +01:00
|
|
|
tryOnError(subscriber, canNotSubscribeTheSameSubscriberMultipleTimesException)
|
2015-03-03 10:57:25 +01:00
|
|
|
}
|
2014-12-08 23:10:04 +01:00
|
|
|
|
2015-03-03 10:57:25 +01:00
|
|
|
final def rejectAdditionalSubscriber[T](subscriber: Subscriber[T], rejector: String): Unit = {
|
|
|
|
|
tryOnSubscribe(subscriber, CancelledSubscription)
|
2014-12-08 23:10:04 +01:00
|
|
|
tryOnError(subscriber, new IllegalStateException(s"$rejector $SupportsOnlyASingleSubscriber"))
|
2015-03-03 10:57:25 +01:00
|
|
|
}
|
2014-12-08 23:10:04 +01:00
|
|
|
|
|
|
|
|
final def rejectDueToNonPositiveDemand[T](subscriber: Subscriber[T]): Unit =
|
|
|
|
|
tryOnError(subscriber, numberOfElementsInRequestMustBePositiveException)
|
2014-11-18 23:19:30 +01:00
|
|
|
|
2015-03-03 10:57:25 +01:00
|
|
|
final def requireNonNullSubscriber[T](subscriber: Subscriber[T]): Unit =
|
|
|
|
|
if (subscriber eq null) throw subscriberMustNotBeNullException
|
|
|
|
|
|
|
|
|
|
final def requireNonNullException(cause: Throwable): Unit =
|
|
|
|
|
if (cause eq null) throw exceptionMustNotBeNullException
|
|
|
|
|
|
|
|
|
|
final def requireNonNullElement[T](element: T): Unit =
|
|
|
|
|
if (element == null) throw elementMustNotBeNullException
|
|
|
|
|
|
|
|
|
|
final def requireNonNullSubscription(subscription: Subscription): Unit =
|
|
|
|
|
if (subscription == null) throw subscriptionMustNotBeNullException
|
|
|
|
|
|
2015-02-26 11:58:29 +01:00
|
|
|
sealed trait SpecViolation extends Throwable
|
|
|
|
|
|
|
|
|
|
@SerialVersionUID(1L)
|
2019-03-11 10:38:24 +01:00
|
|
|
final class SignalThrewException(message: String, cause: Throwable)
|
|
|
|
|
extends IllegalStateException(message, cause)
|
|
|
|
|
with SpecViolation
|
2014-11-17 22:50:15 +01:00
|
|
|
|
|
|
|
|
final def tryOnError[T](subscriber: Subscriber[T], error: Throwable): Unit =
|
2014-11-18 23:19:30 +01:00
|
|
|
error match {
|
2019-03-11 10:38:24 +01:00
|
|
|
case sv: SpecViolation =>
|
|
|
|
|
throw new IllegalStateException("It is not legal to try to signal onError with a SpecViolation", sv)
|
2019-02-09 15:25:39 +01:00
|
|
|
case other =>
|
2019-03-11 10:38:24 +01:00
|
|
|
try subscriber.onError(other)
|
|
|
|
|
catch {
|
2019-04-05 13:06:33 +02:00
|
|
|
case NonFatal(t) => throw new SignalThrewException(s"${subscriber}.onError", t)
|
2014-11-18 23:19:30 +01:00
|
|
|
}
|
2014-11-17 22:50:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-03 10:57:25 +01:00
|
|
|
final def tryOnNext[T](subscriber: Subscriber[T], element: T): Unit = {
|
|
|
|
|
requireNonNullElement(element)
|
2019-03-11 10:38:24 +01:00
|
|
|
try subscriber.onNext(element)
|
|
|
|
|
catch {
|
2019-04-05 13:06:33 +02:00
|
|
|
case NonFatal(t) => throw new SignalThrewException(s"${subscriber}.onNext", t)
|
2014-11-17 22:50:15 +01:00
|
|
|
}
|
2015-03-03 10:57:25 +01:00
|
|
|
}
|
2014-11-17 22:50:15 +01:00
|
|
|
|
2015-03-03 10:57:25 +01:00
|
|
|
final def tryOnSubscribe[T](subscriber: Subscriber[T], subscription: Subscription): Unit = {
|
2019-03-11 10:38:24 +01:00
|
|
|
try subscriber.onSubscribe(subscription)
|
|
|
|
|
catch {
|
2019-04-05 13:06:33 +02:00
|
|
|
case NonFatal(t) => throw new SignalThrewException(s"${subscriber}.onSubscribe", t)
|
2014-11-17 22:50:15 +01:00
|
|
|
}
|
2015-03-03 10:57:25 +01:00
|
|
|
}
|
2014-11-17 22:50:15 +01:00
|
|
|
|
2015-06-17 16:34:05 +02:00
|
|
|
final def tryOnComplete[T](subscriber: Subscriber[T]): Unit = {
|
2019-03-11 10:38:24 +01:00
|
|
|
try subscriber.onComplete()
|
|
|
|
|
catch {
|
2019-04-05 13:06:33 +02:00
|
|
|
case NonFatal(t) => throw new SignalThrewException(s"${subscriber}.onComplete", t)
|
2014-11-17 22:50:15 +01:00
|
|
|
}
|
2015-06-17 16:34:05 +02:00
|
|
|
}
|
|
|
|
|
|
2015-06-19 17:15:50 +02:00
|
|
|
final def tryRequest(subscription: Subscription, demand: Long): Unit = {
|
2019-03-11 10:38:24 +01:00
|
|
|
if (subscription eq null)
|
|
|
|
|
throw new IllegalStateException("Subscription must be not null on request() call, rule 1.3")
|
|
|
|
|
try subscription.request(demand)
|
|
|
|
|
catch {
|
|
|
|
|
case NonFatal(t) =>
|
|
|
|
|
throw new SignalThrewException("It is illegal to throw exceptions from request(), rule 3.16", t)
|
2015-06-17 16:34:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 10:53:14 +02:00
|
|
|
final def tryCancel(subscription: Subscription, cause: Throwable): Unit = {
|
2019-03-11 10:38:24 +01:00
|
|
|
if (subscription eq null)
|
|
|
|
|
throw new IllegalStateException("Subscription must be not null on cancel() call, rule 1.3")
|
2019-08-16 10:53:14 +02:00
|
|
|
try subscription match {
|
|
|
|
|
case s: SubscriptionWithCancelException => s.cancel(cause)
|
|
|
|
|
case s => s.cancel()
|
|
|
|
|
} catch {
|
2019-03-11 10:38:24 +01:00
|
|
|
case NonFatal(t) =>
|
|
|
|
|
throw new SignalThrewException("It is illegal to throw exceptions from cancel(), rule 3.15", t)
|
2015-06-17 16:34:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-21 16:07:09 +02:00
|
|
|
}
|