Recipe 12.6 Reading and Writing: Event-Driven


Problem

After the connection is made, you don't know what order to read or write in.

Solution

Use Java Communication Events to notify you when data becomes available. Or use threads (see Recipe 12.7).

Discussion

While lock-step mode is acceptable for dialing a modem, it breaks down when you have two independent agents communicating over a port. Either end may be a person or a program, so you cannot predict who will need to read and who will need to write. Consider the simplest case: the programs at both ends try to read at the same time! Using the lock-step model, each end will wait forever for the other end to write something. This error condition is known as a deadlock , since both ends are locked up, dead, until a person intervenes, or the communication line drops, or the world ends, or somebody making tea blows a fuse and causes one of the machines to halt.

There are two general approaches to this problem: event-driven activity, wherein the Communications API notifies you when the port is ready to be read or written; and threads-based activity, wherein each "direction" (from the user to the remote, and from the remote to the user) has its own little flow of control, causing only the reads in that direction to wait. We'll discuss each of these.

First, Example 12-7 reads from a serial port using the event-driven approach.

Example 12-7. SerialReadByEvents.java
import java.awt.*; import java.io.*; import javax.comm.*; import java.util.*; /**  * Read from a Serial port, notifying when data arrives.  * Simulation of part of an event-logging service.  */ public class SerialReadByEvents extends CommPortOpen      implements SerialPortEventListener {     public static void main(String[] argv)         throws IOException, NoSuchPortException, PortInUseException,             UnsupportedCommOperationException {         new SerialReadByEvents(null).converse( );     }     /* Constructor */     public SerialReadByEvents(Frame f)         throws IOException, NoSuchPortException, PortInUseException,             UnsupportedCommOperationException {                  super(f);     }     protected BufferedReader ifile;     /**       * Hold the conversation.       */     protected void converse( ) throws IOException {         if (!(thePort instanceof SerialPort)) {             System.err.println("But I wanted a SERIAL port!");             System.exit(1);         }         // Tell the Comm API that we want serial events.         ((SerialPort)thePort).notifyOnDataAvailable(true);         try {             ((SerialPort)thePort).addEventListener(this);         } catch (TooManyListenersException ev) {             // "CantHappen" error             System.err.println("Too many listeners(!) " + ev);             System.exit(0);         }              // Make a reader for the input file.         ifile = new BufferedReader(new InputStreamReader(is));         //     }     public void serialEvent(SerialPortEvent ev) {         String line;         try {             line = ifile.readLine( );             if (line == null) {                 System.out.println("EOF on serial port.");                 System.exit(0);             }             os.println(line);         } catch (IOException ex) {             System.err.println("IO Error " + ex);         }     } }

As you can see, the serialEvent( ) method does the readLine( ) calls. "But wait!" I hear you say. "This program is not a very meaningful example. It could just as easily be implemented using the lock-step method of Recipe 12.5. True enough, gentle reader. Have patience with your humble and obedient servant. Here is a program that reads from any of the serial ports, whenever data arrives. The program is representative of a class of programs called " data loggers," which receive data from a number (possibly a large number) of remote locations, and log them centrally. One example is a burglar alarm monitoring station, which needs to log activities such as the alarm being turned off at the close of the day, entry by the cleaners later, what time they left, and so on. And then, of course, it needs to notify the operator of the monitoring station when an unexpected event occurs. This last step is left as an exercise for the reader.

Example 12-8 makes use of the EventListener model and uses a unique instance of the inner class Logger for each serial port it's able to open.

Example 12-8. SerialLogger.java
import java.io.*; import javax.comm.*; import java.util.*; /**  * Read from multiple Serial ports, notifying when data arrives on any.  */ public class SerialLogger {     public static void main(String[] argv)         throws IOException, NoSuchPortException, PortInUseException,             UnsupportedCommOperationException {         new SerialLogger( );     }     /* Constructor */     public SerialLogger( )         throws IOException, NoSuchPortException, PortInUseException,             UnsupportedCommOperationException {                  // get list of ports available on this particular computer,         // by calling static method in CommPortIdentifier.         Enumeration pList = CommPortIdentifier.getPortIdentifiers( );         // Process the list, saving Serial Ports in ComboBoxes         while (pList.hasMoreElements( )) {             CommPortIdentifier cpi = (CommPortIdentifier)pList.nextElement( );             String name = cpi.getName( );             System.out.print("Port " + name + " ");             if (cpi.getPortType( ) == CommPortIdentifier.PORT_SERIAL) {                 System.out.println("is a Serial Port: " + cpi);                 SerialPort thePort;                 try {                     thePort = (SerialPort)cpi.open("Logger", 1000);                 } catch (PortInUseException ev) {                     System.err.println("Port in use: " + name);                     continue;                 }                 // Tell the Comm API that we want serial events.                 thePort.notifyOnDataAvailable(true);                 try {                     thePort.addEventListener(new Logger(cpi.getName( ), thePort));                 } catch (TooManyListenersException ev) {                     // "CantHappen" error                     System.err.println("Too many listeners(!) " + ev);                     System.exit(0);                 }             }         }     }     /** Handle one port. */     public class Logger implements SerialPortEventListener {          String portName;         SerialPort thePort;         BufferedReader ifile;         public Logger(String name, SerialPort port) throws IOException {             portName = name;             thePort = port;             // Make a reader for the input file.             ifile = new BufferedReader(                 new InputStreamReader(thePort.getInputStream( )));         }         public void serialEvent(SerialPortEvent ev) {             String line;             try {                 line = ifile.readLine( );                 if (line == null) {                     System.out.println("EOF on serial port.");                     System.exit(0);                 }                 System.out.println(portName + ": " + line);             } catch (IOException ex) {                 System.err.println("IO Error " + ex);             }         }     } }



Java Cookbook
Java Cookbook, Second Edition
ISBN: 0596007019
EAN: 2147483647
Year: 2003
Pages: 409
Authors: Ian F Darwin

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net