/*
* Copyright 2016 Netflix, Inc.
*
* Licensed 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 io.reactivex.netty.channel;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.FileRegion;
import io.netty.util.concurrent.EventExecutorGroup;
import io.reactivex.netty.channel.events.ConnectionEventListener;
import io.reactivex.netty.events.EventAttributeKeys;
import io.reactivex.netty.events.EventPublisher;
import rx.Observable;
import rx.Observable.Transformer;
import rx.functions.Action1;
import rx.functions.Func1;
/**
* An implementation of {@link Connection} delegating all {@link ChannelOperations} methods to
* {@link DefaultChannelOperations}.
*/
public final class ConnectionImpl<R, W> extends Connection<R, W> {
private final ChannelOperations<W> delegate;
private ConnectionImpl(Channel nettyChannel, ConnectionEventListener eventListener, EventPublisher eventPublisher) {
super(nettyChannel);
delegate = new DefaultChannelOperations<>(nettyChannel, eventListener, eventPublisher);
}
private ConnectionImpl(Channel nettyChannel, ChannelOperations<W> delegate) {
super(nettyChannel);
this.delegate = delegate;
}
private ConnectionImpl(ConnectionImpl<?, ?> toCopy, ContentSource<R> contentSource, ChannelOperations<W> delegate) {
super(toCopy, contentSource);
this.delegate = delegate;
}
@Override
public Observable<Void> write(Observable<W> msgs) {
return delegate.write(msgs);
}
@Override
public Observable<Void> write(Observable<W> msgs, Func1<W, Boolean> flushSelector) {
return delegate.write(msgs, flushSelector);
}
@Override
public Observable<Void> writeAndFlushOnEach(Observable<W> msgs) {
return delegate.writeAndFlushOnEach(msgs);
}
@Override
public Observable<Void> writeString(Observable<String> msgs) {
return delegate.writeString(msgs);
}
@Override
public Observable<Void> writeString(Observable<String> msgs, Func1<String, Boolean> flushSelector) {
return delegate.writeString(msgs, flushSelector);
}
@Override
public Observable<Void> writeStringAndFlushOnEach(Observable<String> msgs) {
return delegate.writeStringAndFlushOnEach(msgs);
}
@Override
public Observable<Void> writeBytes(Observable<byte[]> msgs) {
return delegate.writeBytes(msgs);
}
@Override
public Observable<Void> writeBytes(Observable<byte[]> msgs,
Func1<byte[], Boolean> flushSelector) {
return delegate.writeBytes(msgs, flushSelector);
}
@Override
public Observable<Void> writeBytesAndFlushOnEach(Observable<byte[]> msgs) {
return delegate.writeBytesAndFlushOnEach(msgs);
}
@Override
public Observable<Void> writeFileRegion(Observable<FileRegion> msgs) {
return delegate.writeFileRegion(msgs);
}
@Override
public Observable<Void> writeFileRegion(Observable<FileRegion> msgs,
Func1<FileRegion, Boolean> flushSelector) {
return delegate.writeFileRegion(msgs, flushSelector);
}
@Override
public Observable<Void> writeFileRegionAndFlushOnEach(Observable<FileRegion> msgs) {
return delegate.writeFileRegionAndFlushOnEach(msgs);
}
@Override
public void flush() {
delegate.flush();
}
@Override
public Observable<Void> close() {
return delegate.close();
}
@Override
public Observable<Void> close(boolean flush) {
return delegate.close(flush);
}
@Override
public void closeNow() {
delegate.closeNow();
}
@Override
public Observable<Void> closeListener() {
return delegate.closeListener();
}
public static <R, W> ConnectionImpl<R, W> fromChannel(Channel nettyChannel) {
EventPublisher ep = nettyChannel.attr(EventAttributeKeys.EVENT_PUBLISHER).get();
if (null == ep) {
throw new IllegalArgumentException("No event publisher set in the channel.");
}
ConnectionEventListener l = null;
if (ep.publishingEnabled()) {
l = nettyChannel.attr(EventAttributeKeys.CONNECTION_EVENT_LISTENER).get();
if (null == l) {
throw new IllegalArgumentException("No event listener set in the channel.");
}
}
final ConnectionImpl<R, W> toReturn = new ConnectionImpl<>(nettyChannel, l, ep);
toReturn.connectCloseToChannelClose();
return toReturn;
}
/*Visible for testing*/static <R, W> ConnectionImpl<R, W> create(Channel nettyChannel,
ChannelOperations<W> delegate) {
final ConnectionImpl<R, W> toReturn = new ConnectionImpl<>(nettyChannel, delegate);
toReturn.connectCloseToChannelClose();
return toReturn;
}
@Override
public <RR, WW> Connection<RR, WW> addChannelHandlerFirst(String name, ChannelHandler handler) {
getResettableChannelPipeline().markIfNotYetMarked().addFirst(name, handler);
return cast();
}
@Override
public <RR, WW> Connection<RR, WW> addChannelHandlerFirst(EventExecutorGroup group, String name,
ChannelHandler handler) {
getResettableChannelPipeline().markIfNotYetMarked().addFirst(group, name, handler);
return cast();
}
@Override
public <RR, WW> Connection<RR, WW> addChannelHandlerLast(String name, ChannelHandler handler) {
getResettableChannelPipeline().markIfNotYetMarked().addLast(name, handler);
return cast();
}
@Override
public <RR, WW> Connection<RR, WW> addChannelHandlerLast(EventExecutorGroup group, String name,
ChannelHandler handler) {
getResettableChannelPipeline().markIfNotYetMarked().addLast(group, name, handler);
return cast();
}
@Override
public <RR, WW> Connection<RR, WW> addChannelHandlerBefore(String baseName, String name, ChannelHandler handler) {
getResettableChannelPipeline().markIfNotYetMarked().addBefore(baseName, name, handler);
return cast();
}
@Override
public <RR, WW> Connection<RR, WW> addChannelHandlerBefore(EventExecutorGroup group, String baseName, String name,
ChannelHandler handler) {
getResettableChannelPipeline().markIfNotYetMarked().addBefore(group, baseName, name, handler);
return cast();
}
@Override
public <RR, WW> Connection<RR, WW> addChannelHandlerAfter(String baseName, String name, ChannelHandler handler) {
getResettableChannelPipeline().markIfNotYetMarked().addAfter(baseName, name, handler);
return cast();
}
@Override
public <RR, WW> Connection<RR, WW> addChannelHandlerAfter(EventExecutorGroup group, String baseName, String name,
ChannelHandler handler) {
getResettableChannelPipeline().markIfNotYetMarked().addAfter(group, baseName, name, handler);
return cast();
}
@Override
public <RR, WW> Connection<RR, WW> pipelineConfigurator(Action1<ChannelPipeline> pipelineConfigurator) {
pipelineConfigurator.call(getResettableChannelPipeline().markIfNotYetMarked());
return cast();
}
@Override
public <RR> Connection<RR, W> transformRead(Transformer<R, RR> transformer) {
return new ConnectionImpl<>(this, getInput().transform(transformer), delegate);
}
@Override
public <WW> Connection<R, WW> transformWrite(AllocatingTransformer<WW, W> transformer) {
return new ConnectionImpl<>(this, getInput(), delegate.transformWrite(transformer));
}
@SuppressWarnings("unchecked")
protected <RR, WW> Connection<RR, WW> cast() {
return (Connection<RR, WW>) this;
}
}