/* * MockWebSocketSslServerHandler.java * * Created on Jan 30, 2012, 11:30:47 AM * * Description: . * * Copyright (C) Jan 30, 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.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame; 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.WebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker; import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory; import org.texai.util.StringUtils; import org.texai.util.TexaiException; /** * * @author reed */ @NotThreadSafe public class MockWebSocketSslServerHandler extends WebSocketSslServerHandler { /** the logger */ private static final Logger LOGGER = Logger.getLogger(MockWebSocketSslServerHandler.class); /** the web socket path */ private static final String WEBSOCKET_PATH = "/websocket"; /** the web socket server handshaker */ private WebSocketServerHandshaker webSocketServerHandshaker; /** Constructs a new MockWebSocketSslServerHandler instance. * * @param httpRequestHandler the parent HTTP request handler */ public MockWebSocketSslServerHandler(final HTTPRequestHandler httpRequestHandler) { super(httpRequestHandler); } /** Performs the web socket handshake to upgrade the protocol from HTTP to web socket. * * @param httpRequest the HTTP request * @param channelHandlerContext the channel handler context */ public void handshake( final HttpRequest httpRequest, final ChannelHandlerContext channelHandlerContext) { //Preconditions assert httpRequest != null : "httpRequest must not be null"; assert channelHandlerContext != null : "channelHandlerContext must not be null"; final String webSocketURL = "wss://" + httpRequest.getHeader(HttpHeaders.Names.HOST) + WEBSOCKET_PATH; final WebSocketServerHandshakerFactory webSocketServerHandshakeFactory = new WebSocketServerHandshakerFactory( webSocketURL, // webSocketURL null, // subprotocols false); // allowExtensions webSocketServerHandshaker = webSocketServerHandshakeFactory.newHandshaker(httpRequest); if (webSocketServerHandshaker == null) { webSocketServerHandshakeFactory.sendUnsupportedWebSocketVersionResponse(channelHandlerContext.getChannel()); LOGGER.info("web socket version is not supported\n" + httpRequest); } else { webSocketServerHandshaker.handshake(channelHandlerContext.getChannel(), httpRequest); LOGGER.info("web socket server handshake completed"); LOGGER.info("server pipeline ...\n" + channelHandlerContext.getChannel().getPipeline()); } } /** Receives a message from a remote peer. * * @param channelHandlerContext the channel handler context * @param messageEvent the message event * @throws Exception when an exception occurs */ @Override public void messageReceived( final ChannelHandlerContext channelHandlerContext, final MessageEvent messageEvent) throws Exception { //Preconditions assert channelHandlerContext != null : "channelHandlerContext must not be null"; assert messageEvent != null : "messageEvent must not be null"; final Object message = messageEvent.getMessage(); if (message instanceof WebSocketFrame) { handleWebSocketFrame(channelHandlerContext, (WebSocketFrame) message); } else { throw new TexaiException("message must be a WebSocketFrame, but was " + message.getClass().getName()); } } /** Handles a received web socket frame. * * @param channelHandlerContext the channel handler context * @param webSocketFrame the web socket frame */ private void handleWebSocketFrame( final ChannelHandlerContext channelHandlerContext, final WebSocketFrame webSocketFrame) { //Preconditions assert channelHandlerContext != null : "channelHandlerContext must not be null"; assert webSocketFrame != null : "webSocketFrame must not be null"; LOGGER.info("handling web socket frame " + webSocketFrame.getClass().getSimpleName()); // Check for closing frame if (webSocketFrame instanceof CloseWebSocketFrame) { this.webSocketServerHandshaker.close(channelHandlerContext.getChannel(), (CloseWebSocketFrame) webSocketFrame); return; } else if (webSocketFrame instanceof PingWebSocketFrame) { channelHandlerContext.getChannel().write(new PongWebSocketFrame(webSocketFrame.getBinaryData())); return; } else if (!(webSocketFrame instanceof TextWebSocketFrame)) { throw new UnsupportedOperationException(String.format("%s frame types not supported", webSocketFrame.getClass().getName())); } // Send the uppercase string back. String request = ((TextWebSocketFrame) webSocketFrame).getText(); if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("Channel %s received %s", channelHandlerContext.getChannel().getId(), request)); } channelHandlerContext.getChannel().write(new TextWebSocketFrame(request.toUpperCase())); } /** Processes an exception not otherwise caught. * * @param channelHandlerContext the channel handler context * @param exceptionEvent the exception event * @throws Exception when an exception occurs */ @Override public void exceptionCaught( final ChannelHandlerContext channelHandlerContext, final ExceptionEvent exceptionEvent) throws Exception { //Preconditions assert channelHandlerContext != null : "channelHandlerContext must not be null"; assert exceptionEvent != null : "e must not be null"; LOGGER.warn(StringUtils.getStackTraceAsString(exceptionEvent.getCause())); exceptionEvent.getChannel().close(); } }