1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.security; 19 20import java.io.IOException; 21import java.io.InvalidObjectException; 22import java.io.ObjectInputStream; 23import java.io.ObjectOutputStream; 24import java.io.ObjectStreamField; 25import java.io.Serializable; 26import java.util.Enumeration; 27import java.util.HashMap; 28import java.util.Hashtable; 29import java.util.Iterator; 30import java.util.Map; 31import java.util.NoSuchElementException; 32 33import org.apache.harmony.security.internal.nls.Messages; 34 35/** 36 * {@code Permissions} represents a {@code PermissionCollection} where the 37 * contained permissions can be of different types. The permissions are 38 * organized in their appropriate {@code PermissionCollection} obtained by 39 * {@link Permission#newPermissionCollection()}. For permissions which do not 40 * provide a dedicated {@code PermissionCollection}, a default permission 41 * collection, based on a hash table, will be used. 42 */ 43public final class Permissions extends PermissionCollection implements 44 Serializable { 45 46 private static final long serialVersionUID = 4858622370623524688L; 47 48 private static final ObjectStreamField[] serialPersistentFields = { 49 new ObjectStreamField("perms", Hashtable.class), //$NON-NLS-1$ 50 new ObjectStreamField("allPermission", PermissionCollection.class), }; //$NON-NLS-1$ 51 52 // Hash to store PermissionCollection's 53 private transient Map klasses = new HashMap(); 54 55 private boolean allEnabled; // = false; 56 57 /** 58 * Adds the given {@code Permission} to this heterogeneous {@code 59 * PermissionCollection}. The {@code permission} is stored in its 60 * appropriate {@code PermissionCollection}. 61 * 62 * @param permission 63 * the {@code Permission} to be added. 64 * @throws SecurityException 65 * if this collection's {@link #isReadOnly()} method returns 66 * {@code true}. 67 * @throws NullPointerException 68 * if {@code permission} is {@code null}. 69 */ 70 public void add(Permission permission) { 71 if (isReadOnly()) { 72 throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$ 73 } 74 75 if (permission == null) { 76 throw new NullPointerException(Messages.getString("security.20")); //$NON-NLS-1$ 77 } 78 79 Class klass = permission.getClass(); 80 PermissionCollection klassMates = (PermissionCollection)klasses 81 .get(klass); 82 83 if (klassMates == null) { 84 synchronized (klasses) { 85 klassMates = (PermissionCollection)klasses.get(klass); 86 if (klassMates == null) { 87 88 klassMates = permission.newPermissionCollection(); 89 if (klassMates == null) { 90 klassMates = new PermissionsHash(); 91 } 92 klasses.put(klass, klassMates); 93 } 94 } 95 } 96 klassMates.add(permission); 97 98 if (klass == AllPermission.class) { 99 allEnabled = true; 100 } 101 } 102 103 public Enumeration<Permission> elements() { 104 return new MetaEnumeration(klasses.values().iterator()); 105 } 106 107 /** 108 * An auxiliary implementation for enumerating individual permissions from a 109 * collection of PermissionCollections. 110 * 111 */ 112 final static class MetaEnumeration implements Enumeration { 113 114 private Iterator pcIter; 115 116 private Enumeration current; 117 118 /** 119 * Initiates this enumeration. 120 * 121 * @param outer an iterator over external collection of 122 * PermissionCollections 123 */ 124 public MetaEnumeration(Iterator outer) { 125 pcIter = outer; 126 current = getNextEnumeration(); 127 } 128 129 private Enumeration getNextEnumeration() { 130 while (pcIter.hasNext()) { 131 Enumeration en = ((PermissionCollection)pcIter.next()) 132 .elements(); 133 if (en.hasMoreElements()) { 134 return en; 135 } 136 } 137 return null; 138 } 139 140 /** 141 * Indicates if there are more elements to enumerate. 142 */ 143 public boolean hasMoreElements() { 144 return current != null /* && current.hasMoreElements() */; 145 } 146 147 /** 148 * Returns next element. 149 */ 150 public Object nextElement() { 151 if (current != null) { 152 //assert current.hasMoreElements(); 153 Object next = current.nextElement(); 154 if (!current.hasMoreElements()) { 155 current = getNextEnumeration(); 156 } 157 158 return next; 159 } 160 throw new NoSuchElementException(Messages.getString("security.17")); //$NON-NLS-1$ 161 } 162 } 163 164 public boolean implies(Permission permission) { 165 if (permission == null) { 166 // RI compatible 167 throw new NullPointerException(Messages.getString("security.21")); //$NON-NLS-1$ 168 } 169 if (allEnabled) { 170 return true; 171 } 172 Class klass = permission.getClass(); 173 PermissionCollection klassMates = null; 174 175 UnresolvedPermissionCollection billets = (UnresolvedPermissionCollection)klasses 176 .get(UnresolvedPermission.class); 177 if (billets != null && billets.hasUnresolved(permission)) { 178 // try to fill up klassMates with freshly resolved permissions 179 synchronized (klasses) { 180 klassMates = (PermissionCollection)klasses.get(klass); 181 try { 182 klassMates = billets.resolveCollection(permission, 183 klassMates); 184 } catch (Exception ignore) { 185 //TODO log warning 186 ignore.printStackTrace(); 187 } 188 189 if (klassMates != null) { 190 //maybe klassMates were just created 191 // so put them into common map 192 klasses.put(klass, klassMates); 193 // very uncommon case, but not improbable one 194 if (klass == AllPermission.class) { 195 allEnabled = true; 196 } 197 } 198 } 199 } else { 200 klassMates = (PermissionCollection)klasses.get(klass); 201 } 202 203 if (klassMates != null) { 204 return klassMates.implies(permission); 205 } 206 return false; 207 } 208 209 /** 210 * Reads the object from stream and checks for consistency. 211 */ 212 private void readObject(java.io.ObjectInputStream in) throws IOException, 213 ClassNotFoundException { 214 ObjectInputStream.GetField fields = in.readFields(); 215 Map perms = (Map)fields.get("perms", null); //$NON-NLS-1$ 216 klasses = new HashMap(); 217 synchronized (klasses) { 218 for (Iterator iter = perms.entrySet().iterator(); iter.hasNext();) { 219 Map.Entry entry = (Map.Entry) iter.next(); 220 Class key = (Class) entry.getKey(); 221 PermissionCollection pc = (PermissionCollection) entry.getValue(); 222 if (key != pc.elements().nextElement().getClass()) { 223 throw new InvalidObjectException(Messages.getString("security.22")); //$NON-NLS-1$ 224 } 225 klasses.put(key, pc); 226 } 227 } 228 allEnabled = fields.get("allPermission", null) != null; //$NON-NLS-1$ 229 if (allEnabled && !klasses.containsKey(AllPermission.class)) { 230 throw new InvalidObjectException(Messages.getString("security.23")); //$NON-NLS-1$ 231 } 232 } 233 234 /** 235 * Outputs fields via default mechanism. 236 */ 237 private void writeObject(java.io.ObjectOutputStream out) throws IOException { 238 ObjectOutputStream.PutField fields = out.putFields(); 239 fields.put("perms", new Hashtable(klasses)); //$NON-NLS-1$ 240 fields.put("allPermission", allEnabled ? klasses //$NON-NLS-1$ 241 .get(AllPermission.class) : null); 242 out.writeFields(); 243 } 244} 245