Using different middleware

Same problem, different middleware

The client-half object pattern has been given as a means of abstracting away from particular middleware solutions, so that code not directly involved in networking is not affected by changes of middleware.

In this section, we look at the "simple ftp" problem considered earlier, and give a variety of solutions using different middleware systems

Service specification

We specify the service using a Java interface.


package common;

import java.rmi.RemoteException;
import java.io.IOException;

public interface FileTransfer extends java.rmi.Remote {

    public boolean chdir(String dir) throws RemoteException;

    public String[] dir() throws RemoteException;

    public String getdir() throws RemoteException;

    public String get(String filename) throws RemoteException, IOException;

    public void quit() throws RemoteException;
}

There is a concession to lessons from RMI being adopted by a number of middleware systems: in recognition that network errors can occur in calling remote services, the interface extends Remote and all methods throw RemoteException. This exception should not be visible "on the wire" since it is not a cross-platform solution - for example, .NET remoting has its different equivalent System.Runtime.Remoting.RemotingException However, these exceptions are normally generated in the client HOPP and do not appear on the wire. Web Services don't conform to this and the WSDL lists remote exceptions even though they are not generated on the service side.

Service Implementation


package server;

import java.io.File;
import java.io.IOException;
import common.FileTransfer;

public class FileTransferServerHOPP implements FileTransfer {
    File clientDir = new File(".");
    
    public boolean chdir(String dir) {
	File newDir = new File(clientDir, dir);
	if (newDir.isDirectory()) {
	    clientDir = newDir;
	    return true;
	} else {
	    return false;
	}
    }

    public String[] dir() {
	String[] fileNames = clientDir.list();
	// list() doesn't show current and parent dirs, so add them
	String[] allFileNames = new String[fileNames.length + 2];
	allFileNames[0] = ".";
	allFileNames[1] = "..";
	for (int n = 0; n < fileNames.length; n++) {
	    allFileNames[n+2] = fileNames[n];
	}
	
	return allFileNames;
    }

    public String getdir() {
	try {
	    return clientDir.getCanonicalPath();
	} catch(IOException e) {
	    return "";
	}
    }

    public String get(String filename) {
	// stub
	return "";
    }

    public void quit() {
    }
}

Client view

Client UI

The client UI is independent of the network code. It just needs to know that the client half-object implements the common interface common.FileTransfer. To avoid hard-coding the actual half-object into the UI, a call is made to a factory object.


package client;

import java.io.*;
import java.net.*;
import java.rmi.RemoteException;

import common.FileTransfer;
import common.FileTransferFactory;

public class FileTransferClientUI {
    
    private static String DIR = "dir";
    private static String QUIT = "quit";
    private static String CD = "cd";
    private static String GETDIR ="getdir";
    private static String GET ="get";

    private BufferedReader console;
    private FileTransfer clientHOPP;

    public static void main(String[] args){

	if (args.length < 1) {
	    System.err.println("Usage: Client args");
	    System.exit(1);
	}

	FileTransfer clientHOPP = null;
	try {
	    clientHOPP = FileTransferFactory.newClient(args);
	} catch (Exception e) {
	    e.printStackTrace();
	    System.exit(1);
	}
	if (clientHOPP == null) {
	    System.out.println("Unknown client type");
	    System.exit(2);
	}
	
	
	FileTransferClientUI ui = new FileTransferClientUI(clientHOPP);
	ui.loop();
    }

    public FileTransferClientUI(FileTransfer clientHOPP) {

	this.clientHOPP = clientHOPP;
	console = new BufferedReader(new InputStreamReader(System.in));
    }

    public void loop() {
	while (true) {
	    String line = null;
	    try {
		System.out.print("Enter request: ");
		line = console.readLine();
		if (line == null) {
		    break;
		}
		System.out.println("Request was " + line);
	    } catch(IOException e) {
		e.printStackTrace();
		quit();	    
	    }

	    if (line.equals(DIR)) {
		dir();
	    } else if (line.startsWith(CD)) {
		chdir(losePrefix(line, CD));
	    } else if (line.startsWith(GETDIR)) {
		getdir();
	    } else if (line.startsWith(GET)) {
		get(losePrefix(line, GET));
	    } else if (line.equals(QUIT)) {
		quit();
	    } else {
		System.out.println("Unrecognised command");
	    }
	}
    }

    /**
     * Given that the string starts with the prefix,
     * get rid of the prefix and any whitespace
     */
    public String losePrefix(String str, String prefix) {
	int index = prefix.length();
	String ret = str.substring(index).trim();
	return ret;
    }

    protected void dir() {
	String[] dirList = null;
	try {
	    dirList = clientHOPP.dir();
	} catch (RemoteException e) {
	    System.out.println("Error in remote call " + e.toString());
	}
	if (dirList == null) {
	    System.out.println("No dir list available");
	} else {
	    for (int n = 0; n < dirList.length; n++) {
		System.out.println(dirList[n]);
	    }
	}
    }

    public void chdir(String dir) {
	try {
	    if (clientHOPP.chdir(dir)) {
		System.out.println("Chdir okay");
	    } else {
		System.out.println("Chdir failed");
	    }
	} catch (RemoteException e) {
	    System.out.println("Error in remote call " + e.toString());
	}
    }

    public void getdir() {
	try {
	    String dir = clientHOPP.getdir();
	    System.out.println("Current dir: " + dir);
	} catch (RemoteException e) {
	    System.out.println("Error in remote call " + e.toString());
	}
    }

    public void get(String filename) {
	// omitted
    }

    private void quit() {
	try {
	    clientHOPP.quit();
	} catch (RemoteException e) {
	    // nothing	    
	}
	System.exit(0);
    }
} // FileTransferClientUI








Factory

A factory object is used to generate specific client half-objects. It uses command line parameters passed from the UI object to determine which half-object to return. All half-objects implement the FileTransfer interface


package common;

import java.util.ArrayList;

public class FileTransferFactory {

    public static FileTransfer newClient(String[] args) throws Exception {
	String type = args[0];

	if (type.equals("socket")) {
	    return new socket.FileTransferClientHOPP(args[1]);
	}
	if (type.equals("webservice")) {
	    return new webservice.FileTransferClientHOPP(args[1]);
	}
	if (type.equals("corba")) {
	    // lose 1st element
	    String[] shortArgs = new String[args.length - 1];
	    for (int n = 0; n < args.length-1; n++) {
		shortArgs[n] = args[n + 1];
	    }
	    return new corba.FileTransferClientHOPP(shortArgs);
	}
	if (type.equals("rmi")) {
	    return new rmi.FileTransferClientHOPP(args[1]);
	}
	return null;
    }
}

Sockets

The socket-based solution requires a client half-object and a server talking across an ordinary socket

Socket constants

This just defines strings that are common to both client and server


package socket;

/**
 * FileTransferConstants.java
 *
 *
 * Created: Sun Jul 29 21:36:11 2001
 *
 * @author <a href="mailto: "Jan Newmarch</a>
 * @version
 */

public class FileTransferConstants {

    public static final String CD = "CD";
    public static final String DIR = "DIR";
    public static final String GET = "GET";
    public static final String GETDIR = "GETDIR";
    public static final String ERROR = "ERROR";
    public static final String SUCCEEDED = "SUCCEEDED";
    public static final String QUIT = "QUIT";
    public static final int PORT = 18889;
    public static final String CR_LF = "\r\n";
}// FileTransferConstants

Socket client


package socket;

/**
 * FileTransferClientHOPP.java
 *
 *
 * Created: Fri Jul 20 12:54:51 2001
 *
 * @author <a href="mailto: "Jan Newmarch</a>
 * @version
 */
import java.io.*;
import java.net.*;
import common.FileTransfer;
import java.rmi.RemoteException;

public class FileTransferClientHOPP implements FileTransfer {

    protected Socket sock;
    protected BufferedReader reader;
    protected PrintStream writer;

    public FileTransferClientHOPP(String server)
	throws UnknownHostException, IOException {

	InetAddress address = InetAddress.getByName(server);

	sock = null;
	InputStream in = null;
	OutputStream out = null;

	sock = new Socket(address, FileTransferConstants.PORT);
	in = sock.getInputStream();
	out = sock.getOutputStream();

	reader = new BufferedReader(new InputStreamReader(in));
	writer = new PrintStream(out);
    }

    public void quit()  throws RemoteException {
	try {
	    writer.print(FileTransferConstants.QUIT +
			 FileTransferConstants.CR_LF);
	    reader.close();
	    writer.close();
	    sock.close();
	} catch(Exception e) {
	    throw new RemoteException("Quit failed", e);
	}
    }

    public String[] dir() {
	// stub
	return null;
    }

    public boolean chdir(String dir) throws RemoteException {
	writer.print(FileTransferConstants.CD + " " + dir + 
		     FileTransferConstants.CR_LF);

	String response = null;
	try {
	    response = reader.readLine();
	} catch(IOException e) {
	    throw new RemoteException("Chdir failed", e);
	}
	if (response.startsWith(FileTransferConstants.SUCCEEDED)) {
	    return true;
	} else {
	    return false;
	}
    }

    public String getdir()  throws RemoteException {
	writer.print(FileTransferConstants.GETDIR + FileTransferConstants.CR_LF);
	String response = null;
	try {
	    response = reader.readLine();
	} catch(IOException e) {
	    throw new RemoteException("Chdir failed", e);
	}
	return response;
    }

    public String get(String filename) throws RemoteException {
	// stub
	return "";
    }
} // FileTransferClientHOPP








Socket server


package socket;

import java.io.*;
import java.net.*;

import server.FileTransferServerHOPP;

public class FileTransferServer {
    
    public static void main(String argv[]) {
	ServerSocket s = null;
	try {
	    s = new ServerSocket(FileTransferConstants.PORT);
	} catch(IOException e) {
	    System.out.println(e);
	    System.exit(1);
	}

	while (true) {
	    Socket incoming = null;
	    try {
		incoming = s.accept();
	    } catch(IOException e) {
		System.out.println(e);
		continue;
	    }

	    new SocketHandler(incoming).start();
	}
    }
}

class SocketHandler extends Thread {

    Socket incoming;
    FileTransferServerHOPP fileServer = new FileTransferServerHOPP();

    BufferedReader reader;
    PrintStream out;

    SocketHandler(Socket incoming) {
	this.incoming = incoming;
    }

    public void run() {
	try {
	    reader = new BufferedReader(new InputStreamReader(
					incoming.getInputStream()));
	    out = new PrintStream(incoming.getOutputStream());
	    
	    while (true) {
		String line = reader.readLine();
		if (line == null) { 
		    break;
		}
		System.out.println("Received request: " + line);

		if (line.startsWith(FileTransferConstants.CD)) {
		    changeDirRequest(losePrefix(line, 
						FileTransferConstants.CD));
		} else if (line.startsWith(FileTransferConstants.DIR)) {
		    directoryRequest();
		} else if (line.startsWith(FileTransferConstants.GETDIR)) {
		    getdirRequest();
		} else if (line.startsWith(FileTransferConstants.GET)) {
		    // code omitted
		} else if (line.startsWith(FileTransferConstants.QUIT)) {
		    break;
		} else {
		    out.print(FileTransferConstants.ERROR + 
			      FileTransferConstants.CR_LF);
		}
		
	    }
	    incoming.close();
	} catch(IOException e) {
	    e.printStackTrace();
	}
    }


    /**
     * Given that the string starts with the prefix,
     * get rid of the prefix and any following whitespace
     */
    public String losePrefix(String str, String prefix) {
	int index = prefix.length();
	String ret = str.substring(index).trim();
	return ret;

    }

    public void changeDirRequest(String dir) {
	if (fileServer.chdir(dir)) {
	    out.print(FileTransferConstants.SUCCEEDED + " " +
		      fileServer.getdir() +
		      FileTransferConstants.CR_LF);
	} else {
	    out.print(FileTransferConstants.ERROR +
		      FileTransferConstants.CR_LF);
	}
    }

    public void getdirRequest() {
	out.print(fileServer.getdir() + 
		  FileTransferConstants.CR_LF);
    }

    public void directoryRequest() {
	String[] fileNames = fileServer.dir();
	if (fileNames == null) {
	    out.print(FileTransferConstants.ERROR +
		      FileTransferConstants.CR_LF);
	}
	for (int n = 0; n < fileNames.length; n++) {
	    out.print(fileNames[n] +
		      FileTransferConstants.CR_LF);
	}
	out.print(FileTransferConstants.CR_LF);
    }
}

Running

To run the server,

java socket.FileTransferServer
To run the client
java client.FileTransferClientUI socket localhost

Web services

Instant deployment using Axis

Steps:


Instant deployment Service HOPP

Client HOPP

There are several ways of building a client HOPP. One way is to generate the WSDL and from there generate a set of client-side classes. This is the technically simpler but more laborious way based on constructing each function call by hand. Note that call.invoke() will throw a RemoteException if an error occurs.


package webservice;

import java.io.IOException;
import java.rmi.RemoteException;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.namespace.QName;
  
import common.FileTransfer;

public class FileTransferClientHOPP implements FileTransfer {

    private Call call;

    public FileTransferClientHOPP(String host) throws Exception {
	String endpoint =
	    "http://" + host + ":8088/axis/FileTransferServerHOPP.jws";
	
	Service service = new Service();
	call    = (Call) service.createCall();
	
	call.setTargetEndpointAddress( new java.net.URL(endpoint) );
    }

    public void quit() throws RemoteException {
	call.setOperationName(new QName("http://soapinterop.org/", "quit"));
	call.invoke( new Object[] {} );
    }

    public String[] dir() throws RemoteException {
	call.setOperationName(new QName("http://soapinterop.org/", "dir"));
	String[] ret = (String []) call.invoke( new Object[] {} );
	return ret;
    }

    public boolean chdir(String dir) throws RemoteException {
	call.setOperationName(new QName("http://soapinterop.org/", "chdir"));
	Boolean ret = (Boolean) call.invoke( new Object[] { dir } );
	return ret.booleanValue();
    }

    public String getdir() throws RemoteException {
	call.setOperationName(new QName("http://soapinterop.org/", "getdir"));
	String ret = (String) call.invoke( new Object[] {} );
	return ret;
    }

    public String get(String filename) throws RemoteException, IOException {
	call.setOperationName(new QName("http://soapinterop.org/", "get"));
	String ret = (String) call.invoke( new Object[] { filename } );
	return ret;
    }
}

Running

Download Axis from Apache.org. Copy the FileTransferClientHOPP.java to the axis subdirectory with the .jws extension. Start Axis

To run the client, the classpath needs to include the Axis libraries and also the Xerces XML parser library. Then

java -classpath ... client.FileTransferClientUI webservice localhost

CORBA

IDL

The file ftp.idl contains


module corba {
  typedef sequence<string> string_seq;

  interface FileTransfer {
    boolean chdir(in string dir);
    string_seq dir();
    string getdir();
    string get(in string filename);
    void quit();
  };
};

Generate files by


idlj -fall ftp.idl
See http://java.sun.com/j2se/1.5.0/docs/guide/rmi-iiop/toJavaPortableUG.html

Generated files are

CORBA generates its own interfaces and classes. By specifying the module as corba, it generates the corba.FileTransfer, not common.FileTransfer. It also introduces classes such as FileTransferPOA which have to be used. So introduce a "wrapper" class to translate between CORBA and our implementation.

CORBA Server


package corba;

/**
 * FileTransferServer.java
 *
 *
 * Created: Wed Sep 21 11:22:44 2005
 *
 * @author <a href="mailto:jan.newmarch@infotech.monash.edu.au">Jan Newmarch</a>
 * @version 1.0
 */

import java.io.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import org.omg.PortableServer.*;
import org.omg.PortableServer.POA;

import java.util.Properties;

public class FileTransferServer {
 
    static public void main(String[] args) {
	try{
	    // create and initialize the ORB
	    ORB orb = ORB.init(args, null);
	    
	    // get reference to rootpoa & activate the POAManager
	    POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
	    rootpoa.the_POAManager().activate();
	    
	    // create servant and register it with the ORB
	    FileTransferImpl impl = new FileTransferImpl();
	    //	    impl.setORB(orb); 
	    
	    // get object reference from the servant
	    org.omg.CORBA.Object ref = rootpoa.servant_to_reference(impl);
	    FileTransfer href = FileTransferHelper.narrow(ref);
	    
	    // get the root naming context
	    // NameService invokes the name service

	    org.omg.CORBA.Object objRef =
		orb.resolve_initial_references("NameService");

	    // Use NamingContextExt which is part of the Interoperable
	    // Naming Service (INS) specification.
	    NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
	    
	    // bind the Object Reference in Naming
	    String name = "FileTransfer";
	    NameComponent path[] = ncRef.to_name( name );
	    ncRef.rebind(path, href);
	    
	    System.out.println("FileTransferServer ready and waiting ...");
	    
	    // wait for invocations from clients
	    orb.run();
	} 
	catch (org.omg.CORBA.SystemException e) {
	    System.err.println("CORBA ERROR: " + e);
	    e.printStackTrace(System.out);
	}

	catch (org.omg.CORBA.UserException e) {
	    System.err.println("CORBA User ERROR: " + e);
	    e.printStackTrace(System.out);
	}
	
	catch (Exception e) {
	    System.err.println("ERROR: " + e);
	    e.printStackTrace(System.out);
	}
	
	System.out.println("FileTransferServer Exiting ...");
    }
} // FileTransferServer

CORBA Server HOPP


package corba;

/**
 * FileTransferImpl.java
 *
 *
 * Created: Wed Sep 21 11:34:08 2005
 *
 * @author <a href="mailto:jan.newmarch@infotech.monash.edu.au">Jan Newmarch</a>
 * @version 1.0
 */

import server.FileTransferServerHOPP;

public class FileTransferImpl extends FileTransferPOA {

    private FileTransferServerHOPP serverHOPP = new FileTransferServerHOPP();

    public FileTransferImpl() {
	
    } // FileTransferImpl constructor
    
    public boolean chdir(String dir) {
	return serverHOPP.chdir(dir);
    }

    public String[] dir() {
	return serverHOPP.dir();
    }

    public String getdir() {
	return serverHOPP.getdir();
    }

    public String get(String filename) {
	return serverHOPP.get(filename);
    }

    public void quit() {
	serverHOPP.quit();
    }
} // FileTransferImpl

CORBA Client HOPP

CORBA IDL allows the application-defined exceptions. However, any remote method call can also throw an exception. These exceptions are unchecked, that is, they do not form part of the method signature and do not need to be caught. However, if an unchecked exception is thrown and not caught, then it will terminate the application. So it is better to catch them. They are all subclasses of org.omg.CORBA.SystemException.


package corba;

/**
 * FileTransferClientHOPP.java
 *
 *
 * Created: Wed Sep 21 12:19:55 2005
 *
 * @author <a href="mailto:jan.newmarch@infotech.monash.edu.au">Jan Newmarch</a>
 * @version 1.0
 */

// import common.FileTransfer;

import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
import java.rmi.RemoteException;
import java.io.IOException;
import org.omg.CORBA.SystemException;

public class FileTransferClientHOPP implements common.FileTransfer {

    private corba.FileTransfer impl;

    public FileTransferClientHOPP(String[] args) {
	try{
	    // create and initialize the ORB
	    ORB orb = ORB.init(args, null);
	    
	    // get the root naming context
	    org.omg.CORBA.Object objRef = 
		orb.resolve_initial_references("NameService");
	    // Use NamingContextExt instead of NamingContext. This is 
	    // part of the Interoperable naming Service.  
	    NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
	    
	    // resolve the Object Reference in Naming
	    String name = "FileTransfer";
	    impl = FileTransferHelper.narrow(ncRef.resolve_str(name));
	    
	    System.out.println("Obtained a handle on server object: " + impl);
	    
	} catch (Exception e) {
	    System.out.println("ERROR : " + e) ;
	    e.printStackTrace(System.out);
	}
    } // FileTransferClientHOPP constructor
    
    public boolean chdir(String dir) throws RemoteException{
	try {
	    return impl.chdir(dir);	     
	} catch (SystemException e) {
	    throw new RemoteException("CORBA exception", e);
	}	
    }

    public String[] dir() throws RemoteException {
	try {
	    return impl.dir();
	} catch (SystemException e) {
	    throw new RemoteException("CORBA exception", e);
	}	
    }

    public String getdir() throws RemoteException {
	try {
	    return impl.getdir();
	} catch (SystemException e) {
	    throw new RemoteException("CORBA exception", e);
	}	
    }

    public String get(String filename) throws RemoteException, IOException {
	try {
	    return impl.get(filename);
	} catch (SystemException e) {
	    throw new RemoteException("CORBA exception", e);
	}	
    }

    public void quit() throws RemoteException {
	try {
	    impl.quit();
	} catch (SystemException e) {
	    throw new RemoteException("CORBA exception", e);
	}	
    }

} // FileTransferClientHOPP

Running

A name server needs to run

tnameserv -ORBInitialPort 9876

Then you can run the server

java corba.FileTransferServer \
	  -ORBInitialHost localhost \
	  -ORBInitialPort 9876

The client is

java client.FileTransferClientU corba \
	  -ORBInitialHost localhost \
	  -ORBInitialPort 9876

RMI

RMI client


package rmi;

/**
 * FileTransferClientHOPP.java
 *
 *
 * Created: Thu Sep 22 10:58:07 2005
 *
 * @author <a href="mailto:jan.newmarch@infotech.monash.edu.au">Jan Newmarch</a>
 * @version 1.0
 */

import common.FileTransfer;
import java.rmi.RemoteException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
import java.rmi.Naming;

public class FileTransferClientHOPP implements FileTransfer {

    private FileTransfer proxy;

    public FileTransferClientHOPP(String server) 
	throws MalformedURLException, NotBoundException, RemoteException  {

	// find the object
        System.setSecurityManager(new java.rmi.RMISecurityManager());

	proxy = (FileTransfer) Naming.lookup("rmi://" + server + "/FileTransfer");
    } // FileTransferClientHOPP constructor
    
    public boolean chdir(String dir) throws RemoteException {
	return proxy.chdir(dir);
    }

    public String[] dir() throws RemoteException {
	return proxy.dir();
    }

    public String getdir() throws RemoteException {
	return proxy.getdir();
    }

    public String get(String filename) throws RemoteException, IOException {
	return proxy.get(filename);
    }

    public void quit() throws RemoteException {
	proxy.quit();
    }
} // FileTransferClientHOPP

RMI server


package rmi;

/**
 * FileTransferServer.java
 *
 *
 * Created: Thu Sep 22 10:52:48 2005
 *
 * @author <a href="mailto:jan.newmarch@infotech.monash.edu.au">Jan Newmarch</a>
 * @version 1.0
 */

import java.rmi.RemoteException;
import java.rmi.Naming;
import common.FileTransfer;
import server.FileTransferServerHOPP;
import java.rmi.server.RemoteStub;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RMISecurityManager;

public class FileTransferServer{
    
    public static void main(String[] args) {
	FileTransfer fileServer = null;

	System.setSecurityManager(new RMISecurityManager());

	fileServer = new FileTransferServerHOPP();
	RemoteStub stub = null;
	try {
	    stub = UnicastRemoteObject.exportObject(fileServer);
	} catch (RemoteException e) {
	    e.printStackTrace();
	    System.exit(1);
	}
	
	System.out.println("Running");
	// make it public - advertise it

	try {
	    Naming.rebind("rmi://localhost/FileTransfer", fileServer);
	} catch(RemoteException e) {
	    e.printStackTrace();
	    System.exit(1);
	}  catch(java.net.MalformedURLException e) {
            System.out.println(e);
            System.exit(1);
        }

	// main can now finish. An RMI thread keeps the server alive
    }
} // FileTransferServer

Running

Run an RMI name server

rmiregistry

Run the server


java -classpath classes \
     -Djava.rmi.server.codebase=http://localhost/classes/ \
     -Djava.security.policy=policy.all \
     rmi.FileTransferServer

Run the client


java -classpath classes \
     -Djava.security.policy=policy.all \
     client.FileTransferClientUI \
     rmi \
     localhost

Alternative clients

The HOPP model shows that we can change the middleware without too many problems for a decent middleware system. But we can also change the UI for any given system in the same way!

Here is a GUI based client that uses Swing and exactly the same HOPP objects


package client;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import common.FileTransfer;
import common.FileTransferFactory;
import java.rmi.RemoteException;

public class FileTransferClientGUI extends JFrame implements ActionListener {

    private JLabel dirLabel;
    private JList dirList;
    private JButton getBtn;
    private JButton chdirBtn;
    private JButton quitBtn;

    private FileTransfer clientHOPP;

    public static void main(String args[]) {

	if (args.length < 1) {
	    System.err.println("Usage: Client args");
	    System.exit(1);
	}

	FileTransfer clientHOPP = null;
	try {
	    clientHOPP = FileTransferFactory.newClient(args);
	} catch (Exception e) {
	    e.printStackTrace();
	    System.exit(1);
	}
	if (clientHOPP == null) {
	    System.out.println("Unknown client type");
	    System.exit(2);
	}

	new FileTransferClientGUI(clientHOPP);
    }

    FileTransferClientGUI(FileTransfer clientHOPP) {
	this.clientHOPP = clientHOPP;

	Container pane = getContentPane();

	pane.setLayout(new BorderLayout());

	// directory label in the top
	dirLabel = new JLabel("Current dir:");
	pane.add(BorderLayout.NORTH, dirLabel);

	// directory listing in the middle
	dirList = new JList();
	dirList.setModel(new DefaultListModel());
	JScrollPane scrollPane = new JScrollPane();
	scrollPane.getViewport().setView(dirList);

	pane.add(BorderLayout.CENTER, scrollPane);

	// pane full of buttons in the bottom
	JPanel buttons = new JPanel();
	pane.add(BorderLayout.SOUTH, buttons);

	makeButtons(buttons);

	populateGUI();

	setSize(400, 600);
	setVisible(true);
    }

    private void makeButtons(JPanel buttons) {
	buttons.setLayout(new GridLayout(1, 3));

	getBtn = new JButton("Get");
	chdirBtn = new JButton("Chdir");
	quitBtn = new JButton("Quit");

	buttons.add(getBtn);
	buttons.add(chdirBtn);
	buttons.add(quitBtn);
	
	getBtn.addActionListener(this);
	chdirBtn.addActionListener(this);
	quitBtn.addActionListener(this);
    }

    public void populateGUI() {
	try {
	    String dir = clientHOPP.getdir();
	    dirLabel.setText("Current dir: " + dir);
	} catch (RemoteException e) {
		// display warning dialog?	    
	}

	try {
	    String[] list = clientHOPP.dir();
	    setDirList(list);
	} catch (RemoteException e) {
	    // display warning dialog?
	}
    }
    
    public void setDirList(String[] list) {
	DefaultListModel model = (DefaultListModel) dirList.getModel();
	System.out.println("Class "+model.getClass().toString()); 

	model.clear();
	if (list == null) {
	    return;
	}
	
	for (int n = 0; n < list.length; n++) {
	    model.addElement(list[n]);
	}
    }

    public void actionPerformed(ActionEvent evt) {
	Object source = evt.getSource();

	if (source == getBtn) {
	    try {
		String[] list = clientHOPP.dir(); 
		setDirList(list);
	    } catch (RemoteException e) {
		// display warning dialog
	    }
	    return;
	} 
	if (source == chdirBtn) {
	    String dir = (String) dirList.getSelectedValue();
	    if (dir == null) {
		return;
	    }
	    try {
		if (clientHOPP.chdir(dir)) {
		    dirLabel.setText("Current dir: " + clientHOPP.getdir());
		    
		    String[] list = clientHOPP.dir(); 
		    setDirList(list);
		} else {
		    // display warning dialog		    		     
		}				
	    } catch (RemoteException e) {
		// display warning dialog		    
	    }
	    return;
	}
	if (source == quitBtn) {
	    try {
		clientHOPP.quit(); 
	    } catch (RemoteException e) {
		// display warning dialog?
	    }
	    System.exit(0);
	}
    }
}

Session state


Jan Newmarch <jan@newmarch.name>
Last modified: Tue Sep 19 16:42:24 EST 2006
Copyright © Jan Newmarch, Monash University, 2007
Creative Commons License This work is licensed under a Creative Commons License
The moral right of Jan Newmarch to be identified as the author of this page has been asserted.