001    /* BasicPermission.java -- implements a simple named permission
002       Copyright (C) 1998, 1999, 2002, 2003, 2004, 2005, 2006
003       Free Software Foundation, Inc.
004    
005    This file is part of GNU Classpath.
006    
007    GNU Classpath is free software; you can redistribute it and/or modify
008    it under the terms of the GNU General Public License as published by
009    the Free Software Foundation; either version 2, or (at your option)
010    any later version.
011    
012    GNU Classpath is distributed in the hope that it will be useful, but
013    WITHOUT ANY WARRANTY; without even the implied warranty of
014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015    General Public License for more details.
016    
017    You should have received a copy of the GNU General Public License
018    along with GNU Classpath; see the file COPYING.  If not, write to the
019    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
020    02110-1301 USA.
021    
022    Linking this library statically or dynamically with other modules is
023    making a combined work based on this library.  Thus, the terms and
024    conditions of the GNU General Public License cover the whole
025    combination.
026    
027    As a special exception, the copyright holders of this library give you
028    permission to link this library with independent modules to produce an
029    executable, regardless of the license terms of these independent
030    modules, and to copy and distribute the resulting executable under
031    terms of your choice, provided that you also meet, for each linked
032    independent module, the terms and conditions of the license of that
033    module.  An independent module is a module which is not derived from
034    or based on this library.  If you modify this library, you may extend
035    this exception to your version of the library, but you are not
036    obligated to do so.  If you do not wish to do so, delete this
037    exception statement from your version. */
038    
039    
040    package java.security;
041    
042    import java.io.Serializable;
043    import java.util.Enumeration;
044    import java.util.Hashtable;
045    
046    /**
047     * This class implements a simple model for named permissions without an
048     * associated action list.  That is, either the named permission is granted
049     * or it is not.
050     *
051     * <p>It also supports trailing wildcards to allow the easy granting of
052     * permissions in a hierarchical fashion.  (For example, the name "org.gnu.*"
053     * might grant all permissions under the "org.gnu" permissions hierarchy).
054     * The only valid wildcard character is a '*' which matches anything. It
055     * must be the rightmost element in the permission name and must follow a
056     * '.' or else the Permission name must consist of only a '*'. Any other
057     * occurrence of a '*' is not valid.
058     *
059     * <p>This class ignores the action list.  Subclasses can choose to implement
060     * actions on top of this class if desired.
061     *
062     * @author Aaron M. Renn (arenn@urbanophile.com)
063     * @author Eric Blake (ebb9@email.byu.edu)
064     * @see Permission
065     * @see Permissions
066     * @see PermissionCollection
067     * @see RuntimePermission
068     * @see SecurityPermission
069     * @see PropertyPermission
070     * @see AWTPermission
071     * @see NetPermission
072     * @see SecurityManager
073     * @since 1.1
074     * @status updated to 1.4
075     */
076    public abstract class BasicPermission extends Permission
077      implements Serializable
078    {
079      /**
080       * Compatible with JDK 1.1+.
081       */
082      private static final long serialVersionUID = 6279438298436773498L;
083    
084      /**
085       * Create a new instance with the specified permission name. If the
086       * name is empty an exception is thrown.
087       *
088       * @param name the name of this permission
089       * @throws NullPointerException if name is null
090       * @throws IllegalArgumentException if name is invalid
091       */
092      public BasicPermission(String name)
093      {
094        super(name);
095    
096        // This routine used to check for illegal wildcards, but no such
097        // requirement exists in the specification and Sun's runtime
098        // doesn't appear to do it.
099    
100        if (name.equals(""))
101          throw new IllegalArgumentException("Empty name");
102      }
103    
104      /**
105       * Create a new instance with the specified permission name. If the name
106       * is empty, or contains an illegal wildcard character, an exception is
107       * thrown. The actions parameter is ignored.
108       *
109       * @param name the name of this permission
110       * @param actions ignored
111       * @throws NullPointerException if name is null
112       * @throws IllegalArgumentException if name is invalid
113       */
114      public BasicPermission(String name, String actions)
115      {
116        this(name);
117      }
118    
119      /**
120       * This method tests to see if the specified permission is implied by this
121       * permission.  This will be true if the following conditions are met:<ul>
122       * <li>The specified object is an instance of the same class as this
123       * object.</li>
124       * <li>The name of the specified permission is implied by this permission's
125       * name based on wildcard matching. For example, "a.*" implies "a.b".</li>
126       * </ul>
127       *
128       * @param perm the <code>Permission</code> object to test against
129       * @return true if the specified permission is implied
130       */
131      public boolean implies(Permission perm)
132      {
133        if (! getClass().isInstance(perm))
134          return false;
135    
136        String otherName = perm.getName();
137        String name = getName();
138    
139        if (name.equals(otherName))
140          return true;
141    
142        int last = name.length() - 1;
143        return name.charAt(last) == '*'
144          && otherName.startsWith(name.substring(0, last));
145      }
146    
147      /**
148       * This method tests to see if this object is equal to the specified
149       * <code>Object</code>.  This will be true if and only if the specified
150       * object meets the following conditions:<ul>
151       * <li>It is an instance of the same class as this.</li>
152       * <li>It has the same name as this permission.</li>
153       * </ul>
154       *
155       * @param obj the <code>Object</code> to test for equality
156       * @return true if obj is semantically equal to this
157       */
158      public boolean equals(Object obj)
159      {
160        return getClass().isInstance(obj)
161          && getName().equals(((BasicPermission) obj).getName());
162      }
163    
164      /**
165       * This method returns a hash code for this permission object.  The hash
166       * code returned is the value returned by calling the <code>hashCode</code>
167       * method on the <code>String</code> that is the name of this permission.
168       *
169       * @return a hash value for this object
170       */
171      public int hashCode()
172      {
173        return getName().hashCode();
174      }
175    
176      /**
177       * This method returns a list of the actions associated with this
178       * permission.  This method always returns the empty string ("") since
179       * this class ignores actions.
180       *
181       * @return the action list
182       */
183      public String getActions()
184      {
185        return "";
186      }
187    
188      /**
189       * This method returns an instance of <code>PermissionCollection</code>
190       * suitable for storing <code>BasicPermission</code> objects.  The
191       * collection returned can only store objects of the same type as this.
192       * Subclasses which use actions must override this method; but a class with
193       * no actions will work fine with this.
194       *
195       * @return a new empty <code>PermissionCollection</code> object
196       */
197      public PermissionCollection newPermissionCollection()
198      {
199        return new BasicPermissionCollection(getClass());
200      }
201    
202      /**
203       * Implements AllPermission.newPermissionCollection, and obeys serialization
204       * of JDK.
205       *
206       * @author Eric Blake (ebb9@email.byu.edu)
207       */
208      private static final class BasicPermissionCollection extends PermissionCollection
209      {
210        /**
211         * Compatible with JDK 1.1+.
212         */
213        private static final long serialVersionUID = 739301742472979399L;
214    
215        /**
216         * The permissions in the collection.
217         *
218         * @serial a hash mapping name to permissions, all of type permClass
219         */
220        private final Hashtable permissions = new Hashtable();
221    
222        /**
223         * If "*" is in the collection.
224         *
225         * @serial true if a permission named "*" is in the collection
226         */
227        private boolean all_allowed;
228    
229        /**
230         * The runtime class which all entries in the table must belong to.
231         *
232         * @serial the limiting subclass of this collection
233         */
234        private final Class permClass;
235    
236        /**
237         * Construct a collection over the given runtime class.
238         *
239         * @param c the class
240         */
241        BasicPermissionCollection(Class c)
242        {
243          permClass = c;
244        }
245    
246        /**
247         * Add a Permission. It must be of the same type as the permission which
248         * created this collection.
249         *
250         * @param perm the permission to add
251         * @throws IllegalArgumentException if perm is not the correct type
252         * @throws SecurityException if the collection is read-only
253         */
254        public void add(Permission perm)
255        {
256          if (isReadOnly())
257            throw new SecurityException("readonly");
258          if (! permClass.isInstance(perm))
259            throw new IllegalArgumentException("Expecting instance of " + permClass);
260          BasicPermission bp = (BasicPermission) perm;
261          String name = bp.getName();
262          if (name.equals("*"))
263            all_allowed = true;
264          permissions.put(name, bp);
265        }
266    
267        /**
268         * Returns true if this collection implies the given permission.
269         *
270         * @param permission the permission to check
271         * @return true if it is implied by this
272         */
273        public boolean implies(Permission permission)
274        {
275          if (! permClass.isInstance(permission))
276            return false;
277          if (all_allowed)
278            return true;
279          BasicPermission toImply = (BasicPermission) permission;
280          String name = toImply.getName();
281          if (name.equals("*"))
282            return false;
283          int prefixLength = name.length();
284          if (name.endsWith("*"))
285            prefixLength -= 2;
286    
287          while (true)
288            {
289              if (permissions.get(name) != null)
290                return true;
291              prefixLength = name.lastIndexOf('.', prefixLength);
292              if (prefixLength < 0)
293                return false;
294              name = name.substring(0, prefixLength + 1) + '*';
295            }
296        }
297    
298        /**
299         * Enumerate over the collection.
300         *
301         * @return an enumeration of the collection contents
302         */
303        public Enumeration elements()
304        {
305          return permissions.elements();
306        }
307      } // class BasicPermissionCollection
308    } // class BasicPermission