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 | } |