/*
* Copyright 2009 Thomas Bocek
*
* 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 net.tomp2p.rpc;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.tomp2p.connection2.ChannelCreator;
import net.tomp2p.connection2.ConnectionBean;
import net.tomp2p.connection2.ConnectionConfiguration;
import net.tomp2p.connection2.PeerBean;
import net.tomp2p.connection2.RequestHandler;
import net.tomp2p.futures.FutureResponse;
import net.tomp2p.message.Message2;
import net.tomp2p.message.Message2.Type;
import net.tomp2p.p2p.builder.ShutdownBuilder;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerStatusListener;
/**
* This Quit RPC is used to send friendly shutdown messages by peers that are shutdown regularly.
*
* @author Thomas Bocek
*
*/
public class QuitRPC extends DispatchHandler {
private static final Logger LOG = LoggerFactory.getLogger(QuitRPC.class);
public static final byte QUIT_COMMAND = 6;
private final List<PeerStatusListener> listeners = new ArrayList<PeerStatusListener>();
/**
* Constructor that registers this RPC with the message handler.
*
* @param peerBean
* The peer bean that contains data that is unique for each peer
* @param connectionBean
* The connection bean that is unique per connection (multiple peers can share a single connection)
*/
public QuitRPC(final PeerBean peerBean, final ConnectionBean connectionBean) {
super(peerBean, connectionBean, QUIT_COMMAND);
}
/**
* Add a peer status listener that gets notified when a peer is offline.
*
* @param listener
* The listener
* @return This class
*/
public QuitRPC addPeerStatusListener(final PeerStatusListener listener) {
listeners.add(listener);
return this;
}
/**
* Sends a message that indicates this peer is about to quit. This is an RPC.
*
* @param remotePeer
* The remote peer to send this request
* @param shutdownBuilder
* Used for the sign and force TCP flag Set if the message should be signed
* @param channelCreator
* The channel creator that creates connections
* @param configuration
* The client side connection configuration
* @return The future response to keep track of future events
*/
public FutureResponse quit(final PeerAddress remotePeer, final ShutdownBuilder shutdownBuilder,
final ChannelCreator channelCreator) {
final Message2 message = createMessage(remotePeer, QUIT_COMMAND, Type.REQUEST_FF_1);
if (shutdownBuilder.isSignMessage()) {
message.setPublicKeyAndSign(peerBean().getKeyPair());
}
FutureResponse futureResponse = new FutureResponse(message);
final RequestHandler<FutureResponse> requestHandler = new RequestHandler<FutureResponse>(
futureResponse, peerBean(), connectionBean(), shutdownBuilder);
if (!shutdownBuilder.isForceTCP()) {
return requestHandler.fireAndForgetUDP(channelCreator);
} else {
return requestHandler.fireAndForgetTCP(channelCreator);
}
}
@Override
public Message2 handleResponse(final Message2 message, final boolean sign) throws Exception {
if (!(message.getType() == Type.REQUEST_FF_1 && message.getCommand() == QUIT_COMMAND)) {
throw new IllegalArgumentException("Message content is wrong");
}
LOG.debug("received QUIT message {}" + message);
synchronized (listeners) {
for (PeerStatusListener listener : listeners) {
listener.peerFailed(message.getSender(), true);
}
}
return message;
}
}