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.

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, as in a remote login session, or a program, either a server or a client program. A client program, in turn, may be driven by a person (as is a web browser) or may be self-driven (such as an FTP client transferring many files at one request). You cannot predict, then, who will need to read and who will need to write. Consider the simplest case: the programs at both end 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 the universe 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 11-7 reads from a serial port using the event-driven approach.

Example 11-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 Section 11.6. True enough, gentle reader. Have patience with your humble and obedient servant. Here is a program that will read from each and 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 11-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 11-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, putting serial and parallel into 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);
            }
        }
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.212.160