package jdc.patterns.peer;
import jdc.util.*;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Properties;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.net.*;
public class RMIPeerImpl extends UnicastRemoteObject implements RMIPeer {
/**
* Table of currently connected Peers.
*/
protected Hashtable mPeers = new Hashtable();
protected Hashtable mIdentities = new Hashtable();
/**
* The networked identity of this peer. Subclasses implementing this
* abstract class will need to provide a means for initializing this
* identity, such that the identity is unique in the distributed context.
*/
protected Identity mIdentity = null;
/**
* Static host property name. The host specifier includes any required
* port specifier, if the default RMI port is not in use.
*/
static final public String HOST_PROP = "HOST";
/**
* Property for RMI registry name of remote peer.
*/
static final public String REGNAME_PROP = "REGNAME";
/**
* Name under which this peer is registered.
*/
protected String mRegName = "Peer";
/**
* Default constructor. Leave identity uninitialized, to indicate
* no identity.
*/
public RMIPeerImpl() throws RemoteException {
mIdentity = new Identity();
register();
}
public RMIPeerImpl(String name) throws RemoteException {
super();
mRegName = name;
mIdentity = new Identity();
register();
}
protected void register() {
try {
// Bind this peer to our name in the local registry
Naming.rebind(mRegName, this);
// Set our identity properties accordingly
// The "name" is the name used in the registry.
getIdentity().setName(mRegName);
// The "host" property includes the local host name and the port
// on which the RMI registry is listening on the local host.
getIdentity().setProperty(HOST_PROP,
InetAddress.getLocalHost().getHostName() +
":" + Registry.REGISTRY_PORT);
}
catch (Exception e) {
System.out.println("Error registering peer \"" + mRegName + "\":");
e.printStackTrace();
}
}
//
// Remotely exported interface implementation
//
public Identity getIdentity() throws RemoteException {
return mIdentity;
}
// Non-remote
public void setIdentity(Identity i) {
mIdentity = i;
}
/**
* Handle an incoming message.
*/
public void handle(Message m, RMIPeer p) throws RemoteException {
System.out.println("Got message: \"" + m.getId() + "\", body: \"" +
m.getBody() + "\" from " + p.getIdentity().getName());
}
/**
* Add a peer to our list.
*/
public void addPeer(RMIPeer p) throws RemoteException {
// Store peer by id in one table, and store id by peer in another
Identity id = p.getIdentity();
mPeers.put(id, p);
mIdentities.put(p, id);
}
/**
* Get the peer identified by the given identity.
*/
public RMIPeer getPeer(Identity i) throws RemoteException {
Enumeration e = mPeers.keys();
RMIPeer p = null;
while (e.hasMoreElements()) {
Object o = e.nextElement();
if (i.equals(o)) {
p = (RMIPeer)mPeers.get(o);
break;
}
}
return p;
}
/**
* Get list of Peers
*/
public Enumeration getPeers() throws RemoteException {
return mPeers.elements();
}
/**
* Remove a peer from our list.
*/
public void removePeer(RMIPeer p) throws RemoteException {
Identity id = (Identity)mIdentities.get(p);
mPeers.remove(id);
mIdentities.remove(p);
}
//
// Local Peer interface implementation
//
/**
* Connect to a peer given the connection properties. This RMI-based peer
* requires the host and registry name of the remote peer object.
*/
public boolean connect(Properties connProps) {
Identity id = new Identity();
id.setName((String)connProps.getProperty(REGNAME_PROP));
id.setProperty(HOST_PROP, (String)connProps.getProperty(HOST_PROP));
return connect(id);
}
/**
* Connect to a peer given the connection properties and identity of the
* peer. Subclasses can choose to implement this using both arguments, or
* ignoring one in favor of the other (connection properties vs. properties
* pulled from the remote peer identifier).
*/
public boolean connect(Identity peerID) {
boolean success = false;
String host = (String)peerID.getProperty(HOST_PROP);
String regName = peerID.getName();
// If no host specified, assume a local peer
if (host == null) {
host = "localhost";
}
// If no registry name, then fail right here
if (regName == null || regName.trim().length() == 0) {
System.out.println("RMIPeerImpl.connect: No registry name in identity.");
return false;
}
String rmiURL = "rmi://" + host + "/" + regName;
try {
RMIPeer p = (RMIPeer)Naming.lookup(rmiURL);
addPeer(p);
p.addPeer(this);
success = true;
}
catch (Exception re) {
re.printStackTrace();
}
return success;
}
/**
* Broadcast the message to all currently connected peers.
*/
public boolean broadcast(Message msg) {
boolean success = true;
try {
Enumeration pEnum = getPeers();
while (pEnum.hasMoreElements()) {
RMIPeer p = (RMIPeer)pEnum.nextElement();
try {
if (!send(msg, p.getIdentity())) {
success = false;
}
}
catch (java.rmi.RemoteException ce) {
System.out.println("Lost connection to peer");
try { removePeer(p); } catch (Exception e) { e.printStackTrace(); }
}
}
}
catch (RemoteException re) {
System.out.println("broadcast failed: ");
re.printStackTrace();
}
return success;
}
/**
* Send the message to the identified peer.
*/
public boolean send(Message msg, Identity peer) {
boolean success = false;
RMIPeer p = null;
try {
p = (RMIPeer)getPeer(peer);
p.handle(msg, this);
success = true;
}
catch (java.rmi.ConnectException ce) {
System.out.println("Lost connection to peer.");
try { removePeer(p); } catch (Exception e) { e.printStackTrace(); }
}
catch (Exception e) {
System.out.println("Error sending message:" );
e.printStackTrace();
}
return success;
}
}
|