package org.apache.jxtadoop.hdfs.p2p;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.security.auth.login.LoginException;
import net.jxta.discovery.DiscoveryService;
import net.jxta.exception.PeerGroupException;
import net.jxta.peer.PeerID;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.PeerAdvertisement;
import net.jxta.rendezvous.RendezVousService;
import net.jxta.rendezvous.RendezvousEvent;
import net.jxta.rendezvous.RendezvousListener;
import net.jxta.socket.JxtaServerSocket;
import net.jxta.socket.JxtaSocketAddress;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jxtadoop.conf.Configuration;
import org.apache.jxtadoop.security.UserGroupInformation;
/**
* The namenode peer is an extension of the Jxtadoop peer. <br>
* It implements the methods from the RendezvousListener interface as well as overrides specific peer methods :<br>
* <p>setupnetworking()<br>
* <p>start()<br>
* <br>
* The method to return the RPC socket server is also implemented as this is required for the Hadoop RPC server.<br>
*
*
* @author Franck Besnard <franck@besnard.mobi>
* @version 1.0
* @since November, 2011
*
*/
@SuppressWarnings({"rawtypes","unchecked"})
public class NamenodePeer extends Peer implements RendezvousListener {
public static final Log LOG = LogFactory.getLog(NamenodePeer.class);
/**
* The jxta server socket on which the RPC server will liste,.
*/
private JxtaServerSocket jss;
private RendezVousService rdv;
/**
* The listener array
*/
private List _dnlisteners = new ArrayList();
/**
* Constructor with the peer name unique ID. This is important for the peer ID and key generation.
* @param s The peer unique name
*/
public NamenodePeer(String s) {
super(s);
}
/**
* Constructor with the peer name unique ID and the configuration to be used. This is important for the peer ID and key generation.
* @param s The peer unique name
* @param c The configuration to be used
*/
public NamenodePeer(String s, Configuration c) {
super(s,c);
}
/**
* This method set up the jxta peer network configuration.
* <br> The peer is configured as a Rendez-Vous and as a Relay.
*/
@Override
public void setupNetworking() throws LoginException, IOException, javax.security.cert.CertificateException, PeerGroupException {
nm = new NetworkManager(NetworkManager.ConfigMode.RENDEZVOUS_RELAY, UserGroupInformation.login(pc).getUserName()+"Namenode Peer",p2pdir.toURI());
nm.setConfigPersistent(false);
nc = nm.getConfigurator();
//if (!nc.exists()) {
nc.setTcpPort(Integer.parseInt(pc.get("hadoop.p2p.namenode.port", P2PConstants.RPCNAMENODEPORT)));
nc.setTcpEnabled(true);
nc.setTcpIncoming(true);
nc.setTcpOutgoing(true);
nc.setHttpEnabled(false);
nc.setHttp2Enabled(false);
nc.setTcpStartPort(-1);
nc.setTcpEndPort(-1);
nc.setTcpInterfaceAddress(pc.get("hadoop.p2p.rpc.relay").replaceAll("tcp://","").substring(
0,
pc.get("hadoop.p2p.rpc.relay").replaceAll("tcp://","").indexOf(":"))
);
nc.setTcpPublicAddress(pc.get("hadoop.p2p.rpc.relay").replaceAll("tcp://",""),true);
nc.setUseMulticast(Boolean.getBoolean(pc.get("hadoop.p2p.use.multicast")));
nc.setPeerID(pid);
nc.setName(P2PConstants.RPCNAMENODETAG+" - "+nc.getName());
nc.setKeyStoreLocation(KeyStoreFile.toURI());
nc.setPassword(p2ppass);
// nc.save();
/*} else {
nc.setKeyStoreLocation(KeyStoreFile.toURI());
nc.setPassword(p2ppass);
nc.load();
}*/
npg = nm.startNetwork();
rdv = npg.getRendezVousService();
rdv.addListener(this);
while(!nm.isStarted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}
ds = npg.getDiscoveryService();
}
/**
* The start-up includes 2 steps.<br>
* First, the pipe advertisement is published on the datanode cloud.<br>
* Then the peer monitor thread is started to monitor the datanode cloud.
*/
@Override
public void start() {
try {
publishPipeAdvertisement();
} catch (IOException e) {
LOG.fatal("Cannot start the Namenode peer; Aborting");
LOG.error(e.getMessage());
//e.printStackTrace();
throw new RuntimeException();
}
Thread thread = new Thread(this.new PeerMonitor(),"Peer Monitor Thread");
thread.start();
}
/**
* The datanode list is managed for the namenode using the connection events.
*/
public void rendezvousEvent(RendezvousEvent event) {
synchronized(datanodepeers) {
if ( event.getType() == RendezvousEvent.CLIENTCONNECT || event.getType() == RendezvousEvent.CLIENTRECONNECT) {
LOG.info("\tClient connected - PeerID : "+event.getPeerID());
datanodepeers.put((PeerID)event.getPeerID(),(PeerAdvertisement)null);
LOG.debug("Total number of datanode in the cloud : "+datanodepeers.size());
} else if (event.getType() == RendezvousEvent.CLIENTDISCONNECT || event.getType() == RendezvousEvent.CLIENTFAILED) {
LOG.info("\tClient disconnected - PeerID : "+event.getPeerID());
if(datanodepeers.containsKey((PeerID)event.getPeerID()))
datanodepeers.remove((PeerID)event.getPeerID());
LOG.debug("Total number of datanode in the cloud : "+datanodepeers.size());
} else {
LOG.warn("Something weird happenned : "+event.getType() );
}
}
}
/**
* Published the pipe advertisement in the cloud and set the server socket object.
* @throws IOException The publishing failed.
*/
protected void publishPipeAdvertisement () throws IOException {
ds.publish(rpcPipeAdv);
ds.remotePublish(rpcPipeAdv,DiscoveryService.NO_EXPIRATION);
jssad = new JxtaSocketAddress(npg,rpcPipeAdv,npg.getPeerAdvertisement());
}
/**
* Returns the RPC socket address of the server
* @return The RPC server socket address
*/
public JxtaServerSocket getRpcServerSocket() {
return this.jss;
}
/**
* Adding a new listener to the track list
*
* @param listener
*/
public synchronized void addP2PEventListener(P2PListener listener) {
_dnlisteners.add(listener);
}
/**
* Removing a new listener from the track list
*
* @param listener
*/
public synchronized void removeEventListener(P2PListener listener) {
_dnlisteners.remove(listener);
}
/**
* Triggering a disconnection event and notifying the subscribers
*
* @param event
*/
@Override
public synchronized void fireEvent(DatanodeEvent event) {
Iterator i = _dnlisteners.iterator();
while(i.hasNext()) {
((P2PListener) i.next()).handleDisconnectEvent(event);
}
}
}