package option2;
import common.MIMEType;
import common.FileClassifier;
public class FileClassifierImpl implements FileClassifier {
public MIMEType getMIMEType(String fileName) {
if (fileName.endsWith(".gif")) {
return new MIMEType("image", "gif");
} else if (fileName.endsWith(".jpeg")) {
return new MIMEType("image", "jpeg");
} else if (fileName.endsWith(".mpg")) {
return new MIMEType("video", "mpeg");
} else if (fileName.endsWith(".txt")) {
return new MIMEType("text", "plain");
} else if (fileName.endsWith(".html")) {
return new MIMEType("text", "html");
} else
// fill in lots of other types,
// but eventually give up and
return null;
}
public FileClassifierImpl() {
// empty
}
} // FileClassifierImpl
package option2;
import java.rmi.RMISecurityManager;
import net.jini.discovery.LookupDiscovery;
import net.jini.discovery.DiscoveryListener;
import net.jini.discovery.DiscoveryEvent;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceItem;
import net.jini.core.lookup.ServiceRegistration;
import net.jini.core.lease.Lease;
import com.sun.jini.lease.LeaseRenewalManager;
import com.sun.jini.lease.LeaseListener;
import com.sun.jini.lease.LeaseRenewalEvent;
public class FileClassifierServer implements DiscoveryListener,
LeaseListener {
protected LeaseRenewalManager leaseManager = new LeaseRenewalManager();
public static void main(String argv[]) {
new FileClassifierServer();
// keep server running forever to
// - allow time for locator discovery and
// - keep re-registering the lease
try {
Thread.currentThread().sleep(Lease.FOREVER);
} catch(java.lang.InterruptedException e) {
// do nothing
}
}
public FileClassifierServer() {
LookupDiscovery discover = null;
try {
discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS);
} catch(Exception e) {
System.err.println(e.toString());
System.exit(1);
}
discover.addDiscoveryListener(this);
}
public void discovered(DiscoveryEvent evt) {
ServiceRegistrar[] registrars = evt.getRegistrars();
for (int n = 0; n < registrars.length; n++) {
ServiceRegistrar registrar = registrars[n];
ServiceItem item = new ServiceItem(null,
new FileClassifierImpl(),
null);
ServiceRegistration reg = null;
try {
reg = registrar.register(item, Lease.FOREVER);
} catch(java.rmi.RemoteException e) {
System.err.println("Register exception: " + e.toString());
}
System.out.println("service registered");
// set lease renewal in place
leaseManager.renewUntil(reg.getLease(), Lease.FOREVER, this);
}
}
public void discarded(DiscoveryEvent evt) {
}
public void notify(LeaseRenewalEvent evt) {
System.out.println("Lease expired " + evt.toString());
}
} // FileClassifierServer
JoinManager
(which will change
in later versions of Jini)
public class JoinManager {
public JoinManager(java.lang.Object obj,
Entry[] attrSets,
java.lang.String[] groups,
LookupLocator[] locators,
ServiceIDListener callback,
LeaseRenewalManager leaseMgr);
...
}
package joinmgr;
import option2.FileClassifierImpl;
import com.sun.jini.lookup.JoinManager;
import net.jini.core.lookup.ServiceID;
import com.sun.jini.lookup.ServiceIDListener;
import com.sun.jini.lease.LeaseRenewalManager;
import net.jini.discovery.LookupDiscovery;
public class FileClassifierServer implements ServiceIDListener {
public static void main(String argv[]) {
new FileClassifierServer();
// stay around long enough to receive replies
try {
Thread.currentThread().sleep(1000000L);
} catch(java.lang.InterruptedException e) {
// do nothing
}
}
public FileClassifierServer() {
JoinManager joinMgr = null;
try {
joinMgr = new JoinManager(new FileClassifierImpl(),
null,
LookupDiscovery.ALL_GROUPS,
null,
this,
new LeaseRenewalManager());
} catch(Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void serviceIDNotify(ServiceID serviceID) {
System.out.println("got service ID " + serviceID.toString());
}
} // FileClassifierServer
grant {
permission java.security.AllPermission "", "";
};
grant {
permission net.jini.discovery.DiscoveryPermission "*";
// multicast request address
permission java.net.SocketPermission "224.0.1.85", "connect,accept";
// multicast announcement address
permission java.net.SocketPermission "224.0.1.84", "connect,accept";
// RMI connections
permission java.net.SocketPermission "*.dstc.edu.au:1024-", "connect,accept";
permission java.net.SocketPermission "130.102.176.249:1024-", "connect,accept";
permission java.net.SocketPermission "127.0.0.1:1024-", "connect,accept";
// reading parameters
// like net.jini.discovery.debug!
permission java.util.PropertyPermission "net.jini.discovery.*", "read";
};
grant {
permission net.jini.discovery.DiscoveryPermission "*";
// multicast request address
permission java.net.SocketPermission "224.0.1.85", "connect,accept";
// multicast announcement address
permission java.net.SocketPermission "224.0.1.84", "connect,accept";
// RMI connections
permission java.net.SocketPermission "127.0.0.1:1024-", "connect,accept";
permission java.net.SocketPermission "*.dstc.edu.au:1024-", "connect,accept";
permission java.net.SocketPermission "130.102.176.249:1024-", "connect,accept";
// DANGER
// HTTP connections - this is where external code may come in - careful!!!
permission java.net.SocketPermission "127.0.0.1:80", "connect,accept";
permission java.net.SocketPermission "*.dstc.edu.au:80", "connect,accept";
// reading parameters
// like net.jini.discovery.debug!
permission java.util.PropertyPermission "net.jini.discovery.*", "read";
};
Button
generates an ActionEvent
PropertyChange
events
for Java beans
public interface RemoteEventListener {
public void notify(RemoteEvent evt) throws ...:
}
public class RemoteEvent {
public long getID(); // distinguish event types
public long getSequenceNumber(); // like a timestamp
public MarshalledObject getRegistrationObject(); // handback
addActionListener()
,
addPropertyChangeListener()
, etc. Each object must look
after its own listener list and decide when and how to call it. But...
public class EventRegistration {
public EventRegistration(long eventID, Object source,
Lease lease, long seqNum);
public long getID();
public Object getSource();
public Lease getLease();
public long getSequenceNumber();
}
A list with only one listener on it can be done by
protected RemoteEventListener listener = null;
public EventRegistration addRemoteListener(RemoteEventListener listener)
throws java.util.TooManyListenersException {
if (this.listener == null {
this.listener = listener;
} else {
throw new java.util.TooManyListenersException();
}
return new EventRegistration(0L, this, null, 0L);
}
The source object can send an event to its listener by
protected void fireNotify(long eventID,
long seqNum) {
if (listener == null) {
return;
}
RemoteEvent remoteEvent = new RemoteEvent(this, eventID,
seqNum, null);
listener.notify(remoteEvent);
}
Allow the file classifier to change its list of MIME type mappings, and notify listeners when it does so
package mutable;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.MarshalledObject;
import net.jini.core.event.RemoteEventListener;
import net.jini.core.event.RemoteEvent;
import net.jini.core.event.EventRegistration;
import java.rmi.RemoteException;
import net.jini.core.event.UnknownEventException ;
import javax.swing.event.EventListenerList;
import common.MIMEType;
import common.MutableFileClassifier;
import java.util.Map;
import java.util.HashMap;
public class FileClassifierImpl extends UnicastRemoteObject
implements RemoteFileClassifier {
/**
* Map of String extensions to MIME types
*/
protected Map map = new HashMap();
/**
* Listeners for change events
*/
protected EventListenerList listenerList = new EventListenerList();
public MIMEType getMIMEType(String fileName)
throws java.rmi.RemoteException {
MIMEType type;
String fileExtension;
int dotIndex = fileName.lastIndexOf('.');
if (dotIndex == -1 || dotIndex + 1 == fileName.length()) {
// can't find suitable suffix
return null;
}
fileExtension= fileName.substring(dotIndex + 1);
type = (MIMEType) map.get(fileExtension);
return type;
}
public void addType(String suffix, MIMEType type)
throws java.rmi.RemoteException {
map.put(suffix, type);
fireNotify(ADD_TYPE);
}
public void removeMIMEType(String suffix, MIMEType type)
throws java.rmi.RemoteException {
if (map.remove(suffix) != null) {
fireNotify(REMOVE_TYPE);
}
}
public EventRegistration addRemoteListener(RemoteEventListener listener)
throws java.rmi.RemoteException {
listenerList.add(RemoteEventListener.class, listener);
return new EventRegistration(0, this, null, 0);
}
// Notify all listeners that have registered interest for
// notification on this event type. The event instance
// is lazily created using the parameters passed into
// the fire method.
protected void fireNotify(long eventID) {
RemoteEvent remoteEvent = null;
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == RemoteEventListener.class) {
RemoteEventListener listener = (RemoteEventListener) listeners[i+1];
if (remoteEvent == null) {
remoteEvent = new RemoteEvent(this, eventID,
0L, null);
}
try {
listener.notify(remoteEvent);
} catch(UnknownEventException e) {
e.printStackTrace();
} catch(RemoteException e) {
e.printStackTrace();
}
}
}
}
public FileClassifierImpl() throws java.rmi.RemoteException {
// load a predefined set of MIME type mappings
map.put("gif", new MIMEType("image", "gif"));
map.put("jpeg", new MIMEType("image", "jpeg"));
map.put("mpg", new MIMEType("video", "mpeg"));
map.put("txt", new MIMEType("text", "plain"));
map.put("html", new MIMEType("text", "html"));
}
} // FileClassifierImpl
CommAPI
package rcx;
public class RCXPort {
public RCXPort(String port);
public void addRCXListener(RCXListener rl);
public boolean open();
public void close();
public boolean isOpen();
public OutputStream getOutputStream();
public InputStream getInputStream();
public synchronized boolean write(byte[] bArray);
public void processRead();
public String getLastError();
public void showTable();
public static byte[] parseString(String str);
}
This is best done as an RMI proxy to the service on the server.
The service has an RCXPort
as attribute, and passes
on messages to it.
package rcx.jini;
import java.rmi.server.UnicastRemoteObject;
import net.jini.core.event.RemoteEvent;
import net.jini.core.event.RemoteEventListener;
import rcx.*;
import java.io.*;
import java.util.*;
public class RCXPortImpl extends UnicastRemoteObject
implements RemoteRCXPort, RCXListener {
protected String error = null;
protected byte[] message = null;
protected RCXPort port = null;
protected RemoteEventListener listener = null;
protected long messageSeqNo, errorSeqNo;
public RCXPortImpl()
throws java.rmi.RemoteException {
Properties parameters;
String portName = null;
File f = new File("parameters.txt");
if (!f.exists()) {
f = new File(System.getProperty("user.dir")
+ System.getProperty("path.separator")
+ "parameters.txt");
}
if (f.exists()) {
try {
FileInputStream fis = new FileInputStream(f);
parameters = new Properties();
parameters.load(fis);
fis.close();
portName = parameters.getProperty("port");
} catch (IOException e) { }
} else {
System.err.println("Can't find parameters.txt with \"port=...\" specified");
System.exit(1);
}
port = new RCXPort(portName);
port.addRCXListener(this);
}
public boolean write(byte[] byteCommands)
throws java.rmi.RemoteException {
return port.write(byteCommands);
}
public byte[] parseString(String command)
throws java.rmi.RemoteException {
return RCXPort.parseString(command);
}
/**
* Received a message from the RCX.
* Send it to the listener
*/
public void receivedMessage(byte[] message) {
this.message = message;
// Send it out to listener
if (listener == null) {
return;
}
RemoteEvent evt = new RemoteEvent(this, MESSAGE_EVENT, messageSeqNo++, null);
try {
listener.notify(evt);
} catch(net.jini.core.event.UnknownEventException e) {
e.printStackTrace();
} catch(java.rmi.RemoteException e) {
e.printStackTrace();
}
}
/**
* Received an error message from the RCX.
* Send it to the listener
*/
public void receivedError(String error) {
// System.err.println(error);
// Send it out to listener
if (listener == null) {
return;
}
this.error = error;
RemoteEvent evt = new RemoteEvent(this, ERROR_EVENT, errorSeqNo, null);
try {
listener.notify(evt);
} catch(net.jini.core.event.UnknownEventException e) {
e.printStackTrace();
} catch(java.rmi.RemoteException e) {
e.printStackTrace();
}
}
/**
* Expected use: the RCX has returned a message,
* and we have informed the listeners. They query
* this method to find the message for the message
* seqence number they were given in the RemoteEvent.
* We could use this as an index into a table of messages.
*/
public byte[] getMessage(long msgSeqNo) {
return message;
}
/**
* Expected use: the RCX has returned an error message,
* and we have informed the listeners. They query
* this method to find the error message for the error message
* seqence number they were given in the RemoteEvent.
* We could use this as an index into a table of messages.
*/
public String getError(long errSeqNo) {
return error;
}
/**
* Add a listener for RCX messages.
* Should allow more than one, or throw
* TooManyListeners if more than one registers
*/
public void addListener(RemoteEventListener listener) {
this.listener = listener;
messageSeqNo = 0;
errorSeqNo = 0;
}
} // RCXPortImpl
module corba {
module HelloApp {
interface Hello {
string sayHello();
};
};
};
package corba.HelloApp;
public interface Hello
extends org.omg.CORBA.Object,
org.omg.CORBA.portable.IDLEntity {
String sayHello();
}
package corba;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import corba.HelloApp.*;
public class JavaHelloImpl implements JavaHello {
protected Hello helloRef = null;
protected String[] argv;
public JavaHelloImpl(String[] argv) {
this.argv = argv;
}
public String sayHello() {
// Hello helloRef = null;
if (helloRef == null) {
helloRef = getHelloRef();
}
// now invoke methods on the CORBA proxy
String hello = helloRef.sayHello();
return hello;
}
protected Hello getHelloRef() {
ORB orb = null;
// Act like a CORBA client
try {
orb = ORB.init(argv, null);
// find the CORBA name server
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
// find the CORBA Hello proxy
NameComponent nc = new NameComponent("Hello", "");
NameComponent path[] = {nc};
org.omg.CORBA.Object obj = ncRef.resolve(path);
Hello helloRef = HelloHelper.narrow(obj);
return helloRef;
} catch(Exception e) {
e.printStackTrace();
return null;
}
}
} // JavaHelloImpl