/** * 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 org.apache.camel.component.reactive.streams.util; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.camel.Exchange; import org.apache.camel.TypeConversionException; import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A publisher that converts Camel {@code Exchange}s into the given type. */ public class ConvertingPublisher<R> implements Publisher<R> { private static final Logger LOG = LoggerFactory.getLogger(ConvertingPublisher.class); private Publisher<Exchange> delegate; private Class<R> type; private BodyConverter<R> converter; public ConvertingPublisher(Publisher<Exchange> delegate, Class<R> type) { Objects.requireNonNull(delegate, "delegate publisher cannot be null"); Objects.requireNonNull(type, "type cannot be null"); this.delegate = delegate; this.type = type; this.converter = BodyConverter.forType(type); } @Override public void subscribe(Subscriber<? super R> subscriber) { delegate.subscribe(new Subscriber<Exchange>() { private AtomicBoolean active = new AtomicBoolean(true); private Subscription subscription; @Override public void onSubscribe(Subscription newSubscription) { if (newSubscription == null) { throw new NullPointerException("subscription is null"); } else if (newSubscription == this.subscription) { throw new IllegalArgumentException("already subscribed to the subscription: " + newSubscription); } if (this.subscription != null) { newSubscription.cancel(); } else { this.subscription = newSubscription; subscriber.onSubscribe(newSubscription); } } @Override public void onNext(Exchange ex) { if (!active.get()) { return; } R r; try { r = converter.apply(ex); } catch (TypeConversionException e) { LOG.warn("Unable to convert body to the specified type: " + type.getName(), e); r = null; } if (r == null && ex.getIn().getBody() != null) { this.onError(new ClassCastException("Unable to convert body to the specified type: " + type.getName())); active.set(false); subscription.cancel(); } else { subscriber.onNext(r); } } @Override public void onError(Throwable throwable) { if (!active.get()) { return; } subscriber.onError(throwable); } @Override public void onComplete() { if (!active.get()) { return; } subscriber.onComplete(); } }); } }