KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > security > Permissions


1 /*
2  * @(#)Permissions.java 1.58 04/05/05
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7  
8 package java.security;
9
10 import java.util.Enumeration JavaDoc;
11 import java.util.Hashtable JavaDoc;
12 import java.util.NoSuchElementException JavaDoc;
13 import java.util.Map JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.ArrayList JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.Collections JavaDoc;
19 import java.io.Serializable JavaDoc;
20 import java.io.ObjectStreamField JavaDoc;
21 import java.io.ObjectOutputStream JavaDoc;
22 import java.io.ObjectInputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24
25
26 /**
27  * This class represents a heterogeneous collection of Permissions. That is,
28  * it contains different types of Permission objects, organized into
29  * PermissionCollections. For example, if any
30  * <code>java.io.FilePermission</code> objects are added to an instance of
31  * this class, they are all stored in a single
32  * PermissionCollection. It is the PermissionCollection returned by a call to
33  * the <code>newPermissionCollection</code> method in the FilePermission class.
34  * Similarly, any <code>java.lang.RuntimePermission</code> objects are
35  * stored in the PermissionCollection returned by a call to the
36  * <code>newPermissionCollection</code> method in the
37  * RuntimePermission class. Thus, this class represents a collection of
38  * PermissionCollections.
39  *
40  * <p>When the <code>add</code> method is called to add a Permission, the
41  * Permission is stored in the appropriate PermissionCollection. If no such
42  * collection exists yet, the Permission object's class is determined and the
43  * <code>newPermissionCollection</code> method is called on that class to create
44  * the PermissionCollection and add it to the Permissions object. If
45  * <code>newPermissionCollection</code> returns null, then a default
46  * PermissionCollection that uses a hashtable will be created and used. Each
47  * hashtable entry stores a Permission object as both the key and the value.
48  *
49  * <p> Enumerations returned via the <code>elements</code> method are
50  * not <em>fail-fast</em>. Modifications to a collection should not be
51  * performed while enumerating over that collection.
52  *
53  * @see Permission
54  * @see PermissionCollection
55  * @see AllPermission
56  *
57  * @version 1.58, 04/05/05
58  *
59  * @author Marianne Mueller
60  * @author Roland Schemers
61  *
62  * @serial exclude
63  */

64
65 public final class Permissions extends PermissionCollection JavaDoc
66 implements Serializable JavaDoc
67 {
68     /**
69      * Key is permissions Class, value is PermissionCollection for that class.
70      * Not serialized; see serialization section at end of class.
71      */

72     private transient Map JavaDoc<Class JavaDoc<?>, PermissionCollection JavaDoc> permsMap;
73
74     // optimization. keep track of whether unresolved permissions need to be
75
// checked
76
private transient boolean hasUnresolved = false;
77
78     // optimization. keep track of the AllPermission collection
79
private PermissionCollection JavaDoc allPermission;
80
81     /**
82      * Creates a new Permissions object containing no PermissionCollections.
83      */

84     public Permissions() {
85     permsMap = new HashMap JavaDoc(11);
86     allPermission = null;
87     }
88
89     /**
90      * Adds a permission object to the PermissionCollection for the class the
91      * permission belongs to. For example, if <i>permission</i> is a
92      * FilePermission, it is added to the FilePermissionCollection stored
93      * in this Permissions object.
94      *
95      * This method creates
96      * a new PermissionCollection object (and adds the permission to it)
97      * if an appropriate collection does not yet exist. <p>
98      *
99      * @param permission the Permission object to add.
100      *
101      * @exception SecurityException if this Permissions object is
102      * marked as readonly.
103      *
104      * @see PermissionCollection#isReadOnly()
105      */

106
107     public void add(Permission JavaDoc permission) {
108     if (isReadOnly())
109         throw new SecurityException JavaDoc(
110               "attempt to add a Permission to a readonly Permissions object");
111
112     PermissionCollection JavaDoc pc;
113
114     synchronized (this) {
115         pc = getPermissionCollection(permission, true);
116         pc.add(permission);
117     }
118
119     // No sync; staleness -> optimizations delayed, which is OK
120
if (permission instanceof AllPermission JavaDoc) {
121         allPermission = pc;
122     }
123     if (permission instanceof UnresolvedPermission JavaDoc) {
124         hasUnresolved = true;
125     }
126     }
127
128     /**
129      * Checks to see if this object's PermissionCollection for permissions of
130      * the specified permission's type implies the permissions
131      * expressed in the <i>permission</i> object. Returns true if the
132      * combination of permissions in the appropriate PermissionCollection
133      * (e.g., a FilePermissionCollection for a FilePermission) together
134      * imply the specified permission.
135      *
136      * <p>For example, suppose there is a FilePermissionCollection in this
137      * Permissions object, and it contains one FilePermission that specifies
138      * "read" access for all files in all subdirectories of the "/tmp"
139      * directory, and another FilePermission that specifies "write" access
140      * for all files in the "/tmp/scratch/foo" directory.
141      * Then if the <code>implies</code> method
142      * is called with a permission specifying both "read" and "write" access
143      * to files in the "/tmp/scratch/foo" directory, <code>true</code> is
144      * returned.
145      *
146      * <p>Additionally, if this PermissionCollection contains the
147      * AllPermission, this method will always return true.
148      * <p>
149      * @param permission the Permission object to check.
150      *
151      * @return true if "permission" is implied by the permissions in the
152      * PermissionCollection it
153      * belongs to, false if not.
154      */

155
156     public boolean implies(Permission JavaDoc permission) {
157     // No sync; staleness -> skip optimization, which is OK
158
if (allPermission != null) {
159         return true; // AllPermission has already been added
160
} else {
161         synchronized (this) {
162         PermissionCollection JavaDoc pc = getPermissionCollection(permission,
163             false);
164         if (pc != null) {
165             return pc.implies(permission);
166         } else {
167             // none found
168
return false;
169         }
170         }
171     }
172     }
173
174     /**
175      * Returns an enumeration of all the Permission objects in all the
176      * PermissionCollections in this Permissions object.
177      *
178      * @return an enumeration of all the Permissions.
179      */

180
181     public Enumeration JavaDoc<Permission JavaDoc> elements() {
182     // go through each Permissions in the hash table
183
// and call their elements() function.
184

185     synchronized (this) {
186         return new PermissionsEnumerator(permsMap.values().iterator());
187     }
188     }
189
190     /**
191      * Gets the PermissionCollection in this Permissions object for
192      * permissions whose type is the same as that of <i>p</i>.
193      * For example, if <i>p</i> is a FilePermission,
194      * the FilePermissionCollection
195      * stored in this Permissions object will be returned.
196      *
197      * If createEmpty is true,
198      * this method creates a new PermissionCollection object for the specified
199      * type of permission objects if one does not yet exist.
200      * To do so, it first calls the <code>newPermissionCollection</code> method
201      * on <i>p</i>. Subclasses of class Permission
202      * override that method if they need to store their permissions in a
203      * particular PermissionCollection object in order to provide the
204      * correct semantics when the <code>PermissionCollection.implies</code>
205      * method is called.
206      * If the call returns a PermissionCollection, that collection is stored
207      * in this Permissions object. If the call returns null and createEmpty
208      * is true, then
209      * this method instantiates and stores a default PermissionCollection
210      * that uses a hashtable to store its permission objects.
211      *
212      * createEmpty is ignored when creating empty PermissionCollection
213      * for unresolved permissions because of the overhead of determining the
214      * PermissionCollection to use.
215      *
216      * createEmpty should be set to false when this method is invoked from
217      * implies() because it incurs the additional overhead of creating and
218      * adding an empty PermissionCollection that will just return false.
219      * It should be set to true when invoked from add().
220      */

221     private PermissionCollection JavaDoc getPermissionCollection(Permission JavaDoc p,
222     boolean createEmpty) {
223     Class JavaDoc c = p.getClass();
224
225     PermissionCollection JavaDoc pc = (PermissionCollection JavaDoc) permsMap.get(c);
226
227     if (!hasUnresolved && !createEmpty) {
228         return pc;
229     } else if (pc == null) {
230
231         // Check for unresolved permissions
232
pc = (hasUnresolved ? getUnresolvedPermissions(p) : null);
233
234         // if still null, create a new collection
235
if (pc == null && createEmpty) {
236
237         pc = p.newPermissionCollection();
238             
239         // still no PermissionCollection?
240
// We'll give them a PermissionsHash.
241
if (pc == null)
242             pc = new PermissionsHash();
243         }
244         
245         if (pc != null) {
246         permsMap.put(c, pc);
247         }
248     }
249     return pc;
250     }
251
252     /**
253      * Resolves any unresolved permissions of type p.
254      *
255      * @param p the type of unresolved permission to resolve
256      *
257      * @return PermissionCollection containing the unresolved permissions,
258      * or null if there were no unresolved permissions of type p.
259      *
260      */

261     private PermissionCollection JavaDoc getUnresolvedPermissions(Permission JavaDoc p)
262     {
263     // Called from within synchronized method so permsMap doesn't need lock
264

265     UnresolvedPermissionCollection JavaDoc uc =
266     (UnresolvedPermissionCollection JavaDoc) permsMap.get(UnresolvedPermission JavaDoc.class);
267
268     // we have no unresolved permissions if uc is null
269
if (uc == null)
270         return null;
271
272     List JavaDoc unresolvedPerms = uc.getUnresolvedPermissions(p);
273     
274     // we have no unresolved permissions of this type if unresolvedPerms is null
275
if (unresolvedPerms == null)
276         return null;
277
278     java.security.cert.Certificate JavaDoc certs[] = null;
279
280     Object JavaDoc signers[] = p.getClass().getSigners();
281
282     int n = 0;
283     if (signers != null) {
284         for (int j=0; j < signers.length; j++) {
285         if (signers[j] instanceof java.security.cert.Certificate JavaDoc) {
286             n++;
287         }
288         }
289         certs = new java.security.cert.Certificate JavaDoc[n];
290         n = 0;
291         for (int j=0; j < signers.length; j++) {
292         if (signers[j] instanceof java.security.cert.Certificate JavaDoc) {
293             certs[n++] = (java.security.cert.Certificate JavaDoc)signers[j];
294         }
295         }
296     }
297
298     PermissionCollection JavaDoc pc = null;
299     synchronized (unresolvedPerms) {
300         int len = unresolvedPerms.size();
301         for (int i = 0; i < len; i++) {
302         UnresolvedPermission JavaDoc up =
303             (UnresolvedPermission JavaDoc)unresolvedPerms.get(i);
304         Permission JavaDoc perm = up.resolve(p, certs);
305         if (perm != null) {
306             if (pc == null) {
307             pc = p.newPermissionCollection();
308             if (pc == null)
309                 pc = new PermissionsHash();
310             }
311             pc.add(perm);
312         }
313         }
314     }
315     return pc;
316     }
317
318     private static final long serialVersionUID = 4858622370623524688L;
319
320     // Need to maintain serialization interoperability with earlier releases,
321
// which had the serializable field:
322
// private Hashtable perms;
323

324     /**
325      * @serialField perms java.util.Hashtable
326      * A table of the Permission classes and PermissionCollections.
327      * @serialField allPermission java.security.PermissionCollection
328      */

329     private static final ObjectStreamField JavaDoc[] serialPersistentFields = {
330         new ObjectStreamField JavaDoc("perms", Hashtable JavaDoc.class),
331     new ObjectStreamField JavaDoc("allPermission", PermissionCollection JavaDoc.class),
332     };
333
334     /**
335      * @serialData Default fields.
336      */

337     /*
338      * Writes the contents of the permsMap field out as a Hashtable for
339      * serialization compatibility with earlier releases. allPermission
340      * unchanged.
341      */

342     private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
343     // Don't call out.defaultWriteObject()
344

345     // Copy perms into a Hashtable
346
Hashtable JavaDoc perms = new Hashtable JavaDoc(permsMap.size()*2); // no sync; estimate
347
synchronized (this) {
348         perms.putAll(permsMap);
349     }
350
351     // Write out serializable fields
352
ObjectOutputStream.PutField JavaDoc pfields = out.putFields();
353
354     pfields.put("allPermission", allPermission); // no sync; staleness OK
355
pfields.put("perms", perms);
356         out.writeFields();
357     }
358
359     /*
360      * Reads in a Hashtable of Class/PermissionCollections and saves them in the
361      * permsMap field. Reads in allPermission.
362      */

363     private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc,
364     ClassNotFoundException JavaDoc {
365     // Don't call defaultReadObject()
366

367     // Read in serialized fields
368
ObjectInputStream.GetField JavaDoc gfields = in.readFields();
369
370     // Get allPermission
371
allPermission = (PermissionCollection JavaDoc) gfields.get("allPermission", null);
372
373     // Get permissions
374
Hashtable JavaDoc perms = (Hashtable JavaDoc)gfields.get("perms", null);
375     permsMap = new HashMap JavaDoc(perms.size()*2);
376     permsMap.putAll(perms);
377
378     // Set hasUnresolved
379
UnresolvedPermissionCollection JavaDoc uc =
380     (UnresolvedPermissionCollection JavaDoc) permsMap.get(UnresolvedPermission JavaDoc.class);
381     hasUnresolved = (uc != null && uc.elements().hasMoreElements());
382     }
383 }
384
385 final class PermissionsEnumerator implements Enumeration JavaDoc<Permission JavaDoc> {
386
387     // all the perms
388
private Iterator JavaDoc<PermissionCollection JavaDoc> perms;
389     // the current set
390
private Enumeration JavaDoc<Permission JavaDoc> permset;
391    
392     PermissionsEnumerator(Iterator JavaDoc<PermissionCollection JavaDoc> e) {
393     perms = e;
394     permset = getNextEnumWithMore();
395     }
396
397     // No need to synchronize; caller should sync on object as required
398
public boolean hasMoreElements() {
399     // if we enter with permissionimpl null, we know
400
// there are no more left.
401

402     if (permset == null)
403         return false;
404
405     // try to see if there are any left in the current one
406

407     if (permset.hasMoreElements())
408         return true;
409
410     // get the next one that has something in it...
411
permset = getNextEnumWithMore();
412
413     // if it is null, we are done!
414
return (permset != null);
415     }
416
417     // No need to synchronize; caller should sync on object as required
418
public Permission JavaDoc nextElement() {
419
420     // hasMoreElements will update permset to the next permset
421
// with something in it...
422

423     if (hasMoreElements()) {
424         return permset.nextElement();
425     } else {
426         throw new NoSuchElementException JavaDoc("PermissionsEnumerator");
427     }
428
429     }
430
431     private Enumeration JavaDoc<Permission JavaDoc> getNextEnumWithMore() {
432     while (perms.hasNext()) {
433         PermissionCollection JavaDoc pc = (PermissionCollection JavaDoc)perms.next();
434         Enumeration JavaDoc<Permission JavaDoc> next =pc.elements();
435         if (next.hasMoreElements())
436         return next;
437     }
438     return null;
439
440     }
441 }
442
443 /**
444  * A PermissionsHash stores a homogeneous set of permissions in a hashtable.
445  *
446  * @see Permission
447  * @see Permissions
448  *
449  * @version 1.58, 05/05/04
450  *
451  * @author Roland Schemers
452  *
453  * @serial include
454  */

455
456 final class PermissionsHash extends PermissionCollection JavaDoc
457 implements Serializable JavaDoc
458 {
459     /**
460      * Key and value are (same) permissions objects.
461      * Not serialized; see serialization section at end of class.
462      */

463     private transient Map JavaDoc permsMap;
464
465     /**
466      * Create an empty PermissionsHash object.
467      */

468
469     PermissionsHash() {
470     permsMap = new HashMap JavaDoc(11);
471     }
472
473     /**
474      * Adds a permission to the PermissionsHash.
475      *
476      * @param permission the Permission object to add.
477      */

478
479     public void add(Permission JavaDoc permission) {
480     synchronized (this) {
481         permsMap.put(permission, permission);
482     }
483     }
484
485     /**
486      * Check and see if this set of permissions implies the permissions
487      * expressed in "permission".
488      *
489      * @param permission the Permission object to compare
490      *
491      * @return true if "permission" is a proper subset of a permission in
492      * the set, false if not.
493      */

494
495     public boolean implies(Permission JavaDoc permission) {
496     // attempt a fast lookup and implies. If that fails
497
// then enumerate through all the permissions.
498
synchronized (this) {
499         Permission JavaDoc p = (Permission JavaDoc) permsMap.get(permission);
500
501         // If permission is found, then p.equals(permission)
502
if (p == null) {
503         Iterator JavaDoc enum_ = permsMap.values().iterator();
504         while (enum_.hasNext()) {
505             p = (Permission JavaDoc) enum_.next();
506             if (p.implies(permission))
507             return true;
508         }
509         return false;
510         } else {
511         return true;
512         }
513     }
514     }
515
516     /**
517      * Returns an enumeration of all the Permission objects in the container.
518      *
519      * @return an enumeration of all the Permissions.
520      */

521
522     public Enumeration JavaDoc<Permission JavaDoc> elements() {
523         // Convert Iterator of Map values into an Enumeration
524
synchronized (this) {
525         return Collections.enumeration(permsMap.values());
526     }
527     }
528
529     private static final long serialVersionUID = -8491988220802933440L;
530     // Need to maintain serialization interoperability with earlier releases,
531
// which had the serializable field:
532
// private Hashtable perms;
533
/**
534      * @serialField perms java.util.Hashtable
535      * A table of the Permissions (both key and value are same).
536      */

537     private static final ObjectStreamField JavaDoc[] serialPersistentFields = {
538         new ObjectStreamField JavaDoc("perms", Hashtable JavaDoc.class),
539     };
540
541     /**
542      * @serialData Default fields.
543      */

544     /*
545      * Writes the contents of the permsMap field out as a Hashtable for
546      * serialization compatibility with earlier releases.
547      */

548     private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
549     // Don't call out.defaultWriteObject()
550

551     // Copy perms into a Hashtable
552
Hashtable JavaDoc perms = new Hashtable JavaDoc(permsMap.size()*2);
553     synchronized (this) {
554         perms.putAll(permsMap);
555     }
556
557     // Write out serializable fields
558
ObjectOutputStream.PutField JavaDoc pfields = out.putFields();
559         pfields.put("perms", perms);
560         out.writeFields();
561     }
562
563     /*
564      * Reads in a Hashtable of Permission/Permission and saves them in the
565      * permsMap field.
566      */

567     private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc,
568     ClassNotFoundException JavaDoc {
569     // Don't call defaultReadObject()
570

571     // Read in serialized fields
572
ObjectInputStream.GetField JavaDoc gfields = in.readFields();
573
574     // Get permissions
575
Hashtable JavaDoc perms = (Hashtable JavaDoc)gfields.get("perms", null);
576     permsMap = new HashMap JavaDoc(perms.size()*2);
577     permsMap.putAll(perms);
578     }
579 }
580
Popular Tags