package com.tacitknowledge.slowlight.proxyserver.server; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.tacitknowledge.slowlight.proxyserver.config.HandlerConfig; import com.tacitknowledge.slowlight.proxyserver.config.ServerConfig; import com.tacitknowledge.slowlight.proxyserver.handler.AbstractChannelHandler; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * DynamicChannelInitializer stays at the heart of the slow-light server * and allows dynamic (configuration based) channel pipeline construction. * Base on the given configuration it will instantiate and initialize channel handlers * and then will add them to the pipeline in the order handlers are defined. * * @author Alexandr Donciu (adonciu@tacitknowledge.com) * */ public class DynamicChannelInitializer extends ChannelInitializer { private static final Logger LOG = LoggerFactory.getLogger(DynamicChannelInitializer.class); protected final ServerConfig serverConfig; private final Lock cacheLock = new ReentrantLock(); private final Map<String, AbstractChannelHandler> cachedHandlers = new HashMap<String, AbstractChannelHandler>(); public DynamicChannelInitializer(final ServerConfig serverConfig) { this.serverConfig = serverConfig; } @Override protected void initChannel(Channel ch) throws Exception { final ChannelPipeline pipeline = ch.pipeline(); final Map<String, AbstractChannelHandler> channelHandlers = getChannelHandlers(); for (final String channelHandlerName : channelHandlers.keySet()) { pipeline.addFirst(channelHandlerName, channelHandlers.get(channelHandlerName)); } } private Map<String, AbstractChannelHandler> getChannelHandlers() { final Map<String, AbstractChannelHandler> channelHandler = Maps.newLinkedHashMap(); for (HandlerConfig handlerConfig : Lists.reverse(serverConfig.getHandlers())) { try { AbstractChannelHandler handler = getChannelHandler(handlerConfig); channelHandler.put(handlerConfig.getName(), handler); } catch (Exception e) { LOG.error("Cannot create channel handler [{}]", handlerConfig.getName(), e); } } return channelHandler; } private AbstractChannelHandler getChannelHandler(final HandlerConfig handlerConfig) throws ClassNotFoundException, InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException, NoSuchMethodException { AbstractChannelHandler handler = null; cacheLock.lock(); try { handler = cachedHandlers.get(handlerConfig.getName()); if (handler == null) { handler = createChannelHandler(handlerConfig); if (handlerConfig.isReusable()) { cachedHandlers.put(handlerConfig.getName(), handler); } } } finally { cacheLock.unlock(); } return handler; } protected AbstractChannelHandler createChannelHandler(final HandlerConfig handlerConfig) throws ClassNotFoundException, InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException, NoSuchMethodException { final Class<?> handlerClass = Class.forName(handlerConfig.getType()); return (AbstractChannelHandler) handlerClass.getConstructor(HandlerConfig.class).newInstance(handlerConfig); } }