ProblemSomebody else is using the port you want, and they won't let go! SolutionUse a PortOwnershipListener . DiscussionIf you run the CommPortOpen program and select a port that is opened by a native program such as HyperTerminal on Windows, you get a PortInUseException after the timeout period is up: C:\javasrc\commport>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:\javasrc\commport>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:\javasrc\commport> To resolve conflicts over port ownership, you can register a PortOwnershipListener so that you are told if another (Java) 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 Recipe 14.4). The basic form is that you have to register an object as a listener with an event source. The event source then calls 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 12-3. Figure 12-3. Port conflict resolutionThe trick to make this happen is simply to add a CommPortOwnershipListener to the CommPortIdentifier object. You are then called when any program gets ownership, gives up ownership, or if there is a conflict. Example 12-4 shows the program with this addition. Example 12-4. PortOwner.javaimport 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!). |