The first assignment simplified the home networking situation in many ways
java.awt.Button
when the combination
MousePressed/MouseReleased
occurs, to signal
an ActionEvent
PropertyChangeEvent
RemoteEvent
interface Listener {
public void invoke(Event e);
}
java.awt.ActionListener {
void actionPerformed(ActionEvent evt);
}
java.beans.PropertyChangeListener {
void propertyChange(PropertyChangeEvent evt);
}
public interface RemoteEventListener {
public void notify(RemoteEvent evt);
}
Event evt = new Event(...);
listener.invoke(evt);
public class EventSource {
public void setListener(Listener l);
public void removeListener();
public void callListener(Event evt);
}
public class EventSource {
public void addListener(Listener l);
public void removeListener();
public void callListeners(Event evt);
}
The source may have an implementation such as
public class EventSource {
Listener listener = null;
public void setListener(Listener l) {
if (l == null) {
listener = l;
} else {
throw new java.util.TooManyListenersException();
}
}
public void removeListener() {
listener = null;
}
public void callListener(Event evt) {
if (listener != null) {
listener.invoke(evt);
}
}
}
The multiple listener source might be implemented by
public class EventSource {
Vector listeners = new Vector();
public void addListener(Listener l) {
listeners.add(l);
}
public void removeListener(Listener l) {
if ( ! listeners.remove(l)) {
throw new NoSuchListenerException();
}
}
public void callListeners(Event evt) {
Enumeration enum = listeners.elements();
while (enum.hasMoreElements()) {
Listener listener = (Listener) enum.nextElement();
listener.invoke(evt);
}
}
}
EventListenerList
is intended to support
a list that can be made up of different types of listener
EventListenerList listenerList = new EventListenerList();
FooEvent fooEvent = null;
public void addFooListener(FooListener l) {
listenerList.add(FooListener.class, l);
}
public void removeFooListener(FooListener l) {
listenerList.remove(FooListener.class, l);
}
// 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 fireFooXXX() {
// 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]==FooListener.class) {
// Lazily create the event:
if (fooEvent == null)
fooEvent = new FooEvent(this);
((FooListener)listeners[i+1]).fooXXX(fooEvent);
}
}
}
EventHandler
invoke()
, and has no other
methods
EventHandler
can reduce space
requirements of lots of class code
Button
listener
myButton.addActionListener(new ActionListener {
public void actionPerformed(ActionEvent e) {
frame.toFront();
}
});
by
myButton.addActionListener(
(ActionListener)EventHandler.create(ActionListener.class,
frame, "toFront"));
java.awt.EventQueue
does this, but only
for AWT events
public class EventQueue {
public synchronised void addEvent(Event evt);
public synchronised Event getEvent();
public void dispatchEvents();
}
public class EventQueue {
protected Queue queue;
protected Listener listener;
public synchronised void addEvent(Event evt) {
queue.add(evt);
notifyAll();
}
public synchronised Event getEvent() {
if (queue.isEmpty()) {
wait();
}
return (Event) queue.removeElement():
}
public void dispatchEvents() {
while (true) {
Event evt = getEvent();
if (listener != null) {
listener.invoke(evt);
}
}
}
}
invoke()
method
on a remote object
public class World {
public String sayHello() {
return "Hello world";
}
public String sayGoodbye() {
return "Goodbye cruel world";
}
public static void main(String[] args) {
World w = new World();
System.out.println(w.sayHello());
System.out.println(w.sayGoodbye());
}
WorldServer
which reads messages from the network and calls local
server-side methods
WorldStub
that
send messages to the server and reads replies
WorldClient
)
that calls the stub
public class WorldClient {
main() {
create new WorldStub object
call local methods on stub
}
}// WorldClient
public class WorldStub {
public WorldStub() {
create socket to World server
}
public String sayHello() {
write method name "sayHello" to server
read response
return response
}
public String sayGoodbye() {
write method name "sayGoodbye" to server
read response
return response
}
}// WorldStub
public class WorldServer {
main() {
create new WorldServer
}
public WorldServer () {
create server socket
while true
accept client connection socket
handle client socket
}
handleClient() {
while true
read command from client socket
if command is "sayHello"
result = sayHello()
if command is "sayGoodbye"
result = sayGoodbye()
write result to client socket
}
sayHello() {
return "Hello world";
}
sayGoodbye() {
return "Goodbye cruel world";
}
}// WorldServer
public class WorldClient {
public static void main(String[] args) {
WorldStub w = new WorldStub();
System.out.println(w.sayHello());
System.out.println(w.sayGoodbye());
}
}// WorldClient
import java.net.*;
import java.io.*;
public class WorldStub {
private final String SERVER_IP = "127.0.0.1";
private final int PORT = 7890;
private static String SAY_HELLO = "sayHello";
private static String SAY_GOODBYE = "sayGoodbye";
private Socket s;
private BufferedReader in;
private PrintStream out;
public WorldStub() {
try {
InetAddress address = InetAddress.getByName(SERVER_IP);
s = new Socket(address, PORT);
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out = new PrintStream(s.getOutputStream());
} catch(Exception e) {
System.err.println(e);
System.exit(1);
}
}
public String sayHello() {
try {
out.println(SAY_HELLO);
out.flush();
String response = in.readLine();
return response;
} catch(IOException e) {
return "";
}
}
public String sayGoodbye() {
try {
out.println(SAY_GOODBYE);
out.flush();
String response = in.readLine();
return response;
} catch(IOException e) {
return "";
}
}
}// WorldStub
import java.net.*;
import java.io.*;
public class WorldServer {
private static int PORT = 7890;
private static String SAY_HELLO = "sayHello";
private static String SAY_GOODBYE = "sayGoodbye";
public static void main(String[] args) {
new WorldServer();
}
public WorldServer (){
ServerSocket server = null;
try {
server = new ServerSocket(PORT);
} catch(IOException e) {
e.printStackTrace();
System.exit(1);
}
while (true) {
try {
Socket client = server.accept();
handleClient(client);
} catch(IOException e) {
// ignore errors from a client
}
}
}
private void handleClient(Socket client) {
BufferedReader in = null;
PrintStream out = null;
String result = null;
try {
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintStream(client.getOutputStream());
String command = null;
while (true) {
command = in.readLine();
if (command.equals("")) {
break;
}
if (command.equals(SAY_HELLO)) {
result = sayHello();
} else if (command.equals(SAY_GOODBYE)) {
result = sayGoodbye();
}
out.println(result);
}
} catch(Exception e) {
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch(IOException e) {
// nothing we can do
}
}
}
private String sayHello() {
System.err.println("hello");
return "Hello world";
}
private String sayGoodbye() {
System.err.println("bye");
return "Goodbye cruel world";
}
}// WorldServer
public class World {
public String sayHello();
public String sayGoodbye();
}
ObjectOutputStream
and ObjectInputStream
which allow an object
and all the objects that it refers to, to be serialised
(written as a byte stream) and deserialised
Integer
class has a single field, an int
Integer
objects and writes
them to an ObjectOutputStream
ObjectInputStream
and instantiates them locally
World
example
public class IntegerClient {
public static void main(String[] args) {
IntegerStub w = new IntegerStub();
}
}// IntegerClient
import java.net.*;
import java.io.*;
public class IntegerStub {
private final String SERVER_IP = "127.0.0.1";
private final int PORT = 7891;
private Socket s;
private ObjectInputStream in;
public IntegerStub() {
try {
InetAddress address = InetAddress.getByName(SERVER_IP);
s = new Socket(address, PORT);
in = new ObjectInputStream(s.getInputStream());
for (int n = 0; n < 10; n++) {
Integer nObj = (Integer) in.readObject();
System.out.println(nObj.toString());
}
} catch(Exception e) {
System.err.println(e);
System.exit(1);
}
}
}// IntegerStub
import java.net.*;
import java.io.*;
public class IntegerServer {
private static int PORT = 7891;
public static void main(String[] args) {
new IntegerServer();
}
public IntegerServer (){
ServerSocket server = null;
try {
server = new ServerSocket(PORT);
} catch(IOException e) {
e.printStackTrace();
System.exit(1);
}
while (true) {
try {
Socket client = server.accept();
handleClient(client);
} catch(IOException e) {
// ignore errors from a client
}
}
}
private void handleClient(Socket client) {
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(client.getOutputStream());
for (int n = 0; n < 10; n++) {
out.writeObject(new Integer(10-n));
}
} catch(Exception e) {
} finally {
try {
if (out != null) {
out.close();
}
} catch(IOException e) {
// nothing we can do
}
}
}
}// IntegerServer
RMICLassLoader
will load class files
from any valid URL using e.g.
Class RMIClassLoader(String url, String className)
Object Class.newInstance()
interface Foo {
}
public class Foo1 implements Foo {
public String toString() {
return "I'm a Foo 1 object";
}
}
import java.rmi.server.RMIClassLoader;
public class LoadFoo {
public static void main(String[] args) {
try {
Class cls =
RMIClassLoader.loadClass(
"file://home/httpd/html/internetdevices/infrastructure/",
"Foo1");
Foo foo = (Foo) cls.newInstance();
System.out.println(foo.toString());
cls = RMIClassLoader.loadClass(
"file://home/httpd/html/internetdevices/infrastructure/",
"Foo2");
foo = (Foo) cls.newInstance();
System.out.println(foo.toString());
cls = RMIClassLoader.loadClass(
"file://home/httpd/html/internetdevices/infrastructure/",
"Foo3");
foo = (Foo) cls.newInstance();
System.out.println(foo.toString());
} catch(Exception e) {
e.printStackTrace();
}
}
}
MarshalledObject
combines both
serialisation of an object's instance data and information
about the location of the class files
MarshalledObject
can be unmarshalled,
and will load the class files and restore object state
MarshalledObject(Object obj)
Object get()
java.rmi.server.codebase
to set the location
of the class file
java -Djava.rmi.server.codebase=...
System.setProperty("java.rmi.server.codebase", ...)
ObjectOutputStream
ObjectInputStream
,
casts it to MarshalledObject
and calls get
There are a variety if ways that one object can call methods on another, even if they are remote