/* * 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.server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.ServerChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.util.concurrent.EventExecutorGroup; import io.reactivex.netty.HandlerNames; import io.reactivex.netty.channel.DetachedChannelPipeline; import io.reactivex.netty.channel.WriteTransformer; import rx.functions.Action1; import rx.functions.Func0; import java.net.SocketAddress; /** * A collection of state that a server holds. * * @param <R> The type of objects read from the server owning this state. * @param <W> The type of objects written to the server owning this state. */ public abstract class ServerState<R, W> { protected final SocketAddress socketAddress; protected final ServerBootstrap bootstrap; protected final DetachedChannelPipeline detachedPipeline; protected ServerState(SocketAddress socketAddress, EventLoopGroup parent, EventLoopGroup child, Class<? extends ServerChannel> channelClass) { this.socketAddress = socketAddress; bootstrap = new ServerBootstrap(); bootstrap.childOption(ChannelOption.AUTO_READ, false); // by default do not read content unless asked. bootstrap.group(parent, child); bootstrap.channel(channelClass); detachedPipeline = new DetachedChannelPipeline(); detachedPipeline.addLast(HandlerNames.WriteTransformer.getName(), new Func0<ChannelHandler>() { @Override public ChannelHandler call() { return new WriteTransformer(); } }); bootstrap.childHandler(detachedPipeline.getChannelInitializer()); } protected ServerState(ServerState<R, W> toCopy, final ServerBootstrap newBootstrap) { socketAddress = toCopy.socketAddress; bootstrap = newBootstrap; detachedPipeline = toCopy.detachedPipeline; bootstrap.childHandler(detachedPipeline.getChannelInitializer()); } protected ServerState(ServerState<?, ?> toCopy, final DetachedChannelPipeline newPipeline) { final ServerState<R, W> toCopyCast = toCopy.cast(); socketAddress = toCopy.socketAddress; bootstrap = toCopyCast.bootstrap.clone(); detachedPipeline = newPipeline; bootstrap.childHandler(detachedPipeline.getChannelInitializer()); } protected ServerState(ServerState<R, W> toCopy, final SocketAddress socketAddress) { this.socketAddress = socketAddress; bootstrap = toCopy.bootstrap.clone(); detachedPipeline = toCopy.detachedPipeline; bootstrap.childHandler(detachedPipeline.getChannelInitializer()); } public <T> ServerState<R, W> channelOption(ChannelOption<T> option, T value) { ServerState<R, W> copy = copyBootstrapOnly(); copy.bootstrap.option(option, value); return copy; } public <T> ServerState<R, W> clientChannelOption(ChannelOption<T> option, T value) { ServerState<R, W> copy = copyBootstrapOnly(); copy.bootstrap.childOption(option, value); return copy; } public <RR, WW> ServerState<RR, WW> addChannelHandlerFirst(String name, Func0<ChannelHandler> handlerFactory) { ServerState<RR, WW> copy = copy(); copy.detachedPipeline.addFirst(name, handlerFactory); return copy; } public <RR, WW> ServerState<RR, WW> addChannelHandlerFirst(EventExecutorGroup group, String name, Func0<ChannelHandler> handlerFactory) { ServerState<RR, WW> copy = copy(); copy.detachedPipeline.addFirst(group, name, handlerFactory); return copy; } public <RR, WW> ServerState<RR, WW> addChannelHandlerLast(String name, Func0<ChannelHandler> handlerFactory) { ServerState<RR, WW> copy = copy(); copy.detachedPipeline.addLast(name, handlerFactory); return copy; } public <RR, WW> ServerState<RR, WW> addChannelHandlerLast(EventExecutorGroup group, String name, Func0<ChannelHandler> handlerFactory) { ServerState<RR, WW> copy = copy(); copy.detachedPipeline.addLast(group, name, handlerFactory); return copy; } public <RR, WW> ServerState<RR, WW> addChannelHandlerBefore(String baseName, String name, Func0<ChannelHandler> handlerFactory) { ServerState<RR, WW> copy = copy(); copy.detachedPipeline.addBefore(baseName, name, handlerFactory); return copy; } public <RR, WW> ServerState<RR, WW> addChannelHandlerBefore(EventExecutorGroup group, String baseName, String name, Func0<ChannelHandler> handlerFactory) { ServerState<RR, WW> copy = copy(); copy.detachedPipeline.addBefore(group, baseName, name, handlerFactory); return copy; } public <RR, WW> ServerState<RR, WW> addChannelHandlerAfter(String baseName, String name, Func0<ChannelHandler> handlerFactory) { ServerState<RR, WW> copy = copy(); copy.detachedPipeline.addAfter(baseName, name, handlerFactory); return copy; } public <RR, WW> ServerState<RR, WW> addChannelHandlerAfter(EventExecutorGroup group, String baseName, String name, Func0<ChannelHandler> handlerFactory) { ServerState<RR, WW> copy = copy(); copy.detachedPipeline.addAfter(group, baseName, name, handlerFactory); return copy; } public <RR, WW> ServerState<RR, WW> pipelineConfigurator(Action1<ChannelPipeline> pipelineConfigurator) { ServerState<RR, WW> copy = copy(); copy.detachedPipeline.configure(pipelineConfigurator); return copy; } public ServerState<R, W> enableWireLogging(final LogLevel wireLoggingLevel) { return enableWireLogging(LoggingHandler.class.getName(), wireLoggingLevel); } public ServerState<R, W> enableWireLogging(final String name, final LogLevel wireLoggingLevel) { return addChannelHandlerFirst(HandlerNames.WireLogging.getName(), new Func0<ChannelHandler>() { @Override public ChannelHandler call() { return new LoggingHandler(name, wireLoggingLevel); } }); } public ServerState<R, W> serverAddress(SocketAddress socketAddress) { return copy(socketAddress); } public SocketAddress getServerAddress() { return socketAddress; } /*package private. Should not leak as it is mutable*/ ServerBootstrap getBootstrap() { return bootstrap; } protected abstract ServerState<R, W> copyBootstrapOnly(); protected abstract <RR, WW> ServerState<RR, WW> copy(); protected abstract ServerState<R, W> copy(SocketAddress newSocketAddress); @SuppressWarnings("unchecked") private <RR, WW> ServerState<RR, WW> cast() { return (ServerState<RR, WW>) this; } }