/*
* Copyright 2012-2015, the original author or authors.
*
* 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 com.flipkart.phantom.runtime.impl.server.netty;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.Timer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* <code>ChannelHandlerPipelineFactory</code> is an implementation of the {@link ChannelPipelineFactory} that creates a default channel pipeline.
* Allows setting up a chain of channel handlers configured on this factory. Additionally sets up handlers to process idle state on the channel, if specified.
* This factory also implements the Spring {@link ApplicationContextAware} interface so that it may create new instances for handlers for every call to
* {@link ChannelPipelineFactory#getPipeline()}
*
* @author Regunath B
* @version 1.0, 15 Mar 2013
*/
public class ChannelHandlerPipelineFactory implements ChannelPipelineFactory, ApplicationContextAware {
/** The default idle check time in milliseconds*/
private static final long DFFAULT_IDLE_TIME_MILLIS = 200;
/** The channel idle time*/
private long channelIdleTimeMillis = DFFAULT_IDLE_TIME_MILLIS;
/** Logger for this class*/
private static final Logger LOGGER = LoggerFactory.getLogger(ChannelHandlerPipelineFactory.class);
/** The Timer for idle time checking*/ // this is set using Spring DI. The timer is however stopped when #close() is called to ensure that it exits
private Timer timer;
/** The IdleStateAwareChannelHandler bean name to handle channel timeouts*/
private String idleStateAwareChannelHandlerBean;
/** The ApplicationContext instance for instantiating ChannelHandlers*/
private ApplicationContext applicationContext;
/** Map of channel handler names and bean names to add to the pipeline*/
private Map<String, String> channelHandlerBeanNamesMap = new HashMap<String, String>();
/**
* Interface call back method. Stores the passed in ApplicationContext for ChannelHandler instantiation in {@link #getPipeline()}
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* Interface implementation. Creates a default channel pipeline and sets up timeout handlers, if specified
* @see org.jboss.netty.channel.ChannelPipelineFactory#getPipeline()
*/
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline channelPipeline = Channels.pipeline();
if (this.getIdleStateAwareChannelHandlerBean()!= null) {
channelPipeline.addLast("idleStateCheck", new IdleStateHandler(timer, 0L, 0L, this.getChannelIdleTimeMillis(),TimeUnit.MILLISECONDS));
channelPipeline.addLast("idleCheckHandler", (ChannelHandler)this.applicationContext.getBean(this.getIdleStateAwareChannelHandlerBean()));
}
for (String handlerKey : this.getChannelHandlerBeanNamesMap().keySet()) {
channelPipeline.addLast(handlerKey, (ChannelHandler)this.applicationContext.getBean(this.getChannelHandlerBeanNamesMap().get(handlerKey)));
}
return channelPipeline;
}
/**
* Closes this ChannelPipelineFactory and releases all external resources
*/
public void close() {
if (this.getTimer() != null) {
LOGGER.debug("Closing ChannelPipelineFactory : {}", this.getClass().getName());
this.getTimer().stop(); // stop the Timer here explicitly
}
}
/**
* Returns a Map containing ChannelHandler instances
* @return Map containing ChannelHandler instances keyed by the handler bean Ids
*/
public Map<String,ChannelHandler> getChannelHandlersMap() {
Map<String,ChannelHandler> channelHandlersMap = new HashMap<String,ChannelHandler>();
for (String handlerKey : this.getChannelHandlerBeanNamesMap().keySet()) {
channelHandlersMap.put(handlerKey, (ChannelHandler)this.applicationContext.getBean(this.getChannelHandlerBeanNamesMap().get(handlerKey)));
}
return channelHandlersMap;
}
/**
* Returns a string containing bean names of ChannelHandlers in the ChannelPipelin created by this pipeline factory
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer buffer = new StringBuffer("Registered Channel Handlers[");
if (this.getIdleStateAwareChannelHandlerBean()!= null) {
buffer.append("idleStateCheck,");
buffer.append("idleCheckHandler,");
}
for (String handlerKey : this.getChannelHandlerBeanNamesMap().keySet()) {
buffer.append(handlerKey + ",");
}
buffer.append("]");
return buffer.toString();
}
/** Start Getter/Setter methods */
public long getChannelIdleTimeMillis() {
return this.channelIdleTimeMillis;
}
public void setChannelIdleTimeMillis(long channelIdleTimeMillis) {
this.channelIdleTimeMillis = channelIdleTimeMillis;
}
public Timer getTimer() {
return this.timer;
}
public void setTimer(Timer timer) {
this.timer = timer;
}
public String getIdleStateAwareChannelHandlerBean() {
return this.idleStateAwareChannelHandlerBean;
}
public void setIdleStateAwareChannelHandlerBean(String idleStateAwareChannelHandlerBean) {
this.idleStateAwareChannelHandlerBean = idleStateAwareChannelHandlerBean;
}
public Map<String, String> getChannelHandlerBeanNamesMap() {
return this.channelHandlerBeanNamesMap;
}
public void setChannelHandlerBeanNamesMap(Map<String, String> channelHandlerBeanNamesMap) {
this.channelHandlerBeanNamesMap = channelHandlerBeanNamesMap;
}
/** End Getter/Setter methods */
}