]> git.argeo.org Git - lgpl/argeo-commons.git/blob - AbstractLoginDialog.java
fecb80afc9107ecc46c2c440b61f4ee5669d112a
[lgpl/argeo-commons.git] / AbstractLoginDialog.java
1 package org.argeo.security.ui.dialogs;
2
3 import java.io.IOException;
4
5 import javax.security.auth.callback.Callback;
6 import javax.security.auth.callback.CallbackHandler;
7 import javax.security.auth.callback.NameCallback;
8 import javax.security.auth.callback.PasswordCallback;
9
10 import org.apache.commons.logging.Log;
11 import org.apache.commons.logging.LogFactory;
12 import org.argeo.security.ui.SecurityUiPlugin;
13 import org.eclipse.core.runtime.IProgressMonitor;
14 import org.eclipse.core.runtime.NullProgressMonitor;
15 import org.eclipse.jface.dialogs.IDialogConstants;
16 import org.eclipse.jface.dialogs.TrayDialog;
17 import org.eclipse.jface.operation.IRunnableWithProgress;
18 import org.eclipse.jface.operation.ModalContext;
19 import org.eclipse.swt.events.SelectionEvent;
20 import org.eclipse.swt.events.SelectionListener;
21 import org.eclipse.swt.widgets.Button;
22 import org.eclipse.swt.widgets.Display;
23 import org.eclipse.swt.widgets.Shell;
24
25 /** Base for login dialogs */
26 public abstract class AbstractLoginDialog extends TrayDialog implements
27 CallbackHandler {
28
29 private final static Log log = LogFactory.getLog(AbstractLoginDialog.class);
30
31 private Thread modalContextThread = null;
32 boolean processCallbacks = false;
33 boolean isCancelled = false;
34 Callback[] callbackArray;
35
36 protected final Callback[] getCallbacks() {
37 return this.callbackArray;
38 }
39
40 public abstract void internalHandle();
41
42 public boolean isCancelled() {
43 return isCancelled;
44 }
45
46 protected AbstractLoginDialog(Shell parentShell) {
47 super(parentShell);
48 }
49
50 /*
51 * (non-Javadoc)
52 *
53 * @see
54 * javax.security.auth.callback.CallbackHandler#handle(javax.security.auth
55 * .callback.Callback[])
56 */
57 public void handle(final Callback[] callbacks) throws IOException {
58 // clean previous usage
59 if (processCallbacks) {
60 // this handler was already used
61 processCallbacks = false;
62 }
63
64 if (modalContextThread != null) {
65 try {
66 modalContextThread.join(1000);
67 } catch (InterruptedException e) {
68 // silent
69 }
70 modalContextThread = null;
71 }
72
73 // initialize
74 this.callbackArray = callbacks;
75 final Display display = Display.getDefault();
76 display.syncExec(new Runnable() {
77
78 public void run() {
79 isCancelled = false;
80 setBlockOnOpen(false);
81 open();
82 final Button okButton = getButton(IDialogConstants.OK_ID);
83 okButton.setText("Login");
84 okButton.addSelectionListener(new SelectionListener() {
85
86 public void widgetSelected(final SelectionEvent event) {
87 processCallbacks = true;
88 }
89
90 public void widgetDefaultSelected(final SelectionEvent event) {
91 // nothing to do
92 }
93 });
94 final Button cancel = getButton(IDialogConstants.CANCEL_ID);
95 cancel.addSelectionListener(new SelectionListener() {
96
97 public void widgetSelected(final SelectionEvent event) {
98 isCancelled = true;
99 processCallbacks = true;
100 }
101
102 public void widgetDefaultSelected(final SelectionEvent event) {
103 // nothing to do
104 }
105 });
106 }
107 });
108 try {
109 ModalContext.setAllowReadAndDispatch(true); // Works for now.
110 ModalContext.run(new IRunnableWithProgress() {
111
112 public void run(final IProgressMonitor monitor) {
113 modalContextThread = Thread.currentThread();
114 // Wait here until OK or cancel is pressed, then let it rip.
115 // The event
116 // listener
117 // is responsible for closing the dialog (in the
118 // loginSucceeded
119 // event).
120 while (!processCallbacks && (modalContextThread != null)
121 && (modalContextThread == Thread.currentThread())
122 && SecurityUiPlugin.getDefault() != null) {
123 // Note: SecurityUiPlugin.getDefault() != null is false
124 // when the OSGi runtime is shut down
125 try {
126 Thread.sleep(100);
127 // if (display.isDisposed()) {
128 // log.warn("Display is disposed, killing login dialog thread");
129 // throw new ThreadDeath();
130 // }
131 } catch (final Exception e) {
132 // do nothing
133 }
134 }
135 processCallbacks = false;
136 // Call the adapter to handle the callbacks
137 if (!isCancelled())
138 internalHandle();
139 else
140 // clear callbacks are when cancelling
141 for (Callback callback : callbacks)
142 if (callback instanceof PasswordCallback)
143 ((PasswordCallback) callback).setPassword(null);
144 else if (callback instanceof NameCallback)
145 ((NameCallback) callback).setName(null);
146 }
147 }, true, new NullProgressMonitor(), Display.getDefault());
148 } catch (ThreadDeath e) {
149 isCancelled = true;
150 log.debug("Thread " + Thread.currentThread().getId() + " died");
151 throw e;
152 } catch (Exception e) {
153 isCancelled = true;
154 IOException ioe = new IOException(
155 "Unexpected issue in login dialog, see root cause for more details");
156 ioe.initCause(e);
157 throw ioe;
158 } finally {
159 // so that the modal thread dies
160 processCallbacks = true;
161 // try {
162 // // wait for the modal context thread to gracefully exit
163 // modalContextThread.join();
164 // } catch (InterruptedException ie) {
165 // // silent
166 // }
167 modalContextThread = null;
168 }
169 }
170
171 protected void configureShell(Shell shell) {
172 super.configureShell(shell);
173 shell.setText("Login");
174 }
175 }