Package org.rzo.netty.ahessian.session

Source Code of org.rzo.netty.ahessian.session.ClientSessionFilter

package org.rzo.netty.ahessian.session;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineCoverage;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.rzo.netty.ahessian.Constants;
import org.rzo.netty.ahessian.stopable.StopablePipeline;

/**
* Handles sessions on the client side.
* A typical setup for a protocol in a TCP/IP socket would be:
*
* <pre>
* // client session filter is an attribute of the ChannelPipelineFactory Class
* // it should not be created with each call to getPipeline()
* // _mixinFactory is a ChannelPipelineFactory which returns MixinPipeline
* _sessionFilter = new ClientSessionFilter(_mixinFactory);
*
* {@link ChannelPipeline} pipeline = ...;
*
* pipeline.addLast("sessionFilter", _sessionFilter);
* </pre>
*/

@ChannelPipelineCoverage("all")
public class ClientSessionFilter extends SimpleChannelUpstreamHandler
{
 
  /** The current session. */
  private Session _session = null;
 
  /** Indicates if we have received a session. */
  private boolean _hasSession = false;
 
  /** String to read in the session id from the server */
  private String _sessionId = "";
 
  /** Factory for creating session objects. */
  private SessionFactory _factory = new SessionFactory();
 
  /** Connected events are intercepted and sent upstream once a session has been established. */
  private ChannelStateEvent _connectedEvent; 
 
  /** The factory for getting a MixinPipeline for a new session */
  private ChannelPipelineFactory _mixinFactory;
 
  /** Assignment of session-id to pipelines created. //TODO destroy a pipeline if a session is timed out */
  private static Map<String, MixinPipeline> _sessionPipelines = Collections.synchronizedMap(new HashMap<String, MixinPipeline>());
 
  private List<Runnable> _sessionClosedListeners = Collections.synchronizedList(new ArrayList());
 
  private List<Runnable> _sessionNewListeners = Collections.synchronizedList(new ArrayList());
 
  /**
   * Instantiates a new client session filter.
   *
   * @param mixinFactory the mixin factory
   */
  public ClientSessionFilter(ChannelPipelineFactory mixinFactory)
  {
    _mixinFactory = mixinFactory;
  }
 
  /* (non-Javadoc)
   * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#channelConnected(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent)
   */
  @Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
      // remeber the event. it will be sent upstream when session has been created
    _connectedEvent = e;
    String id = _session == null ? "?" : _session.getId();
    // send the session id to client
    ChannelFuture future = Channels.future(ctx.getChannel());
    Channels.write(ctx, future, ChannelBuffers.wrappedBuffer(id.getBytes()));
    }
 
    /* (non-Javadoc)
     * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#messageReceived(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.MessageEvent)
     */
    public void messageReceived(
            ChannelHandlerContext ctx, MessageEvent e) throws Exception
            {
      // if session established forward all messages
          if (_hasSession)
            ctx.sendUpstream(e);
          else
          {
            ChannelBuffer b = (ChannelBuffer) e.getMessage();
            _sessionId += b.toString("UTF-8");
            checkSession(ctx);
          }
            }
   
  private void checkSession(ChannelHandlerContext ctx)
  {
    if (_sessionId.length() == _factory.getSessionIdLength()*2)
    {
      if (_session == null)
        newSession(ctx);
      else if (_session.getId().equals(_sessionId))
        confirmSession(ctx);
      else
        changedSession(ctx);
    }
     
  }

  private void changedSession(ChannelHandlerContext ctx)
  {
    closeSession(_session);
    newSession(ctx);
  }

  private void closeSession(Session session)
  {
    for (Runnable listener : _sessionClosedListeners)
    {
      try
      {
        listener.run();
      }
      catch (Throwable e)
      {
        Constants.ahessianLogger.warn("", e);
      }
    }
    ChannelPipeline p = _sessionPipelines.remove(session.getId());
    if (p instanceof StopablePipeline)
      ((StopablePipeline)p).stop();

  }

  private void confirmSession(ChannelHandlerContext ctx)
  {
    MixinPipeline pipeline = _sessionPipelines.get(_session.getId());
    handleSession(ctx, pipeline);
  }

  private void newSession(ChannelHandlerContext ctx)
  {
    _session = _factory.createSession(_sessionId);
    MixinPipeline pipeline = null;
    try
    {
      pipeline = (MixinPipeline) _mixinFactory.getPipeline();
      _sessionPipelines.put(_session.getId(), pipeline);
    }
    catch (Exception e)
    {
      Constants.ahessianLogger.warn("", e);
    }
    handleSession(ctx, pipeline);
    for (Runnable listener : _sessionNewListeners)
    {
      try
      {
        listener.run();
      }
      catch (Throwable ex)
      {
        Constants.ahessianLogger.warn("", ex);

      }
    }
  }
 
  private void handleSession(ChannelHandlerContext ctx, MixinPipeline pipeline)
  {
    _hasSession = true;
    // now that we have a session extend the pipeline
    ChannelPipeline currentPipeline = ctx.getPipeline();
    pipeline.mixin(currentPipeline);
    ctx.setAttachment(_session);
    ctx.sendUpstream(_connectedEvent);
  }
 
  @Override
    public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
    _hasSession = false;
    _sessionId = "";
    ctx.sendUpstream(e);
  }
 
  @Override
  public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception
  {
    //
  }
 
  public void addSessionClosedListener(Runnable listener)
  {
    _sessionClosedListeners.add(listener);
  }
 
  public void removeSessionClosedListener(Runnable listener)
  {
    _sessionClosedListeners.remove(listener);
  }

  public void addSessionNewListener(Runnable listener)
  {
    _sessionNewListeners.add(listener);
  }
 



}
TOP

Related Classes of org.rzo.netty.ahessian.session.ClientSessionFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.