| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| DualTransportConnector |
|
| 2.1;2.1 | ||||
| DualTransportConnector$ConnectThread |
|
| 2.1;2.1 |
| 1 | /* | |
| 2 | * Created on 20-May-2004 | |
| 3 | */ | |
| 4 | package ca.uhn.hl7v2.protocol.impl; | |
| 5 | ||
| 6 | import ca.uhn.hl7v2.protocol.TransportException; | |
| 7 | import ca.uhn.hl7v2.protocol.TransportLayer; | |
| 8 | ||
| 9 | /** | |
| 10 | * <p>A utility for connecting separate inbound and outbound | |
| 11 | * <code>TransortLayer</code>s in a manner that avoids deadlock.</p> | |
| 12 | * | |
| 13 | * <p>It is not safe to call connect() on two <code>TransportLayer</code> | |
| 14 | * in the same thread, because it blocks, and the remote system may be doing | |
| 15 | * the same thing, but in the opposite order. This class provides a method | |
| 16 | * that connects two layers in separate threads, and pends until they are | |
| 17 | * both connected.</p> | |
| 18 | * | |
| 19 | * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a> | |
| 20 | * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:26 $ by $Author: jamesagnew $ | |
| 21 | */ | |
| 22 | public class DualTransportConnector { | |
| 23 | ||
| 24 | private final TransportLayer myTransportA; | |
| 25 | private final TransportLayer myTransportB; | |
| 26 | private boolean isConnecting; | |
| 27 | ||
| 28 | /** | |
| 29 | * @param theTransportA one <code>TransportLayer</code> we will want to connect | |
| 30 | * @param theTransportB another one | |
| 31 | */ | |
| 32 | 10 | public DualTransportConnector(TransportLayer theTransportA, TransportLayer theTransportB) { |
| 33 | 10 | myTransportA = theTransportA; |
| 34 | 10 | myTransportB = theTransportB; |
| 35 | 10 | } |
| 36 | ||
| 37 | /** | |
| 38 | * @return one of the underlying <code>TransportLayer</code>s. | |
| 39 | */ | |
| 40 | public TransportLayer getTransportA() { | |
| 41 | 10 | return myTransportA; |
| 42 | } | |
| 43 | ||
| 44 | /** | |
| 45 | * @return the other underlying <code>TransportLayer</code>. | |
| 46 | */ | |
| 47 | public TransportLayer getTransportB() { | |
| 48 | 10 | return myTransportB; |
| 49 | } | |
| 50 | ||
| 51 | /** | |
| 52 | * Connects both <code>TransportLayer</code>s in separate threads, | |
| 53 | * and returns when both have been connected, or when cancelConnect() | |
| 54 | * is called. | |
| 55 | */ | |
| 56 | public void connect() throws TransportException { | |
| 57 | 10 | isConnecting = true; |
| 58 | 10 | ConnectThread c1 = new ConnectThread(myTransportA); |
| 59 | 10 | ConnectThread c2 = new ConnectThread(myTransportB); |
| 60 | 10 | c1.start(); |
| 61 | 10 | c2.start(); |
| 62 | ||
| 63 | 52 | while (isConnecting |
| 64 | 52 | && (!c1.isConnected() || !c2.isConnected()) |
| 65 | 42 | && c1.getException() == null |
| 66 | 42 | && c2.getException() == null) { |
| 67 | ||
| 68 | try { | |
| 69 | 42 | Thread.sleep(1); |
| 70 | 42 | } catch (InterruptedException e) {} |
| 71 | } | |
| 72 | ||
| 73 | 10 | if (c1.getException() != null) throw c1.getException(); |
| 74 | 10 | if (c2.getException() != null) throw c2.getException(); |
| 75 | 10 | } |
| 76 | ||
| 77 | public void disconnect() throws TransportException { | |
| 78 | 10 | myTransportA.disconnect(); |
| 79 | 10 | myTransportB.disconnect(); |
| 80 | 10 | } |
| 81 | ||
| 82 | /** | |
| 83 | * Cancels a connect() in progress. Since connect() blocks, this must | |
| 84 | * be called from a separate thread. | |
| 85 | */ | |
| 86 | public void cancelConnect() { | |
| 87 | 0 | isConnecting = false; |
| 88 | 0 | } |
| 89 | ||
| 90 | /** | |
| 91 | * A class to facilitate connecting a <code>TransportLayer</code> in | |
| 92 | * a separate thread. This is needed when we want to perform two connections | |
| 93 | * that are initiated remotely, and we don't know the order in which the | |
| 94 | * remote system will initiate the connections. | |
| 95 | * | |
| 96 | * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a> | |
| 97 | * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:26 $ by $Author: jamesagnew $ | |
| 98 | */ | |
| 99 | private static class ConnectThread extends Thread { | |
| 100 | ||
| 101 | private TransportLayer myTransport; | |
| 102 | private TransportException myException; | |
| 103 | ||
| 104 | 20 | public ConnectThread(TransportLayer theTransport) { |
| 105 | 20 | myTransport = theTransport; |
| 106 | 20 | } |
| 107 | ||
| 108 | public boolean isConnected() { | |
| 109 | 70 | return myTransport.isConnected(); |
| 110 | } | |
| 111 | ||
| 112 | /** | |
| 113 | * @return an exception encountered during the last run, if any | |
| 114 | */ | |
| 115 | public TransportException getException() { | |
| 116 | 104 | return myException; |
| 117 | } | |
| 118 | ||
| 119 | public void run() { | |
| 120 | 20 | myException = null; |
| 121 | try { | |
| 122 | 20 | myTransport.connect(); |
| 123 | 0 | } catch (TransportException e) { |
| 124 | 0 | myException = e; |
| 125 | 20 | } |
| 126 | 20 | } |
| 127 | } | |
| 128 | ||
| 129 | } |