diff options
author | eea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1999-08-24 23:10:38 +0000 |
---|---|---|
committer | eea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1999-08-24 23:10:38 +0000 |
commit | 3510b1fbc485d9f04e4d209637fcaa0d48bb61c4 (patch) | |
tree | 3c67b96e6b4c23d872d68a2e09bd884f1d2f970e | |
parent | e4012b2dc8297540c9501a10daa8b8746d55297e (diff) | |
download | ATCD-3510b1fbc485d9f04e4d209637fcaa0d48bb61c4.tar.gz |
Updated source files for Connection.
-rw-r--r-- | java/JACE/Connection/AcceptStrategy.java | 87 | ||||
-rw-r--r-- | java/JACE/Connection/Acceptor.java | 215 | ||||
-rw-r--r-- | java/JACE/Connection/ActivateStrategy.java | 40 | ||||
-rw-r--r-- | java/JACE/Connection/Blob.java | 114 | ||||
-rw-r--r-- | java/JACE/Connection/BlobHandler.java | 35 | ||||
-rw-r--r-- | java/JACE/Connection/BlobReader.java | 108 | ||||
-rw-r--r-- | java/JACE/Connection/BlobWriter.java | 224 | ||||
-rw-r--r-- | java/JACE/Connection/Connector.java | 148 | ||||
-rw-r--r-- | java/JACE/Connection/CreationStrategy.java | 57 | ||||
-rw-r--r-- | java/JACE/Connection/HTTPHelper.java | 182 | ||||
-rw-r--r-- | java/JACE/Connection/StrategyAcceptor.java | 174 | ||||
-rw-r--r-- | java/JACE/Connection/SvcHandler.java | 101 | ||||
-rw-r--r-- | java/JACE/Connection/package.html | 7 |
13 files changed, 1492 insertions, 0 deletions
diff --git a/java/JACE/Connection/AcceptStrategy.java b/java/JACE/Connection/AcceptStrategy.java new file mode 100644 index 00000000000..3af87865c79 --- /dev/null +++ b/java/JACE/Connection/AcceptStrategy.java @@ -0,0 +1,87 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * AcceptStrategy.java + * + *@author Prashant Jain + *@author Everett Anderson + * + *************************************************/ +package JACE.Connection; + +import java.io.*; +import java.net.*; +import JACE.SOCK_SAP.*; + +/** + * Interface for specifying a passive connection + * acceptance strategy for a + * <a href="ACE.Connection.SvcHandler.html"><tt>SvcHandler</tt></a> + * . + * <P> + * This class provides a strategy that manages passive + * connection setup for an application, and can be extended + * to define new strategies. + * <P> + * + * The default implementation delegates to a generic Acceptor. + * + *@see SvcHandler + *@see Acceptor + */ +public class AcceptStrategy +{ + /** + * Create an instance of AcceptStrategy that delegates to the given + * Acceptor. + *@param port port number where the server will listen for connections + *@param peer Acceptor instance to delegate to + */ + AcceptStrategy (int port, Acceptor peer) throws IOException + { + this.acceptor_ = peer; + this.open (port); + } + + /** + * Create an instance of Accept Strategy that delegates to Acceptor. + *@param port port number where the server will listen for connections + *@exception IOException couldn't open port + */ + AcceptStrategy (int port) throws IOException + { + this.acceptor_ = new Acceptor (); + this.open (port); + } + + /** + * Initialize AcceptStrategy. + *@param port port number where the server will listen for connections + *@exception IOException couldn't open port + */ + public void open (int port) throws IOException + { + this.acceptor_.open (port); + } + + /** + * Accept connections into the SvcHandler. Note that subclasses + * should overwrite this method to provide a different accept + * strategy. + *@param sh Svc Handler in which to accept the connection + *@exception SocketException Socket error + *@exception IOException Socket error + *@return 0 + */ + public int acceptSvcHandler (SvcHandler sh) throws + SocketException, IOException + { + return this.acceptor_.acceptSvcHandler (sh); + } + + // The Acceptor we delegate to (if any) + private Acceptor acceptor_; +} diff --git a/java/JACE/Connection/Acceptor.java b/java/JACE/Connection/Acceptor.java new file mode 100644 index 00000000000..00dbed4c056 --- /dev/null +++ b/java/JACE/Connection/Acceptor.java @@ -0,0 +1,215 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * Acceptor.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + +import java.io.*; +import java.net.*; +import JACE.OS.*; +import JACE.SOCK_SAP.*; +import JACE.ServiceConfigurator.*; + +/** + * Abstract factory for creating a service handler + * (<a href="ACE.Connection.SvcHandler.html"><tt>SvcHandler</tt></a>), + * accepting into the + * <a href="ACE.Connection.SvcHandler.html"><tt>SvcHandler</tt></a>, and activating the + * <a href="ACE.Connection.SvcHandler.html"><tt>SvcHandler</tt></a>. + * <P> + * + * Implements the basic strategy for passively establishing + * connections with applications. The <tt>Acceptor</tt> + * is a factory for <tt>SvcHandler</tt> instances, and, by default + * generates a new <tt>SvcHandler</tt> instance for each connection + * esablished. + * + * <p> + * + * The user of this class <em>must</em> provide a + * reference to a handler factory prior to calling <a + * href="#accept()"><tt>accept</tt></a>, or an exception will be + * thrown. The handler factory is identified by the meta-class for + * the <tt>SvcHandler</tt>, and is typically obtained by calling <a + * href="java.lang.Class#classForName(java.lang.String)"><tt>Class.classForName("SvcHandler")</tt></a>. + * + * <p> + * + * TCP is the transport mechanism used, via + * <a href="ACE.SOCK_SAP.SOCKAcceptor.html#_top_"><tt>SOCKAcceptor</tt></a>, + * <em>et.al.</em> The SvcHandler is instantiated with a concrete type + * that performs the application-specific service. + * + * <P> + * + * This class is not directly related to the + * <tt>AcceptorStrategy</tt> class. + * + * + * @see java.lang.Class + * @see JACE.Connection.SvcHandler + * @see JACE.SOCK_SAP.SOCKAcceptor + */ +public class Acceptor extends ServiceObject +{ + /** + * Create an instance of Acceptor. Default constructor. Note that if + * an instance is created via this method, <tt>setHandlerFactory</tt> + * must be called prior to using <tt>accept</tt>. + * + * @see JACE.Connection.Acceptor#setHandlerFactory + */ + public Acceptor () + { + } + + /** + * Create an instance of Acceptor. + *@param handlerFactory meta-class reference used to create + * an instance of a SvcHandler when a connection is accepted + * (typically obtained by calling <tt>Class.classForName</tt>). + * + *@see java.lang.Class#forName + */ + public Acceptor (Class handlerFactory) + { + this.handlerFactory_ = handlerFactory; + } + + /** + * Set the handler factory. This is provided to aid the default + * no-arg constructor. + *@param handlerFactory meta-class reference used to create + * an instance of a SvcHandler when a connection is accepted + * (typically obtained by calling <tt>Class.forName</tt>). + * + *@see java.lang.Class#forName + */ + public void setHandlerFactory (Class handlerFactory) + { + this.handlerFactory_ = handlerFactory; + } + + /** + * Initialize the Acceptor. + *@param port TCP port number where the Acceptor will listen for connections + *@exception IOException socket level exception + */ + public void open (int port) throws IOException + { + this.port_ = port; + this.sockAcceptor_ = new SOCKAcceptor (port); + } + + /** + * Template method for accepting connections. Delegates operational + * activities to the following bridge methods: + * <ul> + * <li><tt>makeSvcHandler</tt></li> + * <li><tt>acceptSvcHandler</tt></li> + * <li><tt>activateSvcHandler</tt></li> + * </ul> + * + * <p> + * + * The method first obtains a <tt>SvcHandler</tt> via + * <tt>makeSvcHandler</tt>, accepts the connection <q>into</q> the + * handler using <tt>acceptSvcHandler</tt>, and finally turns over + * control to the handler with <tt>activateSvcHandler</tt>. + * + *@exception SocketException socket level error + *@exception InstantiationException <tt>makeSvcHandler</tt> failure + *@exception IllegalAccessException <tt>makeSvcHandler</tt> failure + *@exception IOException socket level error + */ + public void accept () throws SocketException, + InstantiationException, + IllegalAccessException, + IOException + { + + // Create a Svc_Handler using the appropriate Creation_Strategy + SvcHandler sh = this.makeSvcHandler (); + + // Accept a connection into the SvcHandler using the appropriate + // Accept_Strategy + this.acceptSvcHandler (sh); + + // Activate the SvcHandler using the appropriate ActivationStrategy + this.activateSvcHandler (sh); + } + + /** + * Bridge method for creating a <tt>SvcHandler</tt>. The default is to + * create a new <SvcHandler>. However, subclasses can override this + * policy to perform <SvcHandler> creation in any way that they like + * (such as creating subclass instances of <SvcHandler>, using a + * singleton, etc.) + *@return a new instance of the SvcHandler + *@exception InstantiationException could not create new SvcHandler + *@exception IllegalAccessException no SvcHandler factory provided + */ + protected SvcHandler makeSvcHandler () + throws InstantiationException, IllegalAccessException + { + // Create a new handler for the connection + return (SvcHandler) handlerFactory_.newInstance (); + } + + /** + * Bridge method for accepting the new connection into the + * <tt>SvcHandler</tt>. The default behavior delegates the work to + * <tt>SOCKAcceptor.accept</tt>. However, subclasses can override this + * strategy. + *@param sh SvcHandler in which to accept the connection + *@return 0 + *@exception SocketException socket level error + *@exception IOException socket level error + */ + protected int acceptSvcHandler (SvcHandler sh) + throws SocketException, IOException + { + // Create a new stream + SOCKStream sockStream = new SOCKStream (); + + // Block in accept. Returns when a connection shows up + this.sockAcceptor_.accept (sockStream); + + // Set the streams for the new handler + sh.setHandle (sockStream); + return 0; + } + + /** + * Bridge method for activating a <tt>SvcHandler</tt>. The default + * behavior of this method is to activate the <tt>SvcHandler</tt> by + * calling its open() method (which allows the <tt>SvcHandler</tt> to + * define its own concurrency strategy). However, subclasses can + * override this strategy to do more sophisticated concurrency + * activations. + *@param sh SvcHandler to activate + *@return 0 + */ + protected int activateSvcHandler (SvcHandler sh) + { + sh.open (null); + return 0; + } + + protected int port_ = ACE.DEFAULT_SERVER_PORT; + + // Handler class that should be instantiated when a connection is + // made with a client + protected Class handlerFactory_; + + // Our connection acceptance factory + protected SOCKAcceptor sockAcceptor_; +} + diff --git a/java/JACE/Connection/ActivateStrategy.java b/java/JACE/Connection/ActivateStrategy.java new file mode 100644 index 00000000000..91072a6c823 --- /dev/null +++ b/java/JACE/Connection/ActivateStrategy.java @@ -0,0 +1,40 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * ActivateStrategy.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + + +/** + * Bridge supporting activation strategy used by + * <a href="ACE.Connection.StrategyAcceptor.html#_top_"><tt>StrategyAcceptor</tt></a> + * <P> + * Subclass and overload + * <a href="#activateSvcHandler(ACE.Connection.SvcHandler)"><tt>activateSvcHandler</tt></a> + * in order change the activation strategy. Then, submit this subclass to + * <a href="ACE.Connection.StrategyAcceptor.html#_top_"><tt>StrategyAcceptor</tt></a> + * as the activation strategy. + * + *@see StrategyAcceptor + */ +public class ActivateStrategy +{ + /** + * Activate the Svc Handler. Note that subclasses should overwrite + * this method to provide a different Activate strategy. + *@param sh Svc Handler to activate + *@return zero if success, non-zero for failure + */ + public int activateSvcHandler (SvcHandler sh) + { + sh.open (null); + return 0; + } +} diff --git a/java/JACE/Connection/Blob.java b/java/JACE/Connection/Blob.java new file mode 100644 index 00000000000..d3102c81aa2 --- /dev/null +++ b/java/JACE/Connection/Blob.java @@ -0,0 +1,114 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * Blob.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + +import java.io.*; +import java.net.*; +import JACE.SOCK_SAP.*; +import JACE.ASX.*; +import JACE.OS.*; + +/** + * Provides a way of reading from or writing to a remote file + * using MessageBlocks. + */ +public class Blob +{ + /** + * Initialize the Blob. + * + *@param filename File to read or write + *@param hostname Host to contact for the file + *@param port Port on which to connect + */ + public int open (String filename, String hostname , int port) + { + this.filename_ = filename; + this.hostname_ = hostname; + this.port_ = port; + return 0; + } + + /** + * Read a certain amount from the file. + */ + public MessageBlock read (int length, int offset) + { + // Check if we have a valid length and a valid offset + if (length < 0 || offset < 0) + { + ACE.ERROR ("Blob::read(): Negative length or offset"); + return null; + } + + // Create a Blob Reader + BlobReader blobReader = new BlobReader (length, + offset, + this.filename_, + this.hostname_, this.port_); + + // Receive data + MessageBlock mb = blobReader.receiveData (); + if (blobReader.bytesRead () != length) + return null; + else + return mb; + } + + /** + * Write a certain amount to the file. + */ + public int write (MessageBlock mb, int length, int offset) + { + // Check if we have a valid length and a valid offset + if (length < 0 || offset < 0) + ACE.ERROR ("Blob::write(): Negative length or offset"); + + // Create a Blob Writer + BlobWriter blobWriter = new BlobWriter (mb, length, offset, this.filename_); + + try + { + // Connect to the server + this.connector_.open (this.hostname_, this.port_); + this.connector_.connect (blobWriter); + } + catch (UnknownHostException e) + { + ACE.ERROR (e); + } + catch (InstantiationException e) + { + ACE.ERROR (e); + } + catch (IllegalAccessException e) + { + ACE.ERROR (e); + } + catch (IOException e) + { + ACE.ERROR (e); + } + + return blobWriter.bytesWritten (); + } + + public int close () + { + return 0; + } + + String filename_; + String hostname_; + int port_; + Connector connector_ = new Connector (); +} diff --git a/java/JACE/Connection/BlobHandler.java b/java/JACE/Connection/BlobHandler.java new file mode 100644 index 00000000000..ec282bdeaa9 --- /dev/null +++ b/java/JACE/Connection/BlobHandler.java @@ -0,0 +1,35 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * BlobHandler.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + +import java.io.*; +import java.net.*; +import JACE.SOCK_SAP.*; +import JACE.ASX.*; +import JACE.OS.*; + +public abstract class BlobHandler extends SvcHandler +{ + public BlobHandler (int length, int offset, String filename) + { + this.length_ = length; + this.offset_ = offset; + this.filename_ = filename; + } + + public abstract int open (Object obj); + + protected int length_ = 0; + protected int offset_ = 0; + protected String filename_ = null; +} + diff --git a/java/JACE/Connection/BlobReader.java b/java/JACE/Connection/BlobReader.java new file mode 100644 index 00000000000..4de6b65bedc --- /dev/null +++ b/java/JACE/Connection/BlobReader.java @@ -0,0 +1,108 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * BlobReader.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + +import java.io.*; +import java.net.*; +import JACE.SOCK_SAP.*; +import JACE.ASX.*; +import JACE.OS.*; + +/** + * Provides a way to read from a remote file using + * MessageBlocks (and HTTP). <P> + * + * Created by Blob during a call to read. + */ +public class BlobReader +{ + public BlobReader (int length, + int offset, + String filename, + String hostname, + int port) + { + this.length_ = length; + this.offset_= offset; + this.filename_ = filename; + this.hostname_ = hostname; + this.port_ = port; + } + + + public MessageBlock receiveData () + { + String hostname = this.hostname_; + String filename = this.filename_; + + // Check if the filename begins with a "/" and if so, remove it + // since we are concatenating a "/" to the hostname. + if (this.filename_.startsWith ("/")) + filename = this.filename_.substring (1); + + hostname = hostname + ":" + this.port_ + "/"; + // System.out.println (hostname + filename); + + // Allocate a buffer to hold the offset worth of data + byte tempBuf [] = new byte [this.offset_]; + // Allocate a buffer to hold the actual data + byte dataBuf [] = new byte [this.length_]; + + try + { + // Create a URL to fetch the file + URL url = new URL (this.protocol_ + hostname + filename); + + // Get the input stream and pipe it to a DataInputStream + DataInputStream iStream = new DataInputStream (url.openStream ()); + + // Read the offset worth of bytes + iStream.readFully (tempBuf, 0, this.offset_); + + // Read length worth of bytes + iStream.readFully (dataBuf, 0, this.length_); + } + catch (MalformedURLException e) + { + ACE.ERROR (e); + } + catch (IOException e) + { + ACE.ERROR (e); + } + // Cache number of bytes read + this.bytesRead_ = this.length_; + return new MessageBlock (new String (dataBuf, 0, this.length_)); + } + + public int close (long flags) + { + return 0; + } + + public int bytesRead () + { + return this.bytesRead_; + } + + private String protocol_ = "http://"; + + int length_ = 0; + int offset_= 0; + String filename_ = null; + String hostname_ = "localhost"; + int port_ = 80; + + int bytesRead_ = 0; +} + + diff --git a/java/JACE/Connection/BlobWriter.java b/java/JACE/Connection/BlobWriter.java new file mode 100644 index 00000000000..18c9b092964 --- /dev/null +++ b/java/JACE/Connection/BlobWriter.java @@ -0,0 +1,224 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * BlobWriter.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + +import java.io.*; +import java.net.*; +import JACE.SOCK_SAP.*; +import JACE.ASX.*; +import JACE.OS.*; + +/** + * Provides a way to write to a remote file using MessageBlocks + * (and HTTP). <P> + * + * Created by Blob during a write. + */ +public class BlobWriter extends BlobHandler +{ + public BlobWriter (MessageBlock mb, + int length, + int offset, + String filename) + { + super (length, offset, filename); + this.mb_ = mb; + this.returnCode_ = -1; + + } + + /******************************* + * This constructor should be used when using the basic HTTP 1.1 + * authentication scheme + *******************************/ + public BlobWriter (MessageBlock mb, + int length, + int offset, + String filename, + String authentication) + { + super (length, offset, filename); + this.mb_ = mb; + this.returnCode_ = -1; + this.authentication_ = authentication; + } + + + public int open (Object obj) + { + if (this.sendRequest () != 0) + { + ACE.ERROR ("BlobWriter::open():sendRequest failed"); + return -1; + } + else if (this.receiveReply () != 0) + { + ACE.ERROR ("BlobWriter::open():receiveReply failed"); + return -1; + } + return 0; + } + + public int close (long flags) + { + return 0; + } + + public int bytesWritten () + { + return this.bytesWritten_;; + } + + protected int sendRequest () + { + // Check for sanity -- check if we have any data to send. + if (this.offset_+ this.length_ > this.mb_.length ()) + { + ACE.ERROR ("BlobWriter::sendRequest():Invalid offset/length"); + return -1; + } + + if (this.sendHeader () == -1) + { + ACE.ERROR ("BlobWriter::sendHeader failed."); + return -1; + } + else + if (this.sendData () == -1) + { + ACE.ERROR ("BlobWriter::sendData failed."); + return -1; + } + return 0; + } + + // Send the header + protected int sendHeader () + { + String filename = this.filename_; + // Check if the filename begins with a "/" and if it doesn't, add it + if (!this.filename_.startsWith ("/")) + filename = "/" + this.filename_; + + // Create the header, store the actual length in mesglen + String mesg = this.requestPrefix_ + " " + filename + " " + this.requestSuffix_; + + if (this.authentication_ != null) + mesg += "Authorization: Basic " + JACE.Connection.HTTPHelper.EncodeBase64(this.authentication_) + '\n'; + + mesg += "Content-length: " + this.length_ + "\n"; + + try + { + if (this.peer ().send (mesg) < 0) + { + ACE.ERROR ("Error sending request"); + return -1; + } + } + catch (IOException e) + { + ACE.ERROR (e); + return -1; + } + return 0; + } + + // Send the data + protected int sendData () + { + // Get the actual data to send + String data = this.mb_.base ().substring (this.offset_, + this.offset_ + this.length_); + + + try + { + // System.out.println (data); + // Now send the data + if (this.peer ().send (data) != this.length_) + { + ACE.ERROR ("Error sending file"); + return -1; + } + } + catch (IOException e) + { + ACE.ERROR (e); + return -1; + } + this.bytesWritten_ = this.length_; + return 0; + } + + + protected int receiveReply () + { + System.out.println("Waiting for reply"); + + // Receive the reply from the server + StringBuffer reply = new StringBuffer (1024); + + try + { + if (this.peer ().recv (reply) < 0) + { + ACE.ERROR ("Error receiving reply from server"); + return -1; + } + } + catch (IOException e) + { + ACE.ERROR (e); + } + + String s = reply.toString (); + + int index = -1; + // Now parse the reply to see if it was a success or a failure + if ((index = s.indexOf (replyPrefix_)) == -1) + { + ACE.ERROR ("Error receiving reply from server"); + return -1; + } + + int codeIndex = index + replyPrefix_.length () + 1; + + // Assume code is a 3 digit number + String codeString = s.substring (codeIndex, codeIndex + 3); + + returnCode_ = (new Integer (codeString)).intValue (); + // System.out.println (code); + + if (returnCode_ >= 200 && returnCode_ < 300) { // Check if everything went smoothly + System.out.println("We got the goodies!"); + return 0; + } else + return -1; + } + + public int returnCode () + { + return this.returnCode_; + } + + protected String authentication_ = null; + protected String protocol_ = "http://"; + protected int bytesWritten_ = 0; + protected MessageBlock mb_ = null; + protected String requestPrefix_ = "PUT"; + protected String requestSuffix_ = "HTTP/1.0\n"; + protected String replyPrefix_ = "HTTP/1.0"; + protected int returnCode_; +} + + diff --git a/java/JACE/Connection/Connector.java b/java/JACE/Connection/Connector.java new file mode 100644 index 00000000000..dbe72b8c359 --- /dev/null +++ b/java/JACE/Connection/Connector.java @@ -0,0 +1,148 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * Connector.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + +import java.io.*; +import java.net.*; +import JACE.OS.*; +import JACE.SOCK_SAP.*; +import JACE.ServiceConfigurator.*; + +/** + * Abstract factory for connecting a + * (<a href="JACE.Connection.SvcHandler.html"><tt>SvcHandler</tt></a>), + * to an application. + * <P> + * Implements the basic strategy for actively establishing connections + * with applications. The <tt>Connector</tt> establishes the connection, + * passing it on to a <tt>SvcHandler</tt> instance, and handing over + * control to that instance. + *<p> + * TCP is the transport mechanism used, via + * <a href="JACE.SOCK_SAP.SOCKConnector.html#_top_"><tt>SOCKConnector</tt></a>. + *<P> + * This class, as currently implemented, does not work like its C++ + * counterpart. + * Future versions are expected to rectify this discrepancy. + * + *@see SOCKConnector + *@see SvcHandler + */ +public class Connector extends ServiceObject +{ + /** + * Create a Connector. Do nothing constructor. Allows user to + * call <a href="#open(java.lang.String)">open</a>() later. + */ + public Connector () + { + } + + /** + * Create a Connector passing in server hostname and port + * number, effectively shorthand for calling + * <a href="#open(java.lang.String)">open</a>(). + *@param hostname server hostname + *@param port server port number + */ + public Connector (String hostname, int port) + { + this.open (hostname, port); + } + + /** + * Initialize the Connector passing in server hostname and port + * number. Note that no connection attempt is made. + *@param hostname server hostname + *@param port server port number + */ + public void open (String hostname, int port) + { + this.hostname_ = hostname; + this.port_ = port; + } + + /** + * Connect to the server. + *@param sh Svc Handler to use to handle the connection + *@exception UnknownHostException Bad host + *@exception SocketException Socket error + *@exception InstantiationException Couldn't create new SOCKConnector + *@exception IllegalAccessException No strategy available + *@exception IOException Socket error + */ + public void connect (SvcHandler sh) throws UnknownHostException, + SocketException, + InstantiationException, + IllegalAccessException, + IOException + { + // Make a connection using the appropriate Connection_Strategy + this.connectSvcHandler (sh); + + // Activate the Svc_Handler using the appropriate Activation_Strategy + this.activateSvcHandler (sh); + } + + /** + * Bridge method for making a new connection. The default behavior + * creates a new SOCKConnector and then calls setHandle() on the + * <SvcHandler> that was passed in. Subclasses can override this + * strategy, if needed. + *@param sh Svc Handler to use to handle the connection + *@return 0 + *@exception SocketException Socket error + *@exception IOException Socket error + */ + protected int connectSvcHandler (SvcHandler sh) throws + SocketException, IOException + { + // Create a new stream + SOCKStream sockStream = new SOCKStream (); + + // Create a SOCK_Connector (note the constructor does the connect for us) + this.sockConnector_ = new SOCKConnector (sockStream, + this.hostname_, + this.port_); + ACE.DEBUG ("Connected to " + + sockStream.socket ().getInetAddress ()); + + // Set the streams for the new handler + sh.setHandle (sockStream); + return 0; + } + + /** + * Bridge method for activating a <SvcHandler>. The default + * behavior of this method is to activate the <SvcHandler> by + * calling its open() method (which allows the SVC_HANDLER to define + * its own concurrency strategy). However, subclasses can override + * this strategy to do more sophisticated concurrency activations. + *@param sh Svc Handler to activate + *@return 0 + */ + protected int activateSvcHandler (SvcHandler sh) + { + sh.open (null); + return 0; + } + + + // Port server is listening on + private int port_; + + // Server hostname + private String hostname_; + + // Our connection factory + private SOCKConnector sockConnector_; +} diff --git a/java/JACE/Connection/CreationStrategy.java b/java/JACE/Connection/CreationStrategy.java new file mode 100644 index 00000000000..f4828d5bff5 --- /dev/null +++ b/java/JACE/Connection/CreationStrategy.java @@ -0,0 +1,57 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * CreationStrategy.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + +/** + * Defines the interface for specifying a creation strategy for a + * <a href="ACE.Connection.SvcHandler.html#_top_"><tt>SvcHandler</tt></a> to the + * <a href="ACE.Connection.StrategyAcceptor.html#_top_"><tt>StrategyAcceptor</tt></a>. + * <P> + * The default behavior is to make a new SvcHandler. However, + * subclasses can override this strategy to perform SvcHandler + * creation in any way that they like (such as creating subclass + * instances of SvcHandler, using a singleton, dynamically + * linking the handler, etc.). + * + *@see SvcHandler + *@see StrategyAcceptor + *@see AcceptStrategy + *@see ActivateStrategy + */ +public class CreationStrategy +{ + /** + * Create an instance of Creation Strategy. + *@param handlerFactory Svc Handler factory that is used to create + * an instance of a Svc Handler + */ + public CreationStrategy (Class handlerFactory) + { + this.handlerFactory_ = handlerFactory; + } + + /** + * Create a new SvcHandler. Note that subclasses should override + * this method to provide a new creation strategy. + *@return reference to a new instance of the SvcHandler (or subclass) + *@exception InstantiationException Unable to instantiate. + *@exception IllegalAccessException No handler factory available. + */ + public SvcHandler makeSvcHandler () throws InstantiationException, + IllegalAccessException + { + // Create a new Svc_Handler + return (SvcHandler) handlerFactory_.newInstance (); + } + + private Class handlerFactory_; +} diff --git a/java/JACE/Connection/HTTPHelper.java b/java/JACE/Connection/HTTPHelper.java new file mode 100644 index 00000000000..2901d74a14a --- /dev/null +++ b/java/JACE/Connection/HTTPHelper.java @@ -0,0 +1,182 @@ +package JACE.Connection; + +import JACE.OS.*; + +/** + * Collection of methods concerning HTTP. + */ +public class HTTPHelper +{ + /** + * Alphabet used in encoding and decoding basic base64 authentication. + * See the HTTP 1.1 RFC for details. + */ + public static String Alphabet + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * Decode a secret encrypted with the basic base64 HTTP 1.1 authentication + * scheme. + * + *@param secret Message to decode + *@return null on error, decoded String on success + */ + public static String DecodeBase64 (String secret) + { + StringBuffer output = new StringBuffer (); + boolean inalphabet [] = new boolean[256]; + char decoder [] = new char [256]; + + for (int i = 0; i < 256; i++) { + inalphabet [i] = false; + decoder [i] = 0; + } + + for (int i = Alphabet.length () - 1; + i >= 0; + i--) + { + inalphabet [(int)Alphabet.charAt (i)] = true; + decoder [(int)Alphabet.charAt (i)] = (char)i; + } + + int inidx = 0; + int c = 0; + int char_count = 0; + int bits = 0; + boolean error = false; + + while (inidx < secret.length ()) + { + c = secret.charAt (inidx++); + + if (c == '=') + break; + + if (c > 255 || !inalphabet[(int)c]) + continue; + + bits += decoder[c]; + char_count++; + if (char_count == 4) { + output.append ((char) (bits >> 16)); + output.append ((char) ((bits >> 8) & 0xff)); + output.append ((char) (bits & 0xff)); + bits = 0; + char_count = 0; + } else + bits <<= 6; + } + + if (c == '\0') { + if (char_count != 0) { + ACE.DEBUG ("base64 encoding incomplete: at least " + + ((4 - char_count) * 6) + " bits truncated"); + error = true; + } + } else { + // c == '=' + switch (char_count) + { + case 1: + ACE.DEBUG ("output so far: " + output.toString ()); + ACE.DEBUG ("base64 encoding incomplete: at least 2 bits missing"); + error = true; + break; + case 2: + output.append ((char) (bits >> 10)); + break; + case 3: + output.append ((char) (bits >> 16)); + output.append ((char) ((bits >> 8) & 0xff)); + break; + } + } + + if (!error) + return output.toString (); + else + return null; + } + + /** + * Encode a message with the basic base64 HTTP 1.1 authentication + * scheme. Adapted from James' JAWS HTTP_Helpers code. + * + *@param secret Message to encode + *@return null on error, an encoded String on success + */ + public static String EncodeBase64 (String secret) + { + StringBuffer output = new StringBuffer (); + + // Index of the input string + int inidx = 0; + + // character value + int c; + + int char_count = 0; + int bits = 0; + boolean error = false; + + while (inidx < secret.length()) + { + c = secret.charAt(inidx++); + + // This will mess up internationalization. I wonder if it is really + // necessary for HTTP? + if (c > 255) + { + ACE.DEBUG ("encountered char > 255 (decimal %d): " + c); + error = true; + break; + } + + bits += c; + char_count++; + + if (char_count == 3) + { + output.append(HTTPHelper.Alphabet.charAt(bits >> 18)); + output.append(HTTPHelper.Alphabet.charAt((bits >> 12) & 0x3f)); + output.append(HTTPHelper.Alphabet.charAt((bits >> 6) & 0x3f)); + output.append(HTTPHelper.Alphabet.charAt(bits & 0x3f)); + + bits = 0; + char_count = 0; + } + else + bits <<= 8; + } + + if (!error) + { + if (char_count != 0) + { + bits <<= 16 - (8 * char_count); + output.append(HTTPHelper.Alphabet.charAt(bits >> 18)); + output.append(HTTPHelper.Alphabet.charAt((bits >> 12) & 0x3f)); + + if (char_count == 1) + { + output.append("=="); + } + else + { + output.append(HTTPHelper.Alphabet.charAt((bits >> 6) & 0x3f)); + output.append('='); + } + } + + return output.toString(); + } + + // Returns null on error + return null; + } + + private HTTPHelper () {} +} + + diff --git a/java/JACE/Connection/StrategyAcceptor.java b/java/JACE/Connection/StrategyAcceptor.java new file mode 100644 index 00000000000..743d384776f --- /dev/null +++ b/java/JACE/Connection/StrategyAcceptor.java @@ -0,0 +1,174 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * StrategyAcceptor.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + +import java.io.*; +import java.net.*; +import JACE.OS.*; +import JACE.SOCK_SAP.*; + +/** + * Abstract factory for creating, accepting into, and activating + * a service handler. + * <P> + * Uses instances of CreationStrategy, AcceptStrategy, and + * ActivateStrategy. + * + *@see SvcHandler + *@see CreationStrategy + *@see AcceptStrategy + *@see ActivateStrategy + */ +public class StrategyAcceptor extends Acceptor +{ + /** + * Create an instance of StrategyAcceptor. The caller must + * call setHandlerFactory before open! + */ + public StrategyAcceptor () + { + this (null, null, null, null); + } + + /** + * Create an instance of StrategyAcceptor. + *@param handlerFactory Svc Handler factory that is used to create + * an instance of a Svc Handler when a connection is accepted. + */ + public StrategyAcceptor (Class handlerFactory) + { + this (handlerFactory, null, null, null); + } + + /** + * Create an instance of StrategyAcceptor. Use the creation + * strategy and the handlerFactory passed in to creae a new instance + * of the Svc Handler. + *@param handlerFactory Svc Handler factory that is used to create + * an instance of a Svc Handler when a connection is accepted. + *@param creStrategy Creation strategy to use to create a new + * instance of the Svc Handler. + *@param acceptStrategy Accept strategy to use to accept a new + * connection into the Svc Handler. + *@param activateStrategy Activate strategy to use to activate the + * instance of the Svc Handler. + */ + public StrategyAcceptor (Class handlerFactory, + CreationStrategy creStrategy, + AcceptStrategy acceptStrategy, + ActivateStrategy activateStrategy) + { + // Cache everything + this.handlerFactory_ = handlerFactory; + this.creStrategy_ = creStrategy; + this.acceptStrategy_ = acceptStrategy; + this.activateStrategy_ = activateStrategy; + } + + /** + * Initialize the Strategy Acceptor. The method creates the + * appropriate strategies as needed. + *@param port port number where the server will listen for connections + *@exception IOException Socket level error + */ + public void open (int port) throws IOException + { + if (this.creStrategy_ == null) + this.creStrategy_ = new CreationStrategy (this.handlerFactory_); + if (this.acceptStrategy_ == null) + this.acceptStrategy_ = new AcceptStrategy (port); + else + this.acceptStrategy_.open (port); + if (this.activateStrategy_ == null) + this.activateStrategy_ = new ActivateStrategy (); + } + + /** + * Accept a connection using the appropriate strategies. + * + *@exception SocketException Socket level error + *@exception InstantiationException Problem creating a handler + *@exception IllegalAccessException No strategy available + *@exception IOException Socket level error + */ + public void accept () throws SocketException, + InstantiationException, + IllegalAccessException, + IOException + { + // Create a Svc_Handler using the appropriate Creation_Strategy + SvcHandler sh = this.makeSvcHandler (); + + // Accept a connection into the Svc_Handler + this.acceptSvcHandler (sh); + + // Activate the Svc_Handler + this.activateSvcHandler (sh); + } + + /** + * Bridge method for creating a SvcHandler. The strategy for + * creating a SvcHandler is configured into the Acceptor via it's + * creStrategy_. If no strategy is passed in, the default behavior + * of this method is to use the default CreationStrategy. + *@return a new instance of the Svc Handler + *@exception InstantiationException Couldn't create SvcHandler + *@exception IllegalAccessException No strategy available + */ + protected SvcHandler makeSvcHandler () + throws InstantiationException, IllegalAccessException + { + // Create a new handler for the connection + return this.creStrategy_.makeSvcHandler (); + } + + + /** + * Bridge method for accepting the new connection into the + * <SvcHandler>. The strategy for accepting into a SvcHandler is + * configured into the Acceptor via it's acceptStrategy_. If no + * strategy is passed in, the default behavior of this method is to + * use the default AcceptStrategy. + *@param sh Svc Handler in which to accept the connection + *@return result of accepting a connection using the accept strategy + *@exception SocketException Socket level error + *@exception IOException Socket level error + */ + protected int acceptSvcHandler (SvcHandler sh) throws SocketException, IOException + { + // Delegate responsibility to the appropriate strategy + return this.acceptStrategy_.acceptSvcHandler (sh); + } + + /** + * Bridge method for activating a <SvcHandler>. The strategy for + * activating a SvcHandler is configured into the Acceptor via it's + * activateStrategy_. If no strategy is passed in, the default + * behavior of this method is to use the default ActivateStrategy. + *@param sh Svc Handler to activate + *@return result of activating the Svc Handler + */ + protected int activateSvcHandler (SvcHandler sh) + { + // Delegate responsibility to the appropriate strategy + return this.activateStrategy_.activateSvcHandler (sh); + } + + // Creation Strategy + private CreationStrategy creStrategy_; + + // Accept Strategy + private AcceptStrategy acceptStrategy_; + + // Activation Strategy + private ActivateStrategy activateStrategy_; +} diff --git a/java/JACE/Connection/SvcHandler.java b/java/JACE/Connection/SvcHandler.java new file mode 100644 index 00000000000..1df62247baa --- /dev/null +++ b/java/JACE/Connection/SvcHandler.java @@ -0,0 +1,101 @@ +/************************************************* + * + * = PACKAGE + * JACE.Connection + * + * = FILENAME + * SvcHandler.java + * + *@author Prashant Jain + * + *************************************************/ +package JACE.Connection; + +import java.io.*; +import java.net.*; +import JACE.SOCK_SAP.*; +import JACE.ASX.*; +import JACE.Reactor.*; + +/** + * Defines the interface for a service that exchanges data with its + * connected peer. + * <P> + * This class provides a well-defined interface that the Acceptor and + * Connector pattern factories use as their target. Typically, client + * applications will subclass SvcHandler and do all the interesting work + * in the subclass. One thing that the SvcHandler does contain is a + * peer SOCKStream endpoint that is initialized by Acceptor or Connector + * when a connection is established successfully. This endpoint is used + * to exchange data between a SvcHandler and the peer it is connected + * with. + */ +public abstract class SvcHandler extends Task +{ + + /** + * Do nothing constructor. + */ + public SvcHandler () + { + } + + /** + * Set the stream using the SOCKStream passed in. This sets the + * underlying peer + *@param s SOCK Stream to use for the connection + */ + public void setHandle (SOCKStream s) throws IOException + { + this.stream_ = s; + } + + /** + * Get the underlying peer + *@return the underlying peer + */ + public SOCKStream peer () + { + return this.stream_; + } + + /** + * Abstract method that subclasses must define to allow + * initialization to take place. + */ + public abstract int open (Object obj); + + /** + * Provide a default implementation to simplify ancestors. + *@return 0 + */ + public int close (long flags) + { + return 0; + } + + /** + * Provide a default implementation to simplify ancestors. + *@return -1 + */ + public int put (MessageBlock mb, TimeValue tv) + { + return -1; + } + + /** + * Provide a default implementation to simplify ancestors. + *@param tv Time Value when the event occured + *@param obj An arbitrary object that was passed to the Timer Queue + * (Asynchronous Completion Token) + */ + public int handleTimeout (TimeValue tv, Object obj) + { + return -1; + } + + /** + * Underlying peer socket stream. + */ + protected SOCKStream stream_; +} diff --git a/java/JACE/Connection/package.html b/java/JACE/Connection/package.html new file mode 100644 index 00000000000..429904216d5 --- /dev/null +++ b/java/JACE/Connection/package.html @@ -0,0 +1,7 @@ +<!-- $Id$ --> +<HTML> +<BODY> +Collection of factories for services. +@see <a href="http://www.cs.wustl.edu/~schmidt/ACE-papers.html#initialize">Documents on ACE object and service initialization components</a> +</BODY> +</HTML> |