KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > schlichtherle > key > PromptingKeyManager


1 /*
2  * Copyright 2006 Schlichtherle IT Services
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
17 package de.schlichtherle.key;
18
19 import java.lang.reflect.UndeclaredThrowableException JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.Map JavaDoc;
23
24 /**
25  * An abstract {@link KeyManager} which prompts the user for a key if required.
26  * <p>
27  * This class maintains a map of user interface classes for the
28  * <code>PromptingKeyProvider</code> class and each of its subclasses which
29  * require an individual user interface.
30  * The particular user interface classes are determined by a subclass of this
31  * key manager. This enables the subclass to determine which user interface
32  * technology should actually be used to prompt the user for a key.
33  * For example, the implementation in the class
34  * {@link de.schlichtherle.key.passwd.swing.PromptingKeyManager} uses Swing
35  * to prompt the user for either a password or a key file.
36  * <p>
37  * Subclasses must use the method {@link #mapPromptingKeyProviderUIType} to
38  * register a user interface class for a particular user interface class
39  * identifier (the value returned by {@link PromptingKeyProvider#getUIClassID}).
40  * This is best done in the constructor of the subclass.
41  * <p>
42  * Note that class loading and instantiation may happen in a JVM shutdown hook,
43  * so class initializers and constructors must behave accordingly.
44  * In particular, it's not permitted to construct or use a Swing GUI there.
45  * <p>
46  * This class is thread safe.
47  *
48  * @author Christian Schlichtherle
49  * @version @version@
50  * @since TrueZIP 6.0
51  */

52 public abstract class PromptingKeyManager extends KeyManager {
53
54     private static volatile boolean prompting = true;
55
56     private final Map JavaDoc providerUITypes = new HashMap JavaDoc();
57
58     /**
59      * Constructs a new <code>PromptingKeyManager</code>.
60      * This instance maps the following key provider types using
61      * {@link KeyManager#mapKeyProviderType}:
62      * <table border="2" cellpadding="4">
63      * <tr>
64      * <th>forKeyProviderType</th>
65      * <th>useKeyProviderType</th>
66      * </tr>
67      * <tr>
68      * <td>KeyProvider.class</td>
69      * <td>PromptingKeyProvider.class</td>
70      * </tr>
71      * <tr>
72      * <td>AesKeyProvider.class</td>
73      * <td>PromptingAesKeyProvider.class</td>
74      * </tr>
75      * </table>
76      */

77     public PromptingKeyManager() {
78         mapKeyProviderType(KeyProvider.class, PromptingKeyProvider.class);
79         mapKeyProviderType(AesKeyProvider.class, PromptingAesKeyProvider.class);
80     }
81
82     //
83
// Static methods:
84
//
85

86     /**
87      * Returns <code>true</code> if and only if prompting mode is enabled.
88      * This is a class property.
89      * <p>
90      * Note that subclasses might add additional behaviour to both
91      * {@link #isPrompting} and {@link #setPrompting} through the default
92      * key manager instance (see {@link #getInstance}).
93      * Regardless, an application may safely assume that
94      * <code>isPrompting()</code> reflects the actual behaviour of the API
95      * in this package although it may not reflect the parameter value of
96      * the last call to <code>setPrompting(boolean)</code>.
97      *
98      * @return Whether or not the user will be prompted for a key if required.
99      *
100      * @see #setPrompting
101      */

102     public static boolean isPrompting() {
103         KeyManager manager = getInstance();
104         return manager instanceof PromptingKeyManager
105                 && ((PromptingKeyManager) manager).isPromptingImpl();
106     }
107
108     /**
109      * Called by {@link #isPrompting} on the default key manager instance in
110      * order to implement its behaviour and allow subclasses to override it.
111      * Subclasses should call the implementation in this class when
112      * overriding this method.
113      *
114      * @see #setPromptingImpl
115      * @see #getInstance
116      *
117      * @since TrueZIP 6.1
118      */

119     protected boolean isPromptingImpl() {
120         return prompting;
121     }
122
123     /**
124      * Enables or disables prompting mode.
125      * If prompting mode is enabled, the user will be prompted for a key when
126      * a {@link PromptingKeyProvider} is first requested to provide a key
127      * for the respective resource.
128      * If prompting mode is disabled, all attempts to prompt the user will
129      * result in an {@link UnknownKeyException} until prompting mode is
130      * enabled again.
131      * <p>
132      * This is a class property.
133      * <p>
134      * Note that subclasses might add additional behaviour to both
135      * {@link #isPrompting} and {@link #setPrompting} through the default
136      * key manager instance (see {@link #getInstance}).
137      * Regardless, an application may safely assume that
138      * <code>isPrompting()</code> reflects the actual behaviour of the API
139      * in this package although it may not reflect the parameter value of
140      * the last call to <code>setPrompting(boolean)</code>.
141      *
142      * @param prompting The value of the property <code>prompting</code>.
143      *
144      * @see #isPrompting
145      */

146     public static void setPrompting(boolean prompting) {
147         KeyManager manager = getInstance();
148         if (manager instanceof PromptingKeyManager)
149                 ((PromptingKeyManager) manager).setPromptingImpl(prompting);
150     }
151
152     /**
153      * Called by {@link #isPrompting} on the default key manager instance in
154      * order to implement its behaviour and allow subclasses to override it.
155      * Subclasses should call the implementation in this class when
156      * overriding this method.
157      *
158      * @see #isPromptingImpl
159      * @see #getInstance
160      *
161      * @since TrueZIP 6.1
162      */

163     protected void setPromptingImpl(boolean prompting) {
164         PromptingKeyManager.prompting = prompting;
165     }
166
167     static void ensurePrompting()
168     throws KeyPromptingDisabledException {
169         KeyManager manager = getInstance();
170         if (manager instanceof PromptingKeyManager)
171                 ((PromptingKeyManager) manager).ensurePromptingImpl();
172     }
173
174     /**
175      * Called by some methods in the {@link PromptingKeyProvider} class in
176      * order to ensure that prompting mode is enabled.
177      * This method may be overridden by subclasses in order to throw a more
178      * detailed exception.
179      * <p>
180      * The implementation in this class is equivalent to:
181      * <pre>
182         if (!isPromptingImpl())
183             throw new KeyPromptingDisabledException();
184      * </pre>
185      *
186      * @since TrueZIP 6.1
187      */

188     protected void ensurePromptingImpl()
189     throws KeyPromptingDisabledException {
190         if (!isPromptingImpl())
191             throw new KeyPromptingDisabledException();
192     }
193
194     /**
195      * Resets all cancelled key prompts, forcing a new prompt on the next
196      * call to {@link PromptingKeyProvider#getOpenKey()} or
197      * {@link PromptingKeyProvider#getCreateKey()}.
198      * Of course, this call only affects instances of
199      * {@link PromptingKeyProvider}.
200      */

201     public static void resetCancelledPrompts() {
202         forEachKeyProvider(new KeyProviderCommand() {
203             public void run(String JavaDoc resourceID, KeyProvider provider) {
204                 if (provider instanceof PromptingKeyProvider)
205                     ((PromptingKeyProvider) provider).resetCancelledPrompt();
206             }
207         });
208     }
209
210     //
211
// Instance stuff:
212
//
213

214     /**
215      * @deprecated Use {@link #mapPromptingKeyProviderUIType(String, Class)
216      * mapPromptingKeyProviderUIType(uiClassID, uiClass)} instead.
217      */

218     protected final void register(
219             final String JavaDoc uiClassID,
220             final Class JavaDoc uiClass) {
221         mapPromptingKeyProviderUIType(uiClassID, uiClass);
222     }
223
224     /**
225      * Subclasses must use this method to register a user interface class
226      * for a particular user interface class identifier as returned by
227      * {@link PromptingKeyProvider#getUIClassID}.
228      * This is best done in the constructor of the subclass.
229      *
230      * @param uiClassID The identifier of the user interface class.
231      * @param uiClass The class of the user interface. This must have
232      *
233      * @throws NullPointerException If any of the parameters is
234      * <code>null</code>.
235      * @throws IllegalArgumentException If the runtime type of uiClass is not
236      * {@link PromptingKeyProviderUI} or a subclass or does not provide
237      * a public constructor with no parameters.
238      *
239      * @see #getKeyProvider(String, Class)
240      *
241      * @since TrueZIP 6.1
242      */

243     protected synchronized final void mapPromptingKeyProviderUIType(
244             final String JavaDoc uiClassID,
245             final Class JavaDoc uiClass) {
246         if (uiClassID == null)
247             throw new NullPointerException JavaDoc("uiClassID");
248         if (!PromptingKeyProviderUI.class.isAssignableFrom(uiClass))
249             throw new IllegalArgumentException JavaDoc(
250                     uiClass.getName() + " must be PromptingKeyProviderUI or a subclass!");
251         try {
252             uiClass.getConstructor(null);
253         } catch (NoSuchMethodException JavaDoc noPublicNullaryConstructor) {
254             final IllegalArgumentException JavaDoc iae = new IllegalArgumentException JavaDoc(
255                     uiClass.getName() + " (no public nullary constructor)");
256             iae.initCause(noPublicNullaryConstructor);
257             throw iae;
258         }
259         providerUITypes.put(uiClassID, uiClass);
260     }
261
262     /**
263      * Equivalent to {@link #getKeyProvider(String, Class)
264      * getKeyProvider(resourceID, KeyProvider.class)} - provided for
265      * convenience.
266      * Unless another key provider has already been mapped for the protected
267      * resource, the run time type of the returned instance is determined by
268      * the map of key provider types in this key manager.
269      */

270     public KeyProvider getKeyProvider(String JavaDoc resourceID)
271     throws NullPointerException JavaDoc {
272         return getKeyProvider(resourceID, KeyProvider.class);
273     }
274
275     /**
276      * Behaves like the super class implementation, but adds additional
277      * behaviour in case the resulting key provider is an instance of
278      * {@link PromptingKeyProvider}.
279      * In this case, the appropriate user interface instance is determined
280      * and installed in the key provider before it is returned.
281      *
282      * @see KeyManager#getKeyProvider(String, Class)
283      */

284     public KeyProvider getKeyProvider(
285             final String JavaDoc resourceID,
286             final Class JavaDoc keyProviderType)
287     throws NullPointerException JavaDoc, ClassCastException JavaDoc, IllegalArgumentException JavaDoc {
288         final KeyProvider provider
289                 = super.getKeyProvider(resourceID, keyProviderType);
290
291         if (provider instanceof PromptingKeyProvider) {
292             final PromptingKeyProvider pkp = (PromptingKeyProvider) provider;
293             pkp.setUI(getUI(pkp.getUIClassID()));
294         }
295
296         return provider;
297     }
298
299     private synchronized PromptingKeyProviderUI getUI(final String JavaDoc uiClassID) {
300         final Object JavaDoc value = providerUITypes.get(uiClassID);
301
302         final PromptingKeyProviderUI pkpui;
303         if (value instanceof Class JavaDoc) {
304             try {
305                 pkpui = (PromptingKeyProviderUI) ((Class JavaDoc) value).newInstance();
306             } catch (InstantiationException JavaDoc failure) {
307                 throw new UndeclaredThrowableException JavaDoc(failure);
308             } catch (IllegalAccessException JavaDoc failure) {
309                 throw new UndeclaredThrowableException JavaDoc(failure);
310             }
311             providerUITypes.put(uiClassID, pkpui);
312         } else if (value != null) {
313             pkpui = (PromptingKeyProviderUI) value;
314         } else { // value == null
315
throw new IllegalArgumentException JavaDoc(uiClassID +
316                     " (unknown user interface for PromptingKeyProvider)");
317         }
318
319         return pkpui;
320     }
321 }
322
Popular Tags