001    /* ConfirmationCallback.java -- callback for confirmations.
002       Copyright (C) 2003, Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.security.auth.callback;
040    
041    import java.io.Serializable;
042    
043    /**
044     * Underlying security services instantiate and pass a
045     * <code>ConfirmationCallback</code> to the <code>handle()</code> method of a
046     * {@link CallbackHandler} to ask for YES/NO, OK/CANCEL, YES/NO/CANCEL or other
047     * similar confirmations.
048     *
049     * @see CallbackHandler
050     */
051    public class ConfirmationCallback implements Callback, Serializable
052    {
053    
054      // Constants and variables
055      // -------------------------------------------------------------------------
056    
057      /**
058       * <p>Unspecified option type.</p>
059       *
060       * <p>The <code>getOptionType</code> method returns this value if this
061       * <code>ConfirmationCallback</code> was instantiated with <code>options</code>
062       * instead of an <code>optionType</code>.</p>
063       */
064      public static final int UNSPECIFIED_OPTION = -1;
065    
066      /**
067       * <p>YES/NO confirmation option.</p>
068       *
069       * <p>An underlying security service specifies this as the <code>optionType</code>
070       * to a <code>ConfirmationCallback</code> constructor if it requires a
071       * confirmation which can be answered with either <code>YES</code> or
072       * <code>NO</code>.</p>
073       */
074      public static final int YES_NO_OPTION = 0;
075    
076      /**
077       * <p>YES/NO/CANCEL confirmation confirmation option.</p>
078       *
079       * <p>An underlying security service specifies this as the <code>optionType</code>
080       * to a <code>ConfirmationCallback</code> constructor if it requires a
081       * confirmation which can be answered with either <code>YES</code>,
082       * <code>NO</code> or <code>CANCEL</code>.
083       */
084      public static final int YES_NO_CANCEL_OPTION = 1;
085    
086      /**
087       * <p>OK/CANCEL confirmation confirmation option.</p>
088       *
089       * <p>An underlying security service specifies this as the <code>optionType</code>
090       * to a <code>ConfirmationCallback</code> constructor if it requires a
091       * confirmation which can be answered with either <code>OK</code> or
092       * <code>CANCEL</code>.</p>
093       */
094      public static final int OK_CANCEL_OPTION = 2;
095    
096      /**
097       * <p>YES option.</p>
098       *
099       * <p>If an <code>optionType</code> was specified to this
100       * <code>ConfirmationCallback</code>, this option may be specified as a
101       * <code>defaultOption</code> or returned as the selected index.</p>
102       */
103      public static final int YES = 0;
104    
105      /**
106       * <p>NO option.</p>
107       *
108       * <p>If an <code>optionType</code> was specified to this
109       * <code>ConfirmationCallback</code>, this option may be specified as a
110       * <code>defaultOption</code> or returned as the selected index.</p>
111       */
112      public static final int NO = 1;
113    
114      /**
115       * <p>CANCEL option.</p>
116       *
117       * <p>If an <code>optionType</code> was specified to this
118       * <code>ConfirmationCallback</code>, this option may be specified as a
119       * <code>defaultOption</code> or returned as the selected index.</p>
120       */
121      public static final int CANCEL = 2;
122    
123      /**
124       * <p>OK option.</p>
125       *
126       * <p>If an <code>optionType</code> was specified to this
127       * <code>ConfirmationCallback</code>, this option may be specified as a
128       * <code>defaultOption</code> or returned as the selected index.</p>
129       */
130      public static final int OK = 3;
131    
132      /** INFORMATION message type. */
133      public static final int INFORMATION = 0;
134    
135      /** WARNING message type. */
136      public static final int WARNING = 1;
137    
138      /** ERROR message type. */
139      public static final int ERROR = 2;
140    
141      /**
142       * @serial
143       * @since 1.4
144       */
145      private String prompt;
146    
147      /**
148       * @serial
149       * @since 1.4
150       */
151      private int messageType;
152    
153      /**
154       * @serial
155       * @since 1.4
156       */
157      private int optionType;
158    
159      /**
160       * @serial
161       * @since 1.4
162       */
163      private int defaultOption;
164    
165      /**
166       * @serial
167       * @since 1.4
168       */
169      private String[] options = null;
170    
171      /**
172       * @serial
173       * @since 1.4
174       */
175      private int selection;
176    
177      // Constructor(s)
178      // -------------------------------------------------------------------------
179    
180      /**
181       * <p>Construct a <code>ConfirmationCallback</code> with a message type, an
182       * option type and a default option.</p>
183       *
184       * <p>Underlying security services use this constructor if they require
185       * either a YES/NO, YES/NO/CANCEL or OK/CANCEL confirmation.</p>
186       *
187       * @param messageType the message type (INFORMATION, WARNING or ERROR).
188       * @param optionType the option type (YES_NO_OPTION, YES_NO_CANCEL_OPTION or
189       * OK_CANCEL_OPTION).
190       * @param defaultOption the default option from the provided optionType (YES,
191       * NO, CANCEL or OK).
192       * @throws IllegalArgumentException if <code>messageType</code> is not either
193       * <code>INFORMATION</code>, <code>WARNING</code>, or <code>ERROR</code>, if
194       * <code>optionType</code> is not either <code>YES_NO_OPTION</code>,
195       * <code>YES_NO_CANCEL_OPTION</code>, or <code>OK_CANCEL_OPTION</code>, or if
196       * <code>defaultOption</code> does not correspond to one of the options in
197       * <code>optionType</code>.
198       */
199      public ConfirmationCallback(int messageType, int optionType, int defaultOption)
200        throws IllegalArgumentException
201      {
202        super();
203    
204        setMessageType(messageType);
205        setOptionType(optionType, defaultOption);
206        this.defaultOption = defaultOption;
207      }
208    
209      /**
210       * <p>Construct a <code>ConfirmationCallback</code> with a message type, a
211       * list of options and a default option.</p>
212       *
213       * <p>Underlying security services use this constructor if they require a
214       * confirmation different from the available preset confirmations provided
215       * (for example, CONTINUE/ABORT or STOP/GO). The confirmation options are
216       * listed in the <code>options</code> array, and are displayed by the
217       * {@link CallbackHandler} implementation in a manner consistent with the
218       * way preset options are displayed.</p>
219       *
220       * @param messageType the message type (INFORMATION, WARNING or ERROR).
221       * @param options the list of confirmation options.
222       * @param defaultOption the default option, represented as an index into the
223       * <code>options</code> array.
224       * @throws IllegalArgumentException if <code>messageType</code> is not either
225       * <code>INFORMATION</code>, <code>WARNING</code>, or <code>ERROR</code>, if
226       * <code>options</code> is <code>null</code>, if <code>options</code> has a
227       * length of <code>0</code>, if any element from <code>options</code> is
228       * <code>null</code>, if any element from <code>options</code> has a length
229       * of <code>0</code>, or if <code>defaultOption</code> does not lie within
230       * the array boundaries of <code>options</code>.
231       */
232      public ConfirmationCallback(int messageType, String[] options, int defaultOption)
233      {
234        super();
235    
236        setMessageType(messageType);
237        setOptions(options, defaultOption);
238        this.defaultOption = defaultOption;
239      }
240    
241      /**
242       * <p>Construct a <code>ConfirmationCallback</code> with a prompt, message
243       * type, an option type and a default option.</p>
244       *
245       * <p>Underlying security services use this constructor if they require
246       * either a YES/NO, YES/NO/CANCEL or OK/CANCEL confirmation.</p>
247       *
248       * @param prompt the prompt used to describe the list of options.
249       * @param messageType the message type (INFORMATION, WARNING or ERROR).
250       * @param optionType the option type (YES_NO_OPTION, YES_NO_CANCEL_OPTION or
251       * OK_CANCEL_OPTION).
252       * @param defaultOption the default option from the provided optionType (YES,
253       * NO, CANCEL or OK).
254       * @throws IllegalArgumentException if <code>prompt</code> is <code>null</code>,
255       * if <code>prompt</code> has a length of <code>0</code>, if
256       * <code>messageType</code> is not either <code>INFORMATION</code>,
257       * <code>WARNING</code>, or <code>ERROR</code>, if <code>optionType</code> is
258       * not either <code>YES_NO_OPTION</code>, <code>YES_NO_CANCEL_OPTION</code>,
259       * or <code>OK_CANCEL_OPTION</code>, or if <code>defaultOption</code> does
260       * not correspond to one of the options in <code>optionType</code>.
261       */
262      public ConfirmationCallback(String prompt, int messageType, int optionType,
263                                  int defaultOption)
264      {
265        super();
266    
267        setPrompt(prompt);
268        setMessageType(messageType);
269        setOptionType(optionType, defaultOption);
270        this.defaultOption = defaultOption;
271      }
272    
273      /**
274       * <p>Construct a <code>ConfirmationCallback</code> with a prompt, message
275       * type, a list of options and a default option.</p>
276       *
277       * <p>Underlying security services use this constructor if they require a
278       * confirmation different from the available preset confirmations provided
279       * (for example, CONTINUE/ABORT or STOP/GO). The confirmation options are
280       * listed in the <code>options</code> array, and are displayed by the
281       * {@link CallbackHandler} implementation in a manner consistent with the
282       * way preset options are displayed.</p>
283       *
284       * @param prompt the prompt used to describe the list of options.
285       * @param messageType the message type (INFORMATION, WARNING or ERROR).
286       * @param options the list of confirmation options.
287       * @param defaultOption the default option, represented as an index into the
288       * <code>options</code> array.
289       * @throws IllegalArgumentException if <code>prompt</code> is <code>null</code>,
290       * if <code>prompt</code> has a length of <code>0</code>, if
291       * <code>messageType</code> is not either <code>INFORMATION</code>,
292       * <code>WARNING</code>, or <code>ERROR</code>, if <code>options</code> is
293       * <code>null</code>, if <code>options</code> has a length of <code>0</code>,
294       * if any element from <code>options</code> is <code>null</code>, if any
295       * element from <code>options</code> has a length of <code>0</code>, or if
296       * <code>defaultOption</code> does not lie within the array boundaries of
297       * <code>options</code>.
298       */
299      public ConfirmationCallback(String prompt, int messageType, String[] options,
300                                  int defaultOption)
301      {
302        super();
303    
304        setPrompt(prompt);
305        setMessageType(messageType);
306        setOptions(options, defaultOption);
307        this.defaultOption = defaultOption;
308      }
309    
310      // Class methods
311      // -------------------------------------------------------------------------
312    
313      // Instance methods
314      // -------------------------------------------------------------------------
315    
316      /**
317       * Get the prompt.
318       *
319       * @return the prompt, or <code>null</code> if this
320       * <code>ConfirmationCallback</code> was instantiated without a prompt.
321       */
322      public String getPrompt()
323      {
324        return prompt;
325      }
326    
327      /**
328       * Get the message type.
329       *
330       * @return the message type (INFORMATION, WARNING or ERROR).
331       */
332      public int getMessageType()
333      {
334        return messageType;
335      }
336    
337      /**
338       * <p>Get the option type.</p>
339       *
340       * <p>If this method returns {@link #UNSPECIFIED_OPTION}, then this
341       * <code>ConfirmationCallback</code> was instantiated with <code>options</code>
342       * instead of an <code>optionType</code>. In this case, invoke the
343       * {@link #getOptions()} method to determine which confirmation options to
344       * display.</p>
345       *
346       * @return the option type (YES_NO_OPTION, YES_NO_CANCEL_OPTION or
347       * OK_CANCEL_OPTION), or UNSPECIFIED_OPTION if this
348       * <code>ConfirmationCallback</code> was instantiated with <code>options</code>
349       * instead of an <code>optionType</code>.
350       */
351      public int getOptionType()
352      {
353        if (options != null)
354          {
355            return UNSPECIFIED_OPTION;
356          }
357        return optionType;
358      }
359    
360      /**
361       * Get the confirmation options.
362       *
363       * @return the list of confirmation options, or <code>null</code> if this
364       * <code>ConfirmationCallback</code> was instantiated with an
365       * <code>optionType</code> instead of <code>options</code>.
366       */
367      public String[] getOptions()
368      {
369        return options;
370      }
371    
372      /**
373       * Get the default option.
374       *
375       * @return the default option, represented as <code>YES</code>, <code>NO</code>,
376       * <code>OK</code> or <code>CANCEL</code> if an <code>optionType</code> was
377       * specified to the constructor of this <code>ConfirmationCallback</code>.
378       * Otherwise, this method returns the default option as an index into the
379       * <code>options</code> array specified to the constructor of this
380       * <code>ConfirmationCallback</code>.
381       */
382      public int getDefaultOption()
383      {
384        return defaultOption;
385      }
386    
387      /**
388       * Set the selected confirmation option.
389       *
390       * @param selection the selection represented as <code>YES</code>,
391       * <code>NO</code>, <code>OK</code> or <code>CANCEL</code> if an
392       * <code>optionType</code> was specified to the constructor of this
393       * <code>ConfirmationCallback</code>. Otherwise, the <code>selection</code>
394       * represents the index into the <code>options</code> array specified to the
395       * constructor of this <code>ConfirmationCallback</code>.
396       * @see #getSelectedIndex()
397       */
398      public void setSelectedIndex(int selection)
399      {
400        if (options != null)
401          {
402            setOptions(options, selection);
403          }
404        else
405          {
406            setOptionType(optionType, selection);
407          }
408      }
409    
410      /**
411       * Get the selected confirmation option.
412       *
413       * @return the selected confirmation option represented as <code>YES</code>,
414       * <code>NO</code>, <code>OK</code> or <code>CANCEL</code> if an
415       * <code>optionType</code> was specified to the constructor of this
416       * <code>ConfirmationCallback</code>. Otherwise, this method returns the
417       * selected confirmation option as an index into the <code>options</code>
418       * array specified to the constructor of this <code>ConfirmationCallback</code>.
419       * @see #setSelectedIndex(int)
420       */
421      public int getSelectedIndex()
422      {
423        return this.selection;
424      }
425    
426      private void setMessageType(int messageType) throws IllegalArgumentException
427      {
428        switch (messageType)
429          {
430          case INFORMATION:
431          case WARNING:
432          case ERROR: this.messageType = messageType; break;
433          default: throw new IllegalArgumentException("illegal message type");
434          }
435      }
436    
437      private void setOptionType(int optionType, int selectedOption)
438        throws IllegalArgumentException
439      {
440        switch (optionType)
441          {
442          case YES_NO_OPTION:
443            this.optionType = optionType;
444            switch (selectedOption)
445              {
446              case YES:
447              case NO: this.selection = selectedOption; break;
448              default: throw new IllegalArgumentException("invalid option");
449              }
450            break;
451          case YES_NO_CANCEL_OPTION:
452            this.optionType = optionType;
453            switch (selectedOption)
454              {
455              case YES:
456              case NO:
457              case CANCEL: this.selection = selectedOption; break;
458              default: throw new IllegalArgumentException("invalid option");
459              }
460            break;
461          case OK_CANCEL_OPTION:
462            this.optionType = optionType;
463            switch (selectedOption)
464              {
465              case OK:
466              case CANCEL: this.selection = selectedOption; break;
467              default: throw new IllegalArgumentException("invalid option");
468              }
469            break;
470          default:
471            throw new IllegalArgumentException("illegal option type");
472          }
473      }
474    
475      private void setOptions(String[] options, int selectedOption)
476        throws IllegalArgumentException
477      {
478        if ((selectedOption < 0) || (selectedOption > options.length - 1))
479          {
480            throw new IllegalArgumentException("invalid selection");
481          }
482        if ((options == null) || (options.length == 0))
483          {
484            throw new IllegalArgumentException("options is null or empty");
485          }
486        for (int i = 0; i < options.length; i++)
487          {
488            if ((options[i] == null) || (options[i].length() == 0))
489              {
490                throw new IllegalArgumentException("options[" + i + "] is null or empty");
491              }
492          }
493        this.options = options;
494        this.selection = selectedOption;
495      }
496    
497      private void setPrompt(String prompt) throws IllegalArgumentException
498      {
499        if ((prompt == null) || (prompt.length() == 0))
500          {
501            throw new IllegalArgumentException("prompt is null or empty");
502          }
503        this.prompt = prompt;
504      }
505    }