All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tacitknowledge.slowlight.proxyserver.handler.AbstractChannelHandler Maven / Gradle / Ivy

The newest version!
package com.tacitknowledge.slowlight.proxyserver.handler;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.MapConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tacitknowledge.slowlight.proxyserver.config.BehaviorFunctionConfig;
import com.tacitknowledge.slowlight.proxyserver.config.HandlerConfig;
import com.tacitknowledge.slowlight.proxyserver.handler.behavior.BehaviorFunction;

/**
 * Implementation of slow-light abstract handler.
 * Use this abstract handler as extension point for all existing and future handlers.
 *
 * @author Alexandr Donciu ([email protected])
 */
@ChannelHandler.Sharable
public abstract class AbstractChannelHandler extends ChannelDuplexHandler
{
    public static final String TIME_FRAME = "timeFrame";
    public static final int ZERO_TIME_FRAME = 0;

    private static final Logger LOG = LoggerFactory.getLogger(AbstractChannelHandler.class);

    protected AbstractConfiguration handlerParams = new MapConfiguration(new HashMap());

    protected HandlerConfig handlerConfig;

    protected Map behaviorFunctions = new HashMap();

    public AbstractChannelHandler(final HandlerConfig handlerConfig)
    {
        this.handlerConfig = handlerConfig;

        initBehaviorFunctions();
        initTimeFrameTask();

        registerHandlerConfig();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
    {
        LOG.error("Error occurred while executing channel handler", cause);

        closeOnFlush(ctx.channel());
    }

    /**
     * Flush all pending messages and then close the channel.
     *
     * @param channel the channel to be actioned
     */
    public void closeOnFlush(Channel channel)
    {
        if (channel != null && channel.isActive())
        {
            channel.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        }
    }

    /**
     * Gets the current handler time frame configuration.
     *
     * @return time frame configuration (in seconds)
     */
    protected long getTimeFrame()
    {
        final String timeFrameProp = handlerConfig.getParam(TIME_FRAME, false);
        return timeFrameProp == null ? ZERO_TIME_FRAME : Long.parseLong(timeFrameProp);
    }

    /**
     * This callback method gets invoked per each time frame.
     * Use it to do any handler time dependent changes (e.g. update handler parameters, expose metrics, etc.)
     */
    protected void timerCallback()
    {
        // EMPTY
    }

    /**
     * Override this method in a concrete handler to lookup, transform and populate all required parameters.
     */
    protected void populateHandlerParams()
    {
        // EMPTY
    }

    /**
     * Cycles through all defined behaviour function {@link com.tacitknowledge.slowlight.proxyserver.handler.behavior.IntervalBehaviorFunction}
     * and evaluates handler parameters based on function result.
     */
    protected void evaluateBehaviorFunctions()
    {
        for (final BehaviorFunctionConfig behaviorFunctionConfig : handlerConfig.getBehaviorFunctions())
        {
			final BehaviorFunction behaviorFunction = behaviorFunctions.get(behaviorFunctionConfig.getId());

			if (behaviorFunction.shouldEvaluate(behaviorFunctionConfig)) {
				handlerParams.setProperty(
				        behaviorFunctionConfig.getParamName(), behaviorFunction
				                .evaluate(behaviorFunctionConfig.getParams()));
			}
        }
    }

    private void initTimeFrameTask()
    {
        new TimeFrameTask().start();
    }

    private void registerHandlerConfig()
    {
        populateHandlerParams();

        if (!handlerParams.isEmpty())
        {
            HandlerConfigManager.registerConfigMBean(handlerConfig, handlerParams);
        }
    }

    private void initBehaviorFunctions()
    {
        for (final BehaviorFunctionConfig behaviorFunctionConfig : handlerConfig.getBehaviorFunctions())
        {
            if (!handlerConfig.getParams().containsKey(behaviorFunctionConfig.getParamName()))
            {
                throw new IllegalArgumentException("Cannot map behavior function to specified handler param ["
                        + behaviorFunctionConfig.getParamName() + "] because it doesn't exists ");
            }

			behaviorFunctions.put(behaviorFunctionConfig.getId(), createBehaviorFunction(behaviorFunctionConfig));
        }
    }

    private BehaviorFunction createBehaviorFunction(final BehaviorFunctionConfig config)
    {
        try
        {
            final Class behaviorFunctionClass = Class.forName(config.getType());
			return (BehaviorFunction) behaviorFunctionClass.getConstructor()
			        .newInstance();
        }
        catch (Exception e)
        {
            throw new IllegalArgumentException("Cannot create behavior function by specified name [" + config.getType() + "]", e);
        }
    }

    public HandlerConfig getHandlerConfig()
    {
        return handlerConfig;
    }

    /**
     * This class drives the handler time frame functionality.
     */
    protected class TimeFrameTask implements TimerTask
    {
        protected Timer timer;

        public void start()
        {
            if (getTimeFrame() > ZERO_TIME_FRAME)
            {
                if (timer == null)
                {
                    timer = new HashedWheelTimer(1, TimeUnit.SECONDS);
                }

                schedule();
            }
        }

        @Override
        public void run(Timeout timeout) throws Exception
        {
            evaluateBehaviorFunctions();
            timerCallback();

            schedule();
        }

        protected void schedule()
        {
            timer.newTimeout(this, getTimeFrame(), TimeUnit.SECONDS);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy