001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.admin;
006:
007: import org.dijon.Button;
008: import org.dijon.Container;
009: import org.dijon.Dialog;
010: import org.dijon.DialogResource;
011: import org.dijon.Label;
012: import org.dijon.TextField;
013:
014: import com.tc.util.event.UpdateEvent;
015: import com.tc.util.event.UpdateEventListener;
016:
017: import java.awt.BorderLayout;
018: import java.awt.Frame;
019: import java.awt.event.ActionEvent;
020: import java.awt.event.ActionListener;
021: import java.awt.event.HierarchyEvent;
022: import java.awt.event.HierarchyListener;
023: import java.io.IOException;
024: import java.io.InterruptedIOException;
025: import java.util.Map;
026:
027: import javax.management.remote.JMXConnector;
028: import javax.swing.JPasswordField;
029: import javax.swing.JTextField;
030: import javax.swing.SwingUtilities;
031: import javax.swing.Timer;
032:
033: public final class ConnectDialog extends Dialog {
034: private static final long DEFAULT_CONNECT_TIMEOUT_MILLIS = 8000;
035: public static final long CONNECT_TIMEOUT_MILLIS = Long.getLong(
036: "com.tc.admin.connect-timeout",
037: DEFAULT_CONNECT_TIMEOUT_MILLIS).longValue();
038:
039: private ServerConnectionManager m_connectManager;
040: private long m_timeout;
041: private ConnectionListener m_listener;
042: private JMXConnector m_jmxc;
043: private Thread m_mainThread;
044: private Thread m_connectThread;
045: private Timer m_timer;
046: private Exception m_error;
047: private Label m_label;
048: private Button m_cancelButton;
049: private final JTextField m_usernameField;
050: private final JPasswordField m_passwordField;
051: private final Button m_okButton;
052: private final Button m_authCancelButton;
053: private final Container m_emptyPanel;
054: private final Container m_authPanel;
055:
056: public ConnectDialog(Frame parent, ServerConnectionManager scm,
057: ConnectionListener listener) {
058: super (parent, true);
059:
060: m_connectManager = scm;
061: m_timeout = CONNECT_TIMEOUT_MILLIS;
062: m_listener = listener;
063:
064: AdminClientContext acc = AdminClient.getContext();
065: load((DialogResource) acc.topRes.child("ConnectDialog"));
066: m_label = (Label) findComponent("ConnectLabel");
067: m_label.setText("Connecting to " + scm + ". Please wait...");
068: pack();
069:
070: m_cancelButton = (Button) findComponent("CancelButton");
071: m_cancelButton.addActionListener(new ActionListener() {
072: public void actionPerformed(ActionEvent ae) {
073: m_cancelButton.setEnabled(false);
074: m_mainThread.interrupt();
075: m_jmxc = null;
076: ConnectDialog.this .setVisible(false);
077: }
078: });
079: getContentPane().addHierarchyListener(new HL());
080:
081: int delay = 1000;
082: ActionListener taskPerformer = new ActionListener() {
083: public void actionPerformed(ActionEvent evt) {
084: setVisible(false);
085: }
086: };
087:
088: m_emptyPanel = (Container) findComponent("EmptyPanel");
089: m_emptyPanel.setLayout(new BorderLayout());
090:
091: m_authPanel = (Container) AdminClient.getContext().topRes
092: .resolve("AuthPanel");
093:
094: Container credentialsPanel = (Container) m_authPanel
095: .findComponent("CredentialsPanel");
096: m_authPanel.setVisible(false);
097: this .m_usernameField = (JTextField) credentialsPanel
098: .findComponent("UsernameField");
099: this .m_okButton = (Button) m_authPanel
100: .findComponent("OKButton");
101: this .m_authCancelButton = (Button) m_authPanel
102: .findComponent("CancelButton");
103:
104: // must be found last because JPasswordField is not a Dijon Component
105: TextField passwordField = (TextField) credentialsPanel
106: .findComponent("PasswordField");
107: Container passwdHolder = new Container();
108: passwdHolder.setLayout(new BorderLayout());
109: passwdHolder.add(m_passwordField = new JPasswordField());
110: credentialsPanel.replaceChild(passwordField, passwdHolder);
111:
112: m_okButton.addActionListener(new ActionListener() {
113: public void actionPerformed(ActionEvent ae) {
114: final String username = m_usernameField.getText()
115: .trim();
116: final String password = new String(m_passwordField
117: .getPassword()).trim();
118: SwingUtilities.invokeLater(new Thread() {
119: public void run() {
120: m_connectManager.setCredentials(username,
121: password);
122: ((AuthenticatingJMXConnector) m_jmxc)
123: .handleOkClick(username, password);
124: }
125: });
126: }
127: });
128: m_authCancelButton.addActionListener(new ActionListener() {
129: public void actionPerformed(ActionEvent ae) {
130: m_cancelButton.doClick();
131: }
132: });
133:
134: m_timer = new Timer(delay, taskPerformer);
135: m_timer.setRepeats(false);
136: }
137:
138: private void disableAuthenticationDialog() {
139: m_usernameField.setEnabled(false);
140: m_passwordField.setEnabled(false);
141: m_emptyPanel.removeAll();
142: m_usernameField.setText("");
143: m_passwordField.setText("");
144: m_authPanel.setVisible(false);
145: m_authCancelButton.setVisible(false);
146: m_cancelButton.setVisible(true);
147: pack();
148: center(getOwner());
149: }
150:
151: private void enableAuthenticationDialog() {
152: m_emptyPanel.add(m_authPanel);
153: m_cancelButton.setVisible(false);
154: m_authCancelButton.setVisible(true);
155: m_usernameField.setEnabled(true);
156: m_passwordField.setEnabled(true);
157: m_authPanel.setVisible(true);
158: m_authPanel.getRootPane().setDefaultButton(m_okButton);
159: pack();
160: center(getOwner());
161: m_usernameField.grabFocus();
162: }
163:
164: public void setServerConnectionManager(ServerConnectionManager scm) {
165: m_connectManager = scm;
166: m_label.setText("Connecting to " + scm + ". Please wait...");
167: pack();
168: }
169:
170: public ServerConnectionManager getServerConnectionManager() {
171: return m_connectManager;
172: }
173:
174: public void setTimeout(long millis) {
175: m_timeout = millis;
176: }
177:
178: public long getTimeout() {
179: return m_timeout;
180: }
181:
182: public void setConnectionListener(ConnectionListener listener) {
183: m_listener = listener;
184: }
185:
186: public ConnectionListener getConnectionListener() {
187: return m_listener;
188: }
189:
190: public JMXConnector getConnector() {
191: return m_jmxc;
192: }
193:
194: public Exception getError() {
195: return m_error;
196: }
197:
198: class HL implements HierarchyListener {
199: public void hierarchyChanged(HierarchyEvent e) {
200: long flags = e.getChangeFlags();
201:
202: if ((flags & HierarchyEvent.SHOWING_CHANGED) != 0) {
203: if (isShowing()) {
204: m_cancelButton.setEnabled(true);
205: m_mainThread = new MainThread();
206: m_mainThread.start();
207: } else {
208: fireHandleConnect();
209: }
210: }
211: }
212: }
213:
214: protected void fireHandleConnect() {
215: if (m_listener != null) {
216: try {
217: if (m_error == null) {
218: m_listener.handleConnection();
219: } else {
220: m_listener.handleException();
221: }
222: } catch (RuntimeException rte) {
223: rte.printStackTrace();
224: }
225: }
226: }
227:
228: // --------------------------------------------------------------------------------
229:
230: class MainThread extends Thread {
231:
232: private boolean m_isConnecting = true;
233: private boolean m_join;
234: private final ConnectionTimer m_connectionTimer = new ConnectionTimer();
235:
236: public void run() {
237: m_connectThread = new ConnectThread();
238: try {
239: m_error = null;
240: m_jmxc = new AuthenticatingJMXConnector(
241: m_connectManager);
242: ((AuthenticatingJMXConnector) m_jmxc)
243: .addAuthenticationListener(new UpdateEventListener() {
244: public void handleUpdate(UpdateEvent obj) {
245: m_connectionTimer.stopTimer();
246: m_connectionTimer.interrupt();
247: enableAuthenticationDialog();
248: }
249: });
250: ((AuthenticatingJMXConnector) m_jmxc)
251: .addCollapseListener(new UpdateEventListener() {
252: public void handleUpdate(UpdateEvent obj) {
253: m_connectionTimer.setTimer();
254: disableAuthenticationDialog();
255: }
256: });
257: ((AuthenticatingJMXConnector) m_jmxc)
258: .addExceptionListener(new UpdateEventListener() {
259: public void handleUpdate(UpdateEvent obj) {
260: m_connectionTimer.setTimer();
261: m_connectionTimer.interrupt();
262: disableAuthenticationDialog();
263: }
264: });
265:
266: if (m_jmxc != null && m_error == null) {
267: m_connectThread.start();
268: m_connectionTimer.start();
269: synchronized (this ) {
270: while (m_isConnecting)
271: wait();
272: if (m_join)
273: m_connectThread.join(m_timeout);
274: }
275: }
276: } catch (IOException e) {
277: m_error = e;
278: } catch (InterruptedException e) {
279: m_connectThread.interrupt();
280: m_connectionTimer.interrupt();
281: disableAuthenticationDialog();
282: m_error = new InterruptedIOException("Interrupted");
283: return;
284: }
285:
286: if (m_error == null && m_connectThread.isAlive()) {
287: m_connectThread.interrupt();
288: m_error = new InterruptedIOException(
289: "Connection timed out");
290: }
291:
292: if (m_error != null) {
293: m_connectThread.interrupt();
294: }
295:
296: m_timer.start();
297: }
298:
299: private synchronized void connectionJoin() {
300: if (m_connectionTimer.isAlive()) {
301: m_connectionTimer.stopTimer();
302: m_connectionTimer.interrupt();
303: }
304:
305: m_join = true;
306: m_isConnecting = false;
307: notifyAll();
308: }
309:
310: private synchronized void connectionTimeout() {
311: m_isConnecting = false;
312: notifyAll();
313: }
314: }
315:
316: // --------------------------------------------------------------------------------
317:
318: class ConnectThread extends Thread {
319:
320: public ConnectThread() {
321: setDaemon(true);
322: }
323:
324: public void run() {
325: try {
326: m_jmxc.connect(m_connectManager
327: .getConnectionEnvironment());
328: ((MainThread) m_mainThread).connectionJoin();
329: } catch (IOException e) {
330: m_error = e;
331: } catch (RuntimeException e) {
332: if (e instanceof AuthenticatingJMXConnector.AuthenticationException) {
333: return;
334: }
335: m_error = e;
336: }
337: }
338: }
339:
340: // --------------------------------------------------------------------------------
341:
342: private class ConnectionTimer extends Thread {
343:
344: private boolean isSet;
345:
346: private ConnectionTimer() {
347: setDaemon(true);
348: }
349:
350: public void run() {
351: try {
352: startTimer();
353: } catch (InterruptedException e) {
354: // do nothing
355: }
356: }
357:
358: private void startTimer() throws InterruptedException {
359: isSet = true;
360: try {
361: Thread.sleep(m_timeout);
362: } catch (InterruptedException e) {
363: // do nothing
364: }
365: if (isSet) {
366: ((MainThread) m_mainThread).connectionTimeout();
367: return;
368: }
369: while (!isSet) {
370: synchronized (this ) {
371: wait();
372: }
373: }
374: ((MainThread) m_mainThread).connectionJoin();
375: }
376:
377: private synchronized void setTimer() {
378: isSet = true;
379: notifyAll();
380: }
381:
382: private synchronized void stopTimer() {
383: isSet = false;
384: notifyAll();
385: }
386: }
387:
388: // --------------------------------------------------------------------------------
389:
390: void tearDown() {
391: Map env = m_connectManager.getConnectionEnvironment();
392: if (env != null) {
393: env.clear();
394: }
395:
396: m_connectManager = null;
397: m_listener = null;
398: m_jmxc = null;
399: m_mainThread = null;
400: m_connectThread = null;
401: m_cancelButton = null;
402: m_timer = null;
403: m_error = null;
404: }
405: }
|