001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.security;
019:
020: import java.io.IOException;
021: import java.io.InvalidObjectException;
022: import java.io.ObjectInputStream;
023: import java.io.ObjectOutputStream;
024: import java.io.ObjectStreamField;
025: import java.util.Collections;
026: import java.util.Enumeration;
027: import java.util.HashMap;
028: import java.util.Hashtable;
029: import java.util.Iterator;
030: import java.util.Map;
031:
032: import org.apache.harmony.security.internal.nls.Messages;
033:
034: /**
035: * Specific PermissionCollection for storing BasicPermissions of arbitrary type.
036: *
037: */
038:
039: final class BasicPermissionCollection extends PermissionCollection {
040:
041: private static final long serialVersionUID = 739301742472979399L;
042:
043: private static final ObjectStreamField[] serialPersistentFields = {
044: new ObjectStreamField("all_allowed", Boolean.TYPE), //$NON-NLS-1$
045: new ObjectStreamField("permissions", Hashtable.class), //$NON-NLS-1$
046: new ObjectStreamField("permClass", Class.class), }; //$NON-NLS-1$
047:
048: //should be final, but because of writeObject() cannot be
049: private transient Map<String, Permission> items = new HashMap<String, Permission>();
050:
051: // true if this Collection contains a BasicPermission with '*' as its permission name
052: private transient boolean allEnabled; // = false;
053:
054: private Class<? extends Permission> permClass;
055:
056: /**
057: * Adds a permission to the collection. The first added permission must be a
058: * subclass of BasicPermission, next permissions must be of the same class
059: * as the first one.
060: *
061: * @see java.security.PermissionCollection#add(java.security.Permission)
062: */
063: public void add(Permission permission) {
064: if (isReadOnly()) {
065: throw new SecurityException(Messages
066: .getString("security.15")); //$NON-NLS-1$
067: }
068: if (permission == null) {
069: throw new IllegalArgumentException(Messages
070: .getString("security.20")); //$NON-NLS-1$
071: }
072:
073: Class<? extends Permission> inClass = permission.getClass();
074: if (permClass != null) {
075: if (permClass != inClass) {
076: throw new IllegalArgumentException(Messages.getString(
077: "security.16", //$NON-NLS-1$
078: permission));
079: }
080: } else if (!(permission instanceof BasicPermission)) {
081: throw new IllegalArgumentException(Messages.getString(
082: "security.16", //$NON-NLS-1$
083: permission));
084: } else {
085: // this is the first element provided that another thread did not add
086: synchronized (this ) {
087: if (permClass != null && inClass != permClass) {
088: throw new IllegalArgumentException(Messages
089: .getString("security.16", //$NON-NLS-1$
090: permission));
091: }
092: permClass = inClass;
093: }
094: }
095:
096: String name = permission.getName();
097: items.put(name, permission);
098: allEnabled = allEnabled
099: || (name.length() == 1 && '*' == name.charAt(0));
100: }
101:
102: /**
103: * Returns enumeration of contained elements.
104: */
105: public Enumeration<Permission> elements() {
106: return Collections.enumeration(items.values());
107: }
108:
109: /**
110: * Indicates whether the argument permission is implied by the receiver.
111: *
112: * @return boolean <code>true</code> if the argument permission is implied
113: * by the receiver, and <code>false</code> if it is not.
114: * @param permission
115: * java.security.Permission the permission to check
116: */
117: public boolean implies(Permission permission) {
118: if (permission == null || permission.getClass() != permClass) {
119: return false;
120: }
121: if (allEnabled) {
122: return true;
123: }
124: String checkName = permission.getName();
125: //first check direct coincidence
126: if (items.containsKey(checkName)) {
127: return true;
128: }
129: //now check if there are suitable wildcards
130: //suppose we have "a.b.c", let's check "a.b.*" and "a.*"
131: char[] name = checkName.toCharArray();
132: //I presume that "a.b.*" does not imply "a.b."
133: //so the dot at end is ignored
134: int pos = name.length - 2;
135: for (; pos >= 0; pos--) {
136: if (name[pos] == '.') {
137: break;
138: }
139: }
140: while (pos >= 0) {
141: name[pos + 1] = '*';
142: if (items.containsKey(new String(name, 0, pos + 2))) {
143: return true;
144: }
145: for (--pos; pos >= 0; pos--) {
146: if (name[pos] == '.') {
147: break;
148: }
149: }
150: }
151: return false;
152: }
153:
154: /**
155: * Writes the object to the given stream for serialization.
156: *
157: * The following fields are stored via an ObjectOutputStream.PutField,
158: * obtained by calling putFields() on the given output stream, in order to
159: * comply with the serialized form specification for this class:
160: *
161: * <code>boolean all_allowed</code>, set to <code>allEnabled</code>
162: * <code>Hashtable permissions</code>,
163: * set to <code>items</code>
164: * <code>Class permClass</code>, set to
165: * <code>permClass</code>
166: */
167: private void writeObject(java.io.ObjectOutputStream out)
168: throws IOException {
169: ObjectOutputStream.PutField fields = out.putFields();
170: fields.put("all_allowed", allEnabled); //$NON-NLS-1$
171: fields
172: .put(
173: "permissions", new Hashtable<String, Permission>(items)); //$NON-NLS-1$
174: fields.put("permClass", permClass); //$NON-NLS-1$
175: out.writeFields();
176: }
177:
178: /**
179: * Reads the object from stream and checks its consistency: all contained
180: * permissions must be of the same subclass of BasicPermission.
181: */
182: private void readObject(java.io.ObjectInputStream in)
183: throws IOException, ClassNotFoundException {
184: ObjectInputStream.GetField fields = in.readFields();
185:
186: items = new HashMap<String, Permission>();
187: synchronized (this ) {
188: permClass = (Class<? extends Permission>) fields.get(
189: "permClass", null); //$NON-NLS-1$
190: items
191: .putAll((Hashtable<String, Permission>) fields
192: .get(
193: "permissions", new Hashtable<String, Permission>())); //$NON-NLS-1$
194: for (Iterator<Permission> iter = items.values().iterator(); iter
195: .hasNext();) {
196: if (iter.next().getClass() != permClass) {
197: throw new InvalidObjectException(Messages
198: .getString("security.24")); //$NON-NLS-1$
199: }
200: }
201: allEnabled = fields.get("all_allowed", false); //$NON-NLS-1$
202: if (allEnabled && !items.containsKey("*")) { //$NON-NLS-1$
203: throw new InvalidObjectException(Messages
204: .getString("security.25")); //$NON-NLS-1$
205: }
206: }
207: }
208: }
|