Client-side polling Polling code in the printer application

This is now a decent solution from the client side. The button behaves correctly, and the Swing thread is free to refresh the screen and handle additional user events. Moreover, if the print request fails, the user will get a dialog box telling her about it.

21.2.2 Better Solutions

Unfortunately, this is still not a very good solution because it entails a significant commitment on the part of our server. The server is forced to keep a long-lived, and mostly unused, socket connection open with the client. Even worse, this is a socket that is in the middle of a method call at the time, and therefore isnt available for reuse. As a side note, this design would also almost certainly force us to increase RMIs connection timeout using the sun.rmi.transport.tcp.readTimeout parameter. Otherwise, when the printers busy, all the clients will throw instances of RemoteException . This discussion leads us to two better solutions, both of which are commonly used, depending on the circumstances. The first solution is client-side polling. This solution is architecturally similar to our first solution. Theres a background thread that reports back, but instead of making a single method call and holding the connection open, it makes a series of brief method calls. The first call drops off the print request. The subsequent remote method invocations check to see whether the printer has printed the document yet. The second solution is server-side callbacks. In this solution, the client drops off the print request, as in the original application. The difference is that the client passes in another argument, which is itself a remote server. In other words, its an object on the client side, but it implements Remote and is capable of receiving remote method invocations. When the server is done, it calls a remote method on this new server, and the new server is responsible for actually reporting the results back to the client application.

21.2.2.1 Client-side polling

There are two main reasons to use client-side polling. The first is that, architecturally, its simpler. In this model, the client application calls the server application. The server doesnt have to track which clients called and which clients are waiting for responses, nor does it have to actually call them back. This makes for simpler code and makes it easier to have multiple types of clients, should that be necessary. The second reason to use client-side polling is that sometimes clients cant accept socket connections from the server. One typical case for this is when the client is an applet. Most of the time, applets are forbidden from creating any instances of ServerSocket at all. This completely rules out the applet containing an RMI server. Another typical case is when firewalls are involved. A firewall separates two parts of the network and restricts network traffic to certain sockets or only allows data to flow in certain directions. The upshot is that sometimes, even if the client application is capable of creating instances of ServerSocket and thus, can actually contain an RMI server, the server application may not be able to connect to it.

21.2.2.2 Polling code in the printer application

The actual code well need for the printer application isnt too complex. The first change well need to make is to the Printer interface: package com.ora.rmibook.chapter21.printer; import java.rmi.; public interface PollingPrinter extends PrinterConstants, Remote { public boolean printerAvailable throws RemoteException; public String printDocumentDocumentDescriptio n document throws RemoteException, PrinterException; public boolean isDocumentDoneString documentKey throws RemoteException, PrinterException; } In redesigning this interface, weve broken our original printDocument method into two methods: printDocument and isDocumentDone . This is intended to work as follows: 1. The client calls printDocument and receives back a string, which is a unique key. 2. The client can then call isDocumentDone at any time to find out the status of the document. Why Not a PrintingDocument Object? Another way to handle client-side polling would be to create a new type of server on the client side, as in the following pair of interfaces: public interface PollingPrinter extends PrinterConstants, Remote { public boolean printerAvailable throws RemoteException; public PrintingDocument printDocumentDocumentDescription document throws RemoteException, PrinterException; } public interface PrintingDocument extends PrinterConstants, Remote { public boolean isDocumentDone throws RemoteException, PrinterException; } This is a little nicer from an object-oriented point of view. It neatly separates out asking for document status from the initial submission. It removes the String return value returning a key object is almost always bad design™objects returned by the server really should be meaningful to the client, instead of simply being keys that are passed back to the server. In addition, it suggests that perhaps there are other status and manipulation methods that we could place on PrintingDocument as well, to modify the print request even after its been submitted. On the other hand, it feels a little bit like overkill in the current case. After redesigning this interface, we need to alter the client to occasionally call isDocumentDone . Since we were already using a background thread to make the remote method invocation, this doesnt involve a lot of code changes. The only change is that, instead of waiting for an answer, we now repeatedly call isDocumentDone . Heres the new version: private class PrintFile implements ActionListener, Runnable { private PollingPrinter _printer; private String _key; public void actionPerformedActionEvent event { new Threadthis.start ; } public void run { try { makeInitialRequest ; pollPrinter ; } catch PrinterException printerException { SwingUtilities.invokeLaternew PrinterExceptionMessageprinterException; return; } catch Exception exception { SwingUtilities.invokeLaternew ExceptionMessageexception; return; } SwingUtilities.invokeLaternew SuccessMessage ; } private void makeInitialRequest throws PrinterException, Exception { FileInputStream documentStream = new FileInputStream_fileChooser. getSelectedFile ; DocumentDescription documentDescription = new DocumentDescriptiondocumentStream; _printer = PollingPrinter Naming.lookupDEFAULT_PRINTER_NAME; _key = _printer.printDocumentdocumentDescription; } private void pollPrinter throws PrinterException, Exception { while false == _printer.isDocumentDone_key { try { Thread.sleep2000; wait a bit and check again } catch InterruptedException ignored {} } }

21.2.2.3 Server-side callbacks