package org.rzo.netty.ahessian.io; import static org.jboss.netty.channel.Channels.fireMessageReceived; import java.io.IOException; import java.io.InputStream; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.rzo.netty.ahessian.stopable.StopableHandler; //import com.caucho.services.server.ServiceContext; /** * Encodes bytes read by a {@link Channel} into an {@link InputStream}. <br> * Once created the InputStream is passed as a message to the next handler * within a separate thread. From there on, no further messages are passed * through the pipeline. <br> * A typical setup for a serialization protocol in a TCP/IP socket would be: * * <pre> * {@link ChannelPipeline} pipeline = ...; * * // Encoder * pipeline.addLast("outputStream", new {@link handler.io.OutputStream}()); * pipeline.addLast("outputHandler", new MyOutputHandler()); * * // Decoder * pipeline.addLast("inputStream", new {@link handler.io.InputStream}()); * pipeline.addLast("inputHandler", new MyInputHandler()); * </pre> * * and then, within the handler you can use a {@link java.io.InputStream} or * {@link java.io.OutputStream} instead of a {@link ChannelBuffer} as a message: <br> * Writing to OutputStream: * * <pre> * // synchronized for multithreaded environment to avoid messages mixing * synchronized public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception * { * byte[] message = (byte[]) e.getMessage(); * OutputStream out = OutputStreamEncoder.getOutputStream(ctx); * out.write(message); * // if this is the last chunk of bytes we should flush the output * out.flush(); * // netty seems to require this, so that the boss thread may read input from the channel * Thread.yield(); * } * * </pre> * * <br> * Reading from InputStream: * * <pre> * void messageReceived(ChannelHandlerContext ctx, MessageEvent e) * { * // message received is called only once to deliver the input stream * // it is called in a separate thread and not in the netty worker thread. * // incoming bytes are consumed in this method. * // the stream is closed once the channel is disconnected * InputStream in = (InputStream) evt.getMessage(); * * while (ctx.getChannel().isConnected()) * { * // parse the incoming stream and forward the result to the next handler * Channels.fireMessageReceived(ctx, parseReply(in)); * } * } * </pre> */ public class InputStreamDecoder extends SimpleChannelUpstreamHandler implements StopableHandler { /** Thread pool for getting a thread for calling the next handler */ InputStreamBuffer _in = null; boolean _stopEnabled = true; boolean _crcCheck = false; public InputStreamDecoder() { } public InputStreamDecoder (boolean crcCheck) { _crcCheck = crcCheck; } /** * Instantiates a new input stream decoder. * * @param executor * the thread pool */ /* * (non-Javadoc) * * @see * org.jboss.netty.channel.SimpleChannelUpstreamHandler#messageReceived( * org.jboss.netty.channel.ChannelHandlerContext, * org.jboss.netty.channel.MessageEvent) */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { _in.write((ChannelBuffer) e.getMessage()); fireMessageReceived(ctx, _in, e.getRemoteAddress()); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { if (_in == null) { if (_crcCheck) _in = new CRCInputStream(); else _in = new InputStreamBuffer(); ctx.setAttachment(_in); } ctx.sendUpstream(e); } public static InputStreamBuffer getInputStream(ChannelHandlerContext ctx) { return (InputStreamBuffer) ctx.getPipeline().getContext(InputStreamDecoder.class).getAttachment(); } public boolean isStopEnabled() { return _stopEnabled; } public void setStopEnabled(boolean stopEnabled) { _stopEnabled = stopEnabled; } public void stop() { try { _in.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } _in = null; } }