| /* |
| * 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.util.Collections; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.apache.harmony.security.internal.nls.Messages; |
| |
| /** |
| * Specific {@code PermissionCollection} for storing {@code BasicPermissions} of |
| * arbitrary type. |
| * |
| * @see BasicPermission |
| * @see PermissionCollection |
| */ |
| final class BasicPermissionCollection extends PermissionCollection { |
| |
| private static final long serialVersionUID = 739301742472979399L; |
| |
| private static final ObjectStreamField[] serialPersistentFields = { |
| new ObjectStreamField("all_allowed", Boolean.TYPE), //$NON-NLS-1$ |
| new ObjectStreamField("permissions", Hashtable.class), //$NON-NLS-1$ |
| new ObjectStreamField("permClass", Class.class), }; //$NON-NLS-1$ |
| |
| //should be final, but because of writeObject() cannot be |
| private transient Map<String, Permission> items = new HashMap<String, Permission>(); |
| |
| // true if this Collection contains a BasicPermission with '*' as its permission name |
| private transient boolean allEnabled; // = false; |
| |
| private Class<? extends Permission> permClass; |
| |
| /** |
| * Adds a permission to the collection. The first added permission must be a |
| * subclass of BasicPermission, next permissions must be of the same class |
| * as the first one. |
| * |
| * @see java.security.PermissionCollection#add(java.security.Permission) |
| */ |
| @Override |
| public void add(Permission permission) { |
| if (isReadOnly()) { |
| throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$ |
| } |
| if (permission == null) { |
| throw new IllegalArgumentException(Messages.getString("security.20")); //$NON-NLS-1$ |
| } |
| |
| Class<? extends Permission> inClass = permission.getClass(); |
| if (permClass != null) { |
| if (permClass != inClass) { |
| throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$ |
| permission)); |
| } |
| } else if( !(permission instanceof BasicPermission)) { |
| throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$ |
| permission)); |
| } else { |
| // this is the first element provided that another thread did not add |
| synchronized (this) { |
| if (permClass != null && inClass != permClass) { |
| throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$ |
| permission)); |
| } |
| permClass = inClass; |
| } |
| } |
| |
| String name = permission.getName(); |
| items.put(name, permission); |
| allEnabled = allEnabled || (name.length() == 1 && '*' == name.charAt(0)); |
| } |
| |
| /** |
| * Returns enumeration of contained elements. |
| */ |
| @Override |
| public Enumeration<Permission> elements() { |
| return Collections.enumeration(items.values()); |
| } |
| |
| /** |
| * Indicates whether the argument permission is implied by the receiver. |
| * |
| * @return boolean {@code true} if the argument permission is implied by the |
| * receiver, and {@code false} if it is not. |
| * @param permission |
| * the permission to check. |
| * @see Permission |
| */ |
| @Override |
| public boolean implies(Permission permission) { |
| if (permission == null || permission.getClass() != permClass) { |
| return false; |
| } |
| if (allEnabled) { |
| return true; |
| } |
| String checkName = permission.getName(); |
| //first check direct coincidence |
| if (items.containsKey(checkName)) { |
| return true; |
| } |
| //now check if there are suitable wildcards |
| //suppose we have "a.b.c", let's check "a.b.*" and "a.*" |
| char[] name = checkName.toCharArray(); |
| //I presume that "a.b.*" does not imply "a.b." |
| //so the dot at end is ignored |
| int pos = name.length - 2; |
| for (; pos >= 0; pos--) { |
| if (name[pos] == '.') { |
| break; |
| } |
| } |
| while (pos >= 0) { |
| name[pos + 1] = '*'; |
| if (items.containsKey(new String(name, 0, pos + 2))) { |
| return true; |
| } |
| for (--pos; pos >= 0; pos--) { |
| if (name[pos] == '.') { |
| break; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Expected format is the following: |
| * <dl> |
| * <dt>boolean all_allowed |
| * <dd>This is set to true if this BasicPermissionCollection contains a |
| * {@code BasicPermission} with '*' as its permission name. |
| * <dt>Class<T> permClass |
| * <dd>The class to which all {@code BasicPermission}s in this |
| * BasicPermissionCollection belongs. |
| * <dt>Hashtable<K,V> permissions |
| * <dd>The {@code BasicPermission}s in this collection. All {@code |
| * BasicPermission}s in the collection must belong to the same class. The |
| * Hashtable is indexed by the {@code BasicPermission} name; the value of |
| * the Hashtable entry is the permission. |
| * </dl> |
| */ |
| private void writeObject(java.io.ObjectOutputStream out) throws IOException { |
| ObjectOutputStream.PutField fields = out.putFields(); |
| fields.put("all_allowed", allEnabled); //$NON-NLS-1$ |
| fields.put("permissions", new Hashtable<String, Permission>(items)); //$NON-NLS-1$ |
| fields.put("permClass", permClass); //$NON-NLS-1$ |
| out.writeFields(); |
| } |
| |
| /** |
| * Reads the object from stream and checks its consistency: all contained |
| * permissions must be of the same subclass of BasicPermission. |
| */ |
| private void readObject(java.io.ObjectInputStream in) throws IOException, |
| ClassNotFoundException { |
| ObjectInputStream.GetField fields = in.readFields(); |
| |
| items = new HashMap<String, Permission>(); |
| permClass = (Class<? extends Permission>) fields.get("permClass", null); //$NON-NLS-1$ |
| items.putAll((Hashtable<String, Permission>) fields.get( |
| "permissions", new Hashtable<String, Permission>())); //$NON-NLS-1$ |
| for (Iterator<Permission> iter = items.values().iterator(); iter |
| .hasNext();) { |
| if (iter.next().getClass() != permClass) { |
| throw new InvalidObjectException( |
| Messages.getString("security.24")); //$NON-NLS-1$ |
| } |
| } |
| allEnabled = fields.get("all_allowed", false); //$NON-NLS-1$ |
| if (allEnabled && !items.containsKey("*")) { //$NON-NLS-1$ |
| throw new InvalidObjectException(Messages.getString("security.25")); //$NON-NLS-1$ |
| } |
| } |
| } |