/*
* WebSocketClientHandler.java
*
* Created on Jan 29, 2012, 7:28:36 PM
*
* Description: Provides a web socket client handler.
*
* Copyright (C) Jan 29, 2012, Stephen L. Reed, Texai.org.
*
*/
package org.texai.network.netty.handler;
import net.jcip.annotations.NotThreadSafe;
import org.apache.log4j.Logger;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.jboss.netty.util.CharsetUtil;
import org.texai.util.StringUtils;
import org.texai.util.TexaiException;
/** Provides a web socket client handler.
*
* @author reed
*/
@NotThreadSafe
public class WebSocketClientHandler extends SimpleChannelUpstreamHandler {
/** the logger */
private static final Logger LOGGER = Logger.getLogger(WebSocketClientHandler.class);
/** the web socket client handshaker */
private final WebSocketClientHandshaker webSocketClientHandshaker;
/** Constructs a new WebSocketClientHandler instance.
*
* @param webSocketClientHandshaker the web socket client handshaker
*/
public WebSocketClientHandler(final WebSocketClientHandshaker webSocketClientHandshaker) {
//Preconditions
assert webSocketClientHandshaker != null : "webSocketClientHandshaker must not be null";
this.webSocketClientHandshaker = webSocketClientHandshaker;
}
/** Notifies when a {@link Channel} was closed and all its related resources
* were released.
* @param ctx the channel handler context
* @param e the channel state event
* @throws Exception when an exception occurs
*/
@Override
public void channelClosed(
final ChannelHandlerContext ctx,
final ChannelStateEvent e) throws Exception {
LOGGER.info("WebSocket Client disconnected!");
}
/** Receives a message object from a remote peer.
*
* @param ctx the channel handler context
* @param e the channel state event
* @throws Exception
*/
@Override
public void messageReceived(
final ChannelHandlerContext ctx,
final MessageEvent e) throws Exception {
final Channel channel = ctx.getChannel();
if (!webSocketClientHandshaker.isHandshakeComplete()) {
webSocketClientHandshaker.finishHandshake(channel, (HttpResponse) e.getMessage());
LOGGER.info("WebSocket Client connected!");
return;
}
if (e.getMessage() instanceof HttpResponse) {
HttpResponse response = (HttpResponse) e.getMessage();
throw new TexaiException("Unexpected HttpResponse (status=" + response.getStatus() + ", content="
+ response.getContent().toString(CharsetUtil.UTF_8) + ")");
}
final WebSocketFrame webSocketFrame = (WebSocketFrame) e.getMessage();
if (webSocketFrame instanceof TextWebSocketFrame) {
TextWebSocketFrame textFrame = (TextWebSocketFrame) webSocketFrame;
LOGGER.info("WebSocket Client received message: " + textFrame.getText());
} else if (webSocketFrame instanceof PongWebSocketFrame) {
LOGGER.info("WebSocket Client received pong");
} else if (webSocketFrame instanceof CloseWebSocketFrame) {
LOGGER.info("WebSocket Client received closing");
channel.close();
}
}
/** Receives a raised exception.
*
* @param ctx the channel handler context
* @param e the channel state event
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
LOGGER.info(StringUtils.getStackTraceAsString(e.getCause()));
e.getChannel().close();
}
}