If you run the CommPortOpen
program and select a
port that is opened by a native program such as HyperTerminal on
MS-Windows, you will get a PortInUseException
after the timeout period is up:
C:javasrccommport>java CommPortOpen Exception in thread "main" javax.comm.PortInUseException: Port currently owned by Unknown Windows Application at javax.comm.CommPortIdentifier.open(CommPortIdentifier.java:337) at CommPortOpen.main(CommPortOpen.java:41)
If, on the other hand, you run two copies of
CommPortOpen
at the same time for the same port,
you will see something like the following:
C:javasrccommport>java CommPortOpen Exception in thread "main" javax.comm.PortInUseException: Port currently owned by DarwinSys DataComm at javax.comm.CommPortIdentifier.open(CommPortIdentifier.java:337) at CommPortOpen.main(CommPortOpen.java:41) C:javasrccommport>
To resolve conflicts over port ownership, you can register a
PortOwnershipListener
so that you will be told if another
application wants to use the port. Then you can either close the port
and the other application will get it, or ignore the request and the
other program will get a PortInUseException
, as we
did here.
What is this “listener”? The
Event
Listener model is used in many places in Java. It may be best known
for its uses in GUIs (see Section 13.5). The basic
form is that you have to register an object as
a listener with an event
source. The event source will then call a well-known
method to notify you that a particular event has occurred. In the
GUI, for example, an event occurs
when the user presses a button with the mouse; if you wish to monitor
these events, you need to call the button object’s
addActionListener( )
method, passing an instance
of the ActionListener
interface (which can be your
main class, an inner class, or some other class).
How does a listener work in practice? To simplify matters,
we’ve again subclassed from our command-line program
CommPortOpen
to pop up a dialog if one copy of the
program tries to open a port that another copy already has open. If
you run two copies of the new program PortOwner
at
the same time, and select the same port in each, you’ll see the
dialog shown in Figure 11-3.
The trick to make this happen is simply to add a
CommPortOwnershipListener
to the
CommPortIdentifier
object. You will then be called
when any program gets ownership, gives up ownership, or if there is a
conflict. Example 11-4 shows the program with this
addition.
Example 11-4. PortOwner.java
import javax.comm.*; import java.io.*; import javax.swing.*; /** Demonstrate the port conflict resolution mechanism. * Run two copies of this program and choose the same port in each. */ public class PortOwner extends CommPortOpen { /** A name for showing which of several instances of this program */ String myName; public PortOwner(String name) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { super(null); myName = name; thePortID.addPortOwnershipListener(new MyResolver( )); } public void converse( ) { // lah de dah... // To simulate a long conversation on the port... try { Thread.sleep(1000 * 1000); } catch (InterruptedException cantHappen) { // } } /** An inner class that handles the ports conflict resolution. */ class MyResolver implements CommPortOwnershipListener { protected boolean owned = false; public void ownershipChange(int whaHoppen) { switch (whaHoppen) { case PORT_OWNED: System.out.println("An open succeeded."); owned = true; break; case PORT_UNOWNED: System.out.println("A close succeeded."); owned = false; break; case PORT_OWNERSHIP_REQUESTED: if (owned) { if (JOptionPane.showConfirmDialog(null, "I've been asked to give up the port, should I?", "Port Conflict (" + myName + ")", JOptionPane.OK_CANCEL_OPTION) == 0) thePort.close( ); } else { System.out.println("Somebody else has the port"); } } } } public static void main(String[] argv) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { if (argv.length != 1) { System.err.println("Usage: PortOwner aname"); System.exit(1); } new PortOwner(argv[0]).converse( ); System.exit(0); } }
Note the single argument to ownershipChange( )
. Do
not assume that only your listener will be told when an event occurs;
it will be called whether you are the affected program or simply a
bystander. To see if you are the program being requested to give up
ownership, you have to
check to see if you
already have the port that is being requested (for example, by
opening it successfully!).
3.141.38.121