View Javadoc

1   package ch.odi.justblog.gui.swing;
2   
3   import java.awt.Component;
4   import java.awt.Container;
5   import java.awt.Frame;
6   import java.awt.GridBagConstraints;
7   import java.awt.GridBagLayout;
8   import java.awt.Insets;
9   import java.awt.event.ActionEvent;
10  import java.awt.event.ActionListener;
11  import java.io.IOException;
12  import java.util.ArrayList;
13  import java.util.Locale;
14  
15  import javax.security.auth.callback.Callback;
16  import javax.security.auth.callback.ChoiceCallback;
17  import javax.security.auth.callback.ConfirmationCallback;
18  import javax.security.auth.callback.LanguageCallback;
19  import javax.security.auth.callback.NameCallback;
20  import javax.security.auth.callback.PasswordCallback;
21  import javax.security.auth.callback.TextInputCallback;
22  import javax.security.auth.callback.TextOutputCallback;
23  import javax.security.auth.callback.UnsupportedCallbackException;
24  import javax.swing.BoxLayout;
25  import javax.swing.ButtonGroup;
26  import javax.swing.JButton;
27  import javax.swing.JCheckBox;
28  import javax.swing.JComponent;
29  import javax.swing.JDialog;
30  import javax.swing.JLabel;
31  import javax.swing.JPanel;
32  import javax.swing.JPasswordField;
33  import javax.swing.JRadioButton;
34  import javax.swing.JTextField;
35  import javax.swing.JToggleButton;
36  
37  import ch.odi.justblog.gui.IAuthenticator;
38  
39  /***
40   * Creates a Swing GUI for authentication. 
41   * @author oglueck
42   */
43  public class DialogAuthenticator implements IAuthenticator {
44      Frame owner;
45      String title;
46      
47      /***
48       * 
49       */
50      public DialogAuthenticator(Frame owner) {
51          this.owner = owner;
52      }
53  
54      /***
55       * Sets the text to use as the dialog title.
56       * @param context the dialog title or <code>null</code>.
57       */
58      public void setContext(String context) {
59          this.title = context;
60      }
61  
62      /***
63       * Creates a dialog out of the callbacks and pushes the information
64       * entered by the user back into the callbacks.
65       */
66      public void handle(Callback[] callbacks) throws IOException,
67              UnsupportedCallbackException {
68          final JDialog dlg = new JDialog(owner, true);
69          dlg.setTitle("Authenticate");
70          final Container cp = dlg.getContentPane();
71          GridBagLayout lo = new GridBagLayout();
72          GridBagConstraints cs = new GridBagConstraints();
73          cs.insets = new Insets(5,5,5, 5);
74          cs.gridwidth = GridBagConstraints.REMAINDER;
75          cs.anchor = GridBagConstraints.NORTHWEST;
76          cp.setLayout(lo);
77          JLabel lbl = new JLabel(title);
78          cp.add(lbl);
79          lo.setConstraints(lbl, cs);
80          // will be set true whenever there is real content the user has to answer.
81          boolean displayable = false;
82          for (int i=0; i<callbacks.length; i++) {
83              Callback cb = callbacks[i];
84              if (cb instanceof LanguageCallback) {
85                  LanguageCallback lc = (LanguageCallback) cb;
86                  lc.setLocale(Locale.getDefault());
87              } else if (cb instanceof NameCallback) {
88                  JLabel label = new JLabel(((NameCallback) cb).getPrompt()); 
89                  cp.add(label);
90                  cs.gridwidth = 1;
91                  lo.setConstraints(label, cs);
92                  JComponent panel = new NameControl((NameCallback) cb);
93                  cp.add(panel);
94                  cs.gridwidth = GridBagConstraints.REMAINDER;
95                  lo.setConstraints(panel, cs);
96                  displayable = true;
97              } else if (cb instanceof PasswordCallback) {
98                  JLabel label = new JLabel(((PasswordCallback) cb).getPrompt());
99                  cp.add(label);
100                 cs.gridwidth = 1;
101                 lo.setConstraints(label, cs);
102                 JComponent panel = new PasswordControl((PasswordCallback) cb);
103                 cp.add(panel);
104                 cs.gridwidth = GridBagConstraints.REMAINDER;
105                 lo.setConstraints(panel, cs);
106                 displayable = true;
107             } else if (cb instanceof TextOutputCallback) {
108                 String label;
109                 switch (((TextOutputCallback) cb).getMessageType()) {
110                     case TextOutputCallback.ERROR:
111                         label = "Error";
112                     break;
113                     
114                     case TextOutputCallback.WARNING:
115                         label = "Warning";
116                     break;
117                     
118                     case TextOutputCallback.INFORMATION:
119                         label = "Information";
120                     break;
121                     
122                     default:
123                         label = "";
124                 }
125                 JLabel jlabel = new JLabel(label);
126                 cp.add(jlabel);
127                 cs.gridwidth = 1;
128                 lo.setConstraints(jlabel, cs);
129                 JComponent panel = new JLabel(((TextOutputCallback) cb).getMessage());
130                 cp.add(panel);
131                 cs.gridwidth = GridBagConstraints.REMAINDER;
132                 lo.setConstraints(panel, cs);
133                 displayable = true;
134             } else if (cb instanceof TextInputCallback) {
135                 JLabel label = new JLabel(((TextInputCallback) cb).getPrompt()); 
136                 cp.add(label);
137                 cs.gridwidth = 1;
138                 lo.setConstraints(label, cs);
139                 JComponent panel = new TextInputControl((TextInputCallback) cb);
140                 cp.add(panel);
141                 cs.gridwidth = GridBagConstraints.REMAINDER;
142                 lo.setConstraints(panel, cs);
143                 displayable = true;
144             } else if (cb instanceof ChoiceCallback) {
145                 JLabel label = new JLabel(((ChoiceCallback) cb).getPrompt());
146                 cp.add(label);
147                 cs.gridwidth = 1;
148                 lo.setConstraints(label, cs);
149                 JComponent panel = new ChoiceControl((ChoiceCallback) cb);
150                 cp.add(panel);
151                 cs.gridwidth = GridBagConstraints.REMAINDER;
152                 lo.setConstraints(panel, cs);
153                 displayable = true;
154             } else if (cb instanceof ConfirmationCallback) {
155                 String prompt;
156                 switch (((ConfirmationCallback) cb).getMessageType()) {
157                     case ConfirmationCallback.ERROR:
158                         prompt = "Error";
159                     break;
160                     
161                     case ConfirmationCallback.WARNING:
162                         prompt = "Warning";
163                     break;
164                     
165                     case ConfirmationCallback.INFORMATION:
166                         prompt = "Information";
167                     break;
168                     
169                     default:
170                         prompt = "";
171                 }
172                 if (((ConfirmationCallback) cb).getPrompt() != null) {
173                     prompt += ": "+ ((ConfirmationCallback) cb).getPrompt();
174                 }
175                 JLabel label = new JLabel(prompt);
176                 cp.add(label);
177                 cs.gridwidth = 1;
178                 lo.setConstraints(label, cs);
179                 JComponent panel = new ConfirmationControl((ConfirmationCallback) cb);
180                 cp.add(panel);
181                 cs.gridwidth = GridBagConstraints.REMAINDER;
182                 lo.setConstraints(panel, cs);
183                 displayable = true;
184             } else throw new UnsupportedCallbackException(cb);
185 
186         }
187         if (!displayable) {
188             dlg.dispose();
189             return;
190         }
191         JButton ok = new JButton("Ok");
192         ok.setActionCommand("ok");
193         ok.addActionListener(
194             new ActionListener() {
195                 public void actionPerformed(ActionEvent e) {
196                     try {
197                         Component[] components = cp.getComponents();
198                         for (int i = 0; i < components.length; i++) {
199                             if (! (components[i] instanceof Commitable)) continue;
200                             ((Commitable) components[i]).commit();
201                         }
202                     } finally {
203                         dlg.dispose();
204                     }
205                 }
206             }
207         );
208         ok.setDefaultCapable(true);
209         cp.add(ok);
210         cs.anchor = GridBagConstraints.NORTHEAST;
211         lo.setConstraints(ok, cs);
212         dlg.getRootPane().setDefaultButton(ok);
213         dlg.pack();
214         dlg.setResizable(false);
215         dlg.show();
216     }
217 
218     interface Commitable {
219         void commit();
220     }
221 
222     class NameControl extends JTextField implements Commitable {
223         private NameCallback cb;
224         
225         public NameControl(NameCallback cb) {
226             super(10);
227             this.cb = cb;
228         }
229         
230         public void commit() {
231             cb.setName(this.getText());
232         }
233     }
234 
235     class TextInputControl extends JTextField implements Commitable {
236         private TextInputCallback cb;
237         
238         public TextInputControl(TextInputCallback cb) {
239             super(10);
240             this.cb = cb;
241             this.setText(cb.getDefaultText());
242         }
243         
244         public void commit() {
245             cb.setText(this.getText());
246         }
247     }
248     
249     class PasswordControl extends JPasswordField implements Commitable {
250         private PasswordCallback cb;
251         
252         public PasswordControl(PasswordCallback cb) {
253             super(10);
254             this.cb = cb;
255         }
256         
257         public void commit() {
258             cb.setPassword(this.getPassword());
259         }
260     }
261     
262     class ChoiceControl extends JPanel implements Commitable {
263         private ChoiceCallback cb;
264         
265         public ChoiceControl(ChoiceCallback cb) {
266             this.cb = cb;
267             BoxLayout lo = new BoxLayout(this, BoxLayout.Y_AXIS);
268             this.setLayout(lo);
269             String[] choices = cb.getChoices();
270             
271             if (cb.allowMultipleSelections()) {
272                 for(int i = 0; i < choices.length; i++) {
273                     boolean selected = (cb.getDefaultChoice() == i);
274                     JCheckBox rb = new JCheckBox(choices[i], selected);
275                     this.add(rb);
276                 }
277                 
278             } else {
279                 ButtonGroup group = new ButtonGroup();
280                 for(int i = 0; i < choices.length; i++) {
281                     boolean selected = (cb.getDefaultChoice() == i);
282                     JRadioButton rb = new JRadioButton(choices[i], selected);
283                     this.add(rb);
284                     group.add(rb);
285                 }
286             }
287         }
288 
289         public void commit() {
290             Component[] comps = this.getComponents();
291 
292             if (cb.allowMultipleSelections()) {
293                 ArrayList indexes = new ArrayList(comps.length);
294                 for(int i = 0; i < comps.length; i++) {
295                     if (comps[i] instanceof JToggleButton) {
296                         if (((JToggleButton) comps[i]).isSelected()) indexes.add(new Integer(i));
297                     }
298                 }
299                 
300                 int[] choices = new int[indexes.size()];
301                 for (int i = 0; i < indexes.size(); i++) {
302                     int index = ((Integer) indexes.get(i)).intValue();
303                     choices[i] = index;
304                 }
305                 cb.setSelectedIndexes(choices);
306             } else {
307                 for(int i = 0; i < comps.length; i++) {
308                     if (comps[i] instanceof JToggleButton) {
309                         if (((JToggleButton) comps[i]).isSelected()) {
310                             cb.setSelectedIndex(i);
311                         }
312                     }
313                 }
314             }
315         }
316     }
317     
318     class ConfirmationControl extends JPanel implements Commitable {
319         private ConfirmationCallback cb;
320         private int[] options;
321         
322         public ConfirmationControl(ConfirmationCallback cb) {
323             this.cb = cb;
324             BoxLayout lo = new BoxLayout(this, BoxLayout.Y_AXIS);
325             this.setLayout(lo);
326             String[] choices = cb.getOptions();
327             
328             if ((choices == null) || (cb.getOptionType() == ConfirmationCallback.UNSPECIFIED_OPTION)) {
329                 switch (cb.getOptionType()) {
330                     case ConfirmationCallback.OK_CANCEL_OPTION:
331                         choices = new String[] { "Ok", "Cancel" };
332                         options = new int[] { ConfirmationCallback.OK, 
333                                               ConfirmationCallback.CANCEL };
334                     break;
335                     
336                     case ConfirmationCallback.YES_NO_CANCEL_OPTION:
337                         choices = new String[] { "Yes", "No", "Cancel" };
338                         options = new int[] { ConfirmationCallback.YES, 
339                                               ConfirmationCallback.NO,
340                                               ConfirmationCallback.CANCEL };
341                     break;
342                     
343                     case ConfirmationCallback.YES_NO_OPTION:
344                         choices = new String[] { "Yes", "No" };
345                         options = new int[] { ConfirmationCallback.YES, 
346                                               ConfirmationCallback.NO };
347                     break;
348                 }
349             }
350             
351             ButtonGroup group = new ButtonGroup();
352             for(int i = 0; i < choices.length; i++) {
353                 boolean selected = (cb.getDefaultOption() == i);
354                 JRadioButton rb = new JRadioButton(choices[i], selected);
355                 this.add(rb);
356                 group.add(rb);
357             }
358         }
359 
360         public void commit() {
361             Component[] comps = this.getComponents();
362 
363             if (cb.getOptionType() == ConfirmationCallback.UNSPECIFIED_OPTION) {
364                 for(int i = 0; i < comps.length; i++) {
365                     if (comps[i] instanceof JToggleButton) {
366                         if (((JToggleButton) comps[i]).isSelected()) {
367                             cb.setSelectedIndex(i);
368                         }
369                     }
370                 }
371             } else {
372                 for(int i = 0; i < comps.length; i++) {
373                     if (comps[i] instanceof JToggleButton) {
374                         if (((JToggleButton) comps[i]).isSelected()) {
375                             cb.setSelectedIndex(options[i]);
376                         }
377                     }
378                 }
379             }
380         }
381     }
382 }