| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.security; |
| |
| import java.io.IOException; |
| import java.io.InvalidObjectException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.ObjectStreamField; |
| import java.io.Serializable; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.NoSuchElementException; |
| |
| /** |
| * {@code Permissions} represents a {@code PermissionCollection} where the |
| * contained permissions can be of different types. The permissions are |
| * organized in their appropriate {@code PermissionCollection} obtained by |
| * {@link Permission#newPermissionCollection()}. For permissions which do not |
| * provide a dedicated {@code PermissionCollection}, a default permission |
| * collection, based on a hash table, will be used. |
| */ |
| public final class Permissions extends PermissionCollection implements |
| Serializable { |
| |
| private static final long serialVersionUID = 4858622370623524688L; |
| |
| private static final ObjectStreamField[] serialPersistentFields = { |
| new ObjectStreamField("perms", Hashtable.class), |
| new ObjectStreamField("allPermission", PermissionCollection.class), }; |
| |
| // Hash to store PermissionCollection's |
| private transient Map klasses = new HashMap(); |
| |
| private boolean allEnabled; // = false; |
| |
| /** |
| * Adds the given {@code Permission} to this heterogeneous {@code |
| * PermissionCollection}. The {@code permission} is stored in its |
| * appropriate {@code PermissionCollection}. |
| * |
| * @param permission |
| * the {@code Permission} to be added. |
| * @throws SecurityException |
| * if this collection's {@link #isReadOnly()} method returns |
| * {@code true}. |
| * @throws NullPointerException |
| * if {@code permission} is {@code null}. |
| */ |
| public void add(Permission permission) { |
| if (isReadOnly()) { |
| throw new SecurityException("collection is read-only"); |
| } |
| |
| if (permission == null) { |
| throw new NullPointerException("permission == null"); |
| } |
| |
| Class klass = permission.getClass(); |
| PermissionCollection klassMates = (PermissionCollection)klasses |
| .get(klass); |
| |
| if (klassMates == null) { |
| synchronized (klasses) { |
| klassMates = (PermissionCollection)klasses.get(klass); |
| if (klassMates == null) { |
| |
| klassMates = permission.newPermissionCollection(); |
| if (klassMates == null) { |
| klassMates = new PermissionsHash(); |
| } |
| klasses.put(klass, klassMates); |
| } |
| } |
| } |
| klassMates.add(permission); |
| |
| if (klass == AllPermission.class) { |
| allEnabled = true; |
| } |
| } |
| |
| public Enumeration<Permission> elements() { |
| return new MetaEnumeration(klasses.values().iterator()); |
| } |
| |
| /** |
| * An auxiliary implementation for enumerating individual permissions from a |
| * collection of PermissionCollections. |
| * |
| */ |
| final static class MetaEnumeration implements Enumeration { |
| |
| private Iterator pcIter; |
| |
| private Enumeration current; |
| |
| /** |
| * Initiates this enumeration. |
| * |
| * @param outer an iterator over external collection of |
| * PermissionCollections |
| */ |
| public MetaEnumeration(Iterator outer) { |
| pcIter = outer; |
| current = getNextEnumeration(); |
| } |
| |
| private Enumeration getNextEnumeration() { |
| while (pcIter.hasNext()) { |
| Enumeration en = ((PermissionCollection)pcIter.next()) |
| .elements(); |
| if (en.hasMoreElements()) { |
| return en; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Indicates if there are more elements to enumerate. |
| */ |
| public boolean hasMoreElements() { |
| return current != null /* && current.hasMoreElements() */; |
| } |
| |
| /** |
| * Returns next element. |
| */ |
| public Object nextElement() { |
| if (current != null) { |
| //assert current.hasMoreElements(); |
| Object next = current.nextElement(); |
| if (!current.hasMoreElements()) { |
| current = getNextEnumeration(); |
| } |
| |
| return next; |
| } |
| throw new NoSuchElementException(); |
| } |
| } |
| |
| public boolean implies(Permission permission) { |
| if (permission == null) { |
| // RI compatible |
| throw new NullPointerException("permission == null"); |
| } |
| if (allEnabled) { |
| return true; |
| } |
| Class klass = permission.getClass(); |
| PermissionCollection klassMates = null; |
| |
| UnresolvedPermissionCollection billets = (UnresolvedPermissionCollection)klasses |
| .get(UnresolvedPermission.class); |
| if (billets != null && billets.hasUnresolved(permission)) { |
| // try to fill up klassMates with freshly resolved permissions |
| synchronized (klasses) { |
| klassMates = (PermissionCollection)klasses.get(klass); |
| try { |
| klassMates = billets.resolveCollection(permission, |
| klassMates); |
| } catch (Exception ignore) { |
| //TODO log warning |
| ignore.printStackTrace(); |
| } |
| |
| if (klassMates != null) { |
| //maybe klassMates were just created |
| // so put them into common map |
| klasses.put(klass, klassMates); |
| // very uncommon case, but not improbable one |
| if (klass == AllPermission.class) { |
| allEnabled = true; |
| } |
| } |
| } |
| } else { |
| klassMates = (PermissionCollection)klasses.get(klass); |
| } |
| |
| if (klassMates != null) { |
| return klassMates.implies(permission); |
| } |
| return false; |
| } |
| |
| /** |
| * Reads the object from stream and checks for consistency. |
| */ |
| private void readObject(java.io.ObjectInputStream in) throws IOException, |
| ClassNotFoundException { |
| ObjectInputStream.GetField fields = in.readFields(); |
| Map perms = (Map)fields.get("perms", null); |
| klasses = new HashMap(); |
| synchronized (klasses) { |
| for (Iterator iter = perms.entrySet().iterator(); iter.hasNext();) { |
| Map.Entry entry = (Map.Entry) iter.next(); |
| Class key = (Class) entry.getKey(); |
| PermissionCollection pc = (PermissionCollection) entry.getValue(); |
| if (key != pc.elements().nextElement().getClass()) { |
| throw new InvalidObjectException("collection is corrupted"); |
| } |
| klasses.put(key, pc); |
| } |
| } |
| allEnabled = fields.get("allPermission", null) != null; |
| if (allEnabled && !klasses.containsKey(AllPermission.class)) { |
| throw new InvalidObjectException("all-enabled flag is corrupted"); |
| } |
| } |
| |
| /** |
| * Outputs fields via default mechanism. |
| */ |
| private void writeObject(java.io.ObjectOutputStream out) throws IOException { |
| ObjectOutputStream.PutField fields = out.putFields(); |
| fields.put("perms", new Hashtable(klasses)); |
| fields.put("allPermission", allEnabled ? klasses |
| .get(AllPermission.class) : null); |
| out.writeFields(); |
| } |
| } |