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