KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > management > remote > protocol > terracotta > TunnelingEventHandler


1 /*
2  * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
3  * notice. All rights reserved.
4  */

5 package com.tc.management.remote.protocol.terracotta;
6
7 import com.tc.async.api.AbstractEventHandler;
8 import com.tc.async.api.EventContext;
9 import com.tc.async.api.EventHandlerException;
10 import com.tc.logging.TCLogger;
11 import com.tc.logging.TCLogging;
12 import com.tc.net.protocol.tcm.ChannelEvent;
13 import com.tc.net.protocol.tcm.ChannelEventListener;
14 import com.tc.net.protocol.tcm.ChannelEventType;
15 import com.tc.net.protocol.tcm.MessageChannel;
16 import com.tc.net.protocol.tcm.TCMessage;
17 import com.tc.net.protocol.tcm.TCMessageType;
18 import com.tc.util.concurrent.SetOnceFlag;
19
20 import java.io.IOException JavaDoc;
21
22 import javax.management.remote.generic.MessageConnection;
23 import javax.management.remote.message.Message;
24
25 public final class TunnelingEventHandler extends AbstractEventHandler implements
26         ChannelEventListener {
27
28     private static final TCLogger logger = TCLogging
29             .getLogger(TunnelingEventHandler.class);
30
31     private final MessageChannel channel;
32
33     private TunnelingMessageConnection messageConnection;
34
35     private boolean acceptOk;
36
37     private Object JavaDoc jmxReadyLock;
38
39     private SetOnceFlag localJmxServerReady;
40
41     private boolean transportConnected;
42
43     private boolean sentReadyMessage;
44
45     public TunnelingEventHandler(final MessageChannel channel) {
46         this.channel = channel;
47         this.channel.addListener(this);
48         acceptOk = false;
49         jmxReadyLock = new Object JavaDoc();
50         localJmxServerReady = new SetOnceFlag();
51         transportConnected = false;
52         sentReadyMessage = false;
53     }
54
55     public void handleEvent(final EventContext context)
56             throws EventHandlerException {
57         final JmxRemoteTunnelMessage messageEnvelope = (JmxRemoteTunnelMessage) context;
58         if (messageEnvelope.getCloseConnection()) {
59             reset();
60         } else {
61             final Message message = messageEnvelope.getTunneledMessage();
62             synchronized (this) {
63                 if (messageEnvelope.getInitConnection()) {
64                     if (messageConnection != null) {
65                         logger
66                                 .warn("Received a client connection initialization, resetting existing connection");
67                         reset();
68                     }
69                     messageConnection = new TunnelingMessageConnection(channel,
70                             true);
71                     acceptOk = true;
72                     notifyAll();
73                 } else if (messageConnection == null) {
74                     logger
75                             .warn("Received unexpected data message, connection is not yet established");
76                 } else {
77                     if (message != null) {
78                         messageConnection.incomingNetworkMessage(message);
79                     } else {
80                         logger
81                                 .warn("Received tunneled message with no data, resetting connection");
82                         reset();
83                     }
84                 }
85             }
86         }
87     }
88
89     synchronized MessageConnection accept() throws IOException JavaDoc {
90         while (!acceptOk) {
91             try {
92                 wait();
93             } catch (InterruptedException JavaDoc ie) {
94                 logger.warn("Interrupted while waiting for a new connection",
95                         ie);
96                 throw new IOException JavaDoc(
97                         "Interrupted while waiting for new connection: "
98                                 + ie.getMessage());
99             }
100         }
101         acceptOk = false;
102         return messageConnection;
103     }
104
105     private synchronized void reset() {
106         if (messageConnection != null) {
107             try {
108                 messageConnection.close();
109             } catch (IOException JavaDoc ioe) {
110                 logger
111                         .warn("Caught I/O exception while closing tunneled JMX connection");
112             }
113         }
114         messageConnection = null;
115         acceptOk = false;
116         synchronized (jmxReadyLock) {
117             sentReadyMessage = false;
118         }
119         notifyAll();
120     }
121
122     public void notifyChannelEvent(final ChannelEvent event) {
123         if (event.getChannel() == channel) {
124             if (event.getType() == ChannelEventType.TRANSPORT_CONNECTED_EVENT) {
125                 synchronized (jmxReadyLock) {
126                     transportConnected = true;
127                 }
128                 sendJmxReadyMessageIfNecessary();
129             } else if (event.getType() == ChannelEventType.CHANNEL_CLOSED_EVENT
130                     || event.getType() == ChannelEventType.TRANSPORT_DISCONNECTED_EVENT) {
131                 reset();
132                 synchronized (jmxReadyLock) {
133                     transportConnected = false;
134                 }
135             }
136         }
137     }
138
139     public void jmxIsReady() {
140         synchronized (jmxReadyLock) {
141             localJmxServerReady.set();
142         }
143
144         sendJmxReadyMessageIfNecessary();
145     }
146
147     /**
148      * Once the local JMX server has successfully started (this happens in a
149      * background thread as DSO is so early in the startup process that the
150      * system JMX server in 1.5+ can't be created inline with other
151      * initialization) we send a 'ready' message to the L2 each time we connect
152      * to it. This tells the L2 that they can connect to our local JMX server
153      * and see the beans we have in the DSO client.
154      */

155     private void sendJmxReadyMessageIfNecessary() {
156         final boolean send;
157         synchronized (jmxReadyLock) {
158             send = localJmxServerReady.isSet() && transportConnected
159                     && !sentReadyMessage;
160             if (send) {
161                 sentReadyMessage = true;
162             }
163         }
164
165         // Doing this message send outside of the jmxReadyLock to avoid a
166
// deadlock (CDV-132)
167
if (send) {
168             logger
169                     .info("Client JMX server ready; sending notification to L2 server");
170             TCMessage readyMessage = channel
171                     .createMessage(TCMessageType.CLIENT_JMX_READY_MESSAGE);
172             readyMessage.send();
173         }
174
175     }
176 }
177
Popular Tags