package net.jxta.impl.endpoint.netty; import java.io.IOException; import java.net.ConnectException; import java.nio.channels.ClosedChannelException; import java.util.LinkedList; import java.util.Queue; import java.util.logging.Level; import java.util.logging.Logger; import net.jxta.endpoint.EndpointAddress; import net.jxta.endpoint.Message; import net.jxta.impl.endpoint.msgframing.WelcomeMessage; import net.jxta.logging.Logging; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineCoverage; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; /** * The terminal upstream listener, which takes decoded messages (either WelcomeMessage or Message) * and passes this information up to the MessageArrivalListener - typically, the NettyMessenger * for this connection. * * @author iain.mcginniss@onedrum.com */ @ChannelPipelineCoverage("one") public class MessageDispatchHandler extends SimpleChannelUpstreamHandler { private static final Logger LOG = Logger.getLogger(MessageDispatchHandler.class.getName()); public static final String NAME = "messageDispatch"; private NettyChannelRegistry registry; private MessageArrivalListener listener; private Queue<Message> messages; public MessageDispatchHandler(NettyChannelRegistry registry) { this.registry = registry; messages = new LinkedList<Message>(); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if(e.getMessage() instanceof WelcomeMessage) { WelcomeMessage message = (WelcomeMessage) e.getMessage(); EndpointAddress logicalDestinationAddr = new EndpointAddress("jxta", message.getPeerID().getUniqueValue().toString(), null, null); registry.newConnection(ctx.getChannel(), message.getDestinationAddress(), logicalDestinationAddr); return; } synchronized(messages) { if(listener == null) { messages.offer((Message)e.getMessage()); return; } } sendToListener((Message)e.getMessage()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { Throwable cause = e.getCause(); if(cause instanceof ConnectException) { LOG.log(Level.FINE, "Unable to connect to remote host"); } else if(cause instanceof ClosedChannelException) { LOG.log(Level.FINE, "Channel to {0} has been closed", new Object[] { ctx.getChannel().getRemoteAddress() }); } else if(cause instanceof IOException) { LOG.log(Level.FINE, "Channel to {0} has failed - {1}", new Object[] { ctx.getChannel().getRemoteAddress(), cause.getMessage() }); } else if(Logging.SHOW_WARNING && LOG.isLoggable(Level.WARNING)) { LOG.log(Level.WARNING, "Unhandled exception in netty channel pipeline - closing connection", cause); } if(listener != null) { listener.connectionDied(); } Channels.close(ctx, ctx.getChannel().getCloseFuture()); } private void sendToListener(Message message) { if(message instanceof Message) { listener.messageArrived(message); } } public synchronized void setMessageArrivalListener(MessageArrivalListener listener) { synchronized(messages) { this.listener = listener; Object message; while((message = messages.poll()) != null) { sendToListener((Message)message); } } } }