Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package com.datastax.dse.driver.internal.mapper.reactive;
import com.datastax.dse.driver.api.core.cql.reactive.ReactiveResultSet;
import com.datastax.dse.driver.api.core.cql.reactive.ReactiveRow;
import com.datastax.dse.driver.api.mapper.reactive.MappedReactiveResultSet;
import com.datastax.oss.driver.api.core.cql.ColumnDefinitions;
import com.datastax.oss.driver.api.core.cql.ExecutionInfo;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Objects;
import java.util.function.Function;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DefaultMappedReactiveResultSet implements MappedReactiveResultSet {
private static final Logger LOG = LoggerFactory.getLogger(DefaultMappedReactiveResultSet.class);
private static final Subscription EMPTY_SUBSCRIPTION =
new Subscription() {
@Override
public void request(long n) {}
@Override
public void cancel() {}
};
@NonNull private final ReactiveResultSet source;
@NonNull private final Function mapper;
public DefaultMappedReactiveResultSet(
@NonNull ReactiveResultSet source, @NonNull Function mapper) {
this.source = source;
this.mapper = mapper;
}
@Override
@NonNull
public Publisher extends ColumnDefinitions> getColumnDefinitions() {
return source.getColumnDefinitions();
}
@Override
@NonNull
public Publisher extends ExecutionInfo> getExecutionInfos() {
return source.getExecutionInfos();
}
@Override
@NonNull
public Publisher wasApplied() {
return source.wasApplied();
}
@Override
public void subscribe(@NonNull Subscriber super EntityT> subscriber) {
// As per rule 1.9, we need to throw an NPE if subscriber is null
Objects.requireNonNull(subscriber, "Subscriber cannot be null");
// As per rule 1.11, this publisher supports multiple subscribers in a unicast configuration,
// as long as the source publisher does too.
MappedReactiveResultSetSubscriber s = new MappedReactiveResultSetSubscriber(subscriber);
try {
source.subscribe(s);
} catch (Throwable t) {
// As per rule 1.9: subscribe MUST return normally. The only legal way to signal failure (or
// reject the Subscriber) is by calling onError (after calling onSubscribe).
s.cancel();
IllegalStateException error =
new IllegalStateException(
"Publisher violated $1.9 by throwing an exception from subscribe.", t);
LOG.error(error.getMessage(), error.getCause());
// This may violate 1.9 since we cannot know if subscriber.onSubscribe was called or not.
subscriber.onSubscribe(EMPTY_SUBSCRIPTION);
subscriber.onError(error);
}
// As per 1.9, this method must return normally (i.e. not throw)
}
private class MappedReactiveResultSetSubscriber implements Subscriber, Subscription {
private volatile Subscriber super EntityT> downstreamSubscriber;
private volatile Subscription upstreamSubscription;
private volatile boolean terminated;
MappedReactiveResultSetSubscriber(@NonNull Subscriber super EntityT> subscriber) {
this.downstreamSubscriber = subscriber;
}
@Override
public void onSubscribe(@NonNull Subscription subscription) {
// As per rule 2.13, we need to throw NPE if the subscription is null
Objects.requireNonNull(subscription, "Subscription cannot be null");
// As per rule 2.12, Subscriber.onSubscribe MUST be called at most once for a given subscriber
if (upstreamSubscription != null) {
try {
// Cancel the additional subscription
subscription.cancel();
} catch (Throwable t) {
// As per rule 3.15, Subscription.cancel is not allowed to throw an exception; the only
// thing we can do is log.
LOG.error("Subscription violated $3.15 by throwing an exception from cancel.", t);
}
} else if (!terminated) {
upstreamSubscription = subscription;
try {
downstreamSubscriber.onSubscribe(this);
} catch (Throwable t) {
// As per rule 2.13: In the case that this rule is violated,
// any associated Subscription to the Subscriber MUST be considered as
// cancelled...
cancel();
// ...and the caller MUST raise this error condition in a fashion that is "adequate for
// the runtime environment" (we choose to log).
LOG.error("Subscriber violated $2.13 by throwing an exception from onSubscribe.", t);
}
}
}
@Override
public void onNext(@NonNull ReactiveRow row) {
LOG.trace("Received onNext: {}", row);
if (upstreamSubscription == null) {
LOG.error("Publisher violated $1.09 by signalling onNext prior to onSubscribe.");
} else if (!terminated) {
Objects.requireNonNull(row, "Publisher violated $2.13 by emitting a null element");
EntityT entity;
try {
entity = mapper.apply(row);
} catch (Throwable t) {
onError(t);
return;
}
Objects.requireNonNull(entity, "Publisher violated $2.13 by generating a null entity");
try {
downstreamSubscriber.onNext(entity);
} catch (Throwable t) {
LOG.error("Subscriber violated $2.13 by throwing an exception from onNext.", t);
cancel();
}
}
}
@Override
public void onComplete() {
LOG.trace("Received onComplete");
if (upstreamSubscription == null) {
LOG.error("Publisher violated $1.09 by signalling onComplete prior to onSubscribe.");
} else if (!terminated) {
try {
downstreamSubscriber.onComplete();
} catch (Throwable t) {
LOG.error("Subscriber violated $2.13 by throwing an exception from onComplete.", t);
}
// We need to consider this Subscription as cancelled as per rule 1.6
cancel();
}
}
@Override
public void onError(@NonNull Throwable error) {
LOG.trace("Received onError", error);
if (upstreamSubscription == null) {
LOG.error("Publisher violated $1.09 by signalling onError prior to onSubscribe.");
} else if (!terminated) {
Objects.requireNonNull(error, "Publisher violated $2.13 by signalling a null error");
try {
downstreamSubscriber.onError(error);
} catch (Throwable t) {
t.addSuppressed(error);
LOG.error("Subscriber violated $2.13 by throwing an exception from onError.", t);
}
// We need to consider this Subscription as cancelled as per rule 1.6
cancel();
}
}
@Override
public void request(long n) {
LOG.trace("Received request: {}", n);
// As per 3.6: after the Subscription is cancelled, additional calls to request() MUST be
// NOPs.
// Implementation note: triggering onError() from below may break 1.3 because this method is
// called by the subscriber thread, and it can race with the producer thread. But these
// situations are already abnormal, so there is no point in trying to prevent the race
// condition with locks.
if (!terminated) {
if (n <= 0) {
// Validate request as per rule 3.9: While the subscription is not cancelled,
// Subscription.request(long n) MUST signal onError with a
// java.lang.IllegalArgumentException if the argument is <= 0.
// The cause message SHOULD explain that non-positive request signals are illegal.
onError(
new IllegalArgumentException(
"Subscriber violated $3.9 by requesting a non-positive number of elements."));
} else {
try {
upstreamSubscription.request(n);
} catch (Throwable t) {
// As per rule 3.16, Subscription.request is not allowed to throw
IllegalStateException error =
new IllegalStateException(
"Subscription violated $3.16 by throwing an exception from request.", t);
onError(error);
}
}
}
}
@Override
public void cancel() {
// As per 3.5: Subscription.cancel() MUST respect the responsiveness of its caller by
// returning in a timely manner, MUST be idempotent and MUST be thread-safe.
if (!terminated) {
terminated = true;
LOG.trace("Cancelling");
// propagate cancellation, if we got a chance to subscribe to the upstream source
if (upstreamSubscription != null) {
upstreamSubscription.cancel();
}
// As per 3.13, Subscription.cancel() MUST request the Publisher to
// eventually drop any references to the corresponding subscriber.
downstreamSubscriber = null;
upstreamSubscription = null;
}
}
}
}