/* * Copyright (C) 2012 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.ros.internal.transport; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.ros.concurrent.ListenerGroup; import org.ros.concurrent.SignalRunnable; import org.ros.internal.transport.tcp.AbstractNamedChannelHandler; import java.util.concurrent.ExecutorService; /** * Common functionality for {@link ClientHandshake} handlers. * * @author damonkohler@google.com (Damon Kohler) */ public abstract class BaseClientHandshakeHandler extends AbstractNamedChannelHandler { private final ClientHandshake clientHandshake; private final ListenerGroup<ClientHandshakeListener> clientHandshakeListeners; public BaseClientHandshakeHandler(ClientHandshake clientHandshake, ExecutorService executorService) { this.clientHandshake = clientHandshake; clientHandshakeListeners = new ListenerGroup<ClientHandshakeListener>(executorService); } public void addListener(ClientHandshakeListener clientHandshakeListener) { clientHandshakeListeners.add(clientHandshakeListener); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { super.channelConnected(ctx, e); e.getChannel().write(clientHandshake.getOutgoingConnectionHeader().encode()); } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { try { ChannelBuffer buffer = (ChannelBuffer) e.getMessage(); ConnectionHeader connectionHeader = ConnectionHeader.decode(buffer); if (clientHandshake.handshake(connectionHeader)) { onSuccess(connectionHeader, ctx, e); signalOnSuccess(connectionHeader); } else { onFailure(clientHandshake.getErrorMessage(), ctx, e); signalOnFailure(clientHandshake.getErrorMessage()); } } finally { // Assume can shut the listener down after signaled. clientHandshakeListeners.shutdown(); } } /** * Called when the {@link ClientHandshake} succeeds and will block the network * thread until it returns. * <p> * This must block in order to allow changes to the pipeline to be made before * further messages arrive. * * @param incommingConnectionHeader * @param ctx * @param e */ protected abstract void onSuccess(ConnectionHeader incommingConnectionHeader, ChannelHandlerContext ctx, MessageEvent e); private void signalOnSuccess(final ConnectionHeader incommingConnectionHeader) { clientHandshakeListeners.signal(new SignalRunnable<ClientHandshakeListener>() { @Override public void run(ClientHandshakeListener listener) { listener.onSuccess(clientHandshake.getOutgoingConnectionHeader(), incommingConnectionHeader); } }); } protected abstract void onFailure(String errorMessage, ChannelHandlerContext ctx, MessageEvent e); private void signalOnFailure(final String errorMessage) { clientHandshakeListeners.signal(new SignalRunnable<ClientHandshakeListener>() { @Override public void run(ClientHandshakeListener listener) { listener.onFailure(clientHandshake.getOutgoingConnectionHeader(), errorMessage); } }); } }