Factories Socket Factories Special-Purpose Sockets

ServerSocket and override the accept method to return a CompressingSocket . Exam ple 2- 3 shows the complete code for CompressingServerSocket . Example 2-3. CompressingServerSocket.java public class CompressingServerSocket extends ServerSocket { public CompressingServerSocketint port throws IOException { superport; } public Socket accept throws IOException { Socket returnValue = new CompressingSocket ; implAcceptreturnValue; return returnValue; } } This works by creating an instance of CompressingSocket and passing it as an argument to implAccept . implAccept is a protected method that actually listens for connections and blocks. When a connection is made, implAccept configures the CompressingSocket it has been passed and then returns. Logging and Tracing Frequently, the portions of code that perform data translation are also the ideal points to insert logging, tracing, and debugging code. For example, in the com.ora.rmibook.chapter2.sockets package, there are three classes that together illustrate the general idea: LoggingInputStream , LoggingOutputStream , and Recorder . LoggingInputStream and LoggingOutputStream dont perform any data manipulation at all, but they do have a re ference to an instance of Recorder . And they tell the recorder whenever data flows through them, as in the following code snippet from LoggingInputStream : public int readbyte[] b throws IOException { int numberOfBytes = super.readb; _recorder.incrementCounternumberOfBytes; return numberOfBytes; } While this implementation is very primitive the recorder is told the number of bytes received, but does not, for example, know where they came from, the idea is clear. Subclassing Socket , and using the custom subclass in your application, can provide a powerful hook for analyzing network performance.

2.5.4 Factories

Recall that from the list of three reasons to subclass Socket , we said: It isolates code that is likely to change. If most of the application simply creates instances of a subclass of Socket or, better yet, calls a method named something like getSocket on a factory object, and uses only the basic methods defined in Socket , then the application can quickly and easily be modified to use a different subclass of Socket . The idea behind a factory is simple: a factory is an object that knows how to build instances of some other class or interface. That is, it is a generalization of the traditional way of creating an instance of some class. At the risk of belaboring the point, calling a constructor can be broken down into three steps: 1. Find the class object. The class object is referred to by name the programmer knows the class explicitly. 2. Call the constructor. Again, the programmer has explicit knowledge. Usually this step, and the prior one, are simply a line of the form Classname.constructor . 3. Use the returned object. The returned object is an instance of the named class. Factories generalize each of these steps: 1. Find the factory. In a single process, this is usually done by having the programmer know the factory classname and having the factory be a singleton instance. 2. Call the creation method. The programmer has explicit knowledge of what methods are available. 3. Use the returned object. The returned object is an instance of some class that has the right type e.g., implements the interface the factory is defined to return. Well revisit the idea of factories several times over the course of this book. Using factories is one of the most important idioms in designing and building scalable distributed systems. For now, it suffices to note that each of these changes adds important flexibility to a program.

2.5.5 Socket Factories

Factories are often used when there is an identifiable part of a program, easily encapsulated in one or a few objects, which is likely to change repeatedly over time and which may require special expertise to implement. Replacing sockets is a perfect example of this; instead of calling the constructor on a specific type of socket, code that needs to use a socket can get one by calling a factory. This allows the sockets in an application to be changed by simply changing the code in one place™the factory™rather than changing the calls to the constructor everywhere in the program. Because this is such a common usage, Javasoft, as part of the Java Secure Sockets Extension JSSE, defined the javax.net package, includes two abstract classes: SocketFactory and ServerSocketFactory . Here are the method definitions for SocketFactory : public abstract java.net.Socket createSocketjava.net.InetAddress host, int port public abstract java.net.Socket createSocketjava.net.InetAddress address, int port, java.net.InetAddress clientAddress, int clientPort public abstract java.net.Socket createSocketjava.lang.String host, int port public abstract java.net.Socket createSocketjava.lang.String host, int port, java.net.InetAddress clientHost, int clientPort public static SocketFactory getDefault With the exception of getDefault , these look exactly like constructors for a subclass of Socket . getDefault is a hook for a singleton™the idea is that code can get the systems default SocketFactory which is set as part of an applications initialization phase and then create a Socket using it, without ever knowing the classnames of either the default SocketFactory or the particular subclass of Socket it returns. The resulting code, which looks a lot like the following, is truly generic and rarely needs to be rewritten: SocketFactory socketFactory = SocketFactory.getDefault ; gets default factory connects to server Socket connectionToServer = socketFactory.createSockethostMachine, portNumber; Of course, anyone who writes a custom socket needs to do a little more work and implement the factories. In particular, a vendor shipping a special-purpose socket should actually ship at least four classes: a subclass of Socket , a subclass of ServerSocket , a subclass of SocketFactory , and a subclass of ServerSocketFactory . The java.rmi.server package defines a similar, though simpler, pair of interfaces: RMIClientSocketFactory and RMIServerSocketFactor . These enable you to customize the sockets used by the RMI framework ordinary sockets are used by default. We will discuss these further in Chapt er 18 .

2.5.6 Security