jdk/src/share/classes/java/nio/file/attribute/AclEntry.java
changeset 2057 3acf8e5e2ca0
child 2072 80dfe4469bbd
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     1 /*
       
     2  * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package java.nio.file.attribute;
       
    27 
       
    28 import java.util.*;
       
    29 
       
    30 /**
       
    31  * An entry in an access control list (ACL).
       
    32  *
       
    33  * <p> The ACL entry represented by this class is based on the ACL model
       
    34  * specified in <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC&nbsp;3530:
       
    35  * Network File System (NFS) version 4 Protocol</i></a>. Each entry has four
       
    36  * components as follows:
       
    37  *
       
    38  * <ol>
       
    39  *    <li><p> The {@link #type() type} component determines if the entry
       
    40  *    grants or denies access. </p></li>
       
    41  *
       
    42  *    <li><p> The {@link #principal() principal} component, sometimes called the
       
    43  *    "who" component, is a {@link UserPrincipal} corresponding to the identity
       
    44  *    that the entry grants or denies access
       
    45  *    </p></li>
       
    46  *
       
    47  *    <li><p> The {@link #permissions permissions} component is a set of
       
    48  *    {@link AclEntryPermission permissions}
       
    49  *    </p></li>
       
    50  *
       
    51  *    <li><p> The {@link #flags flags} component is a set of {@link AclEntryFlag
       
    52  *    flags} to indicate how entries are inherited and propagated </p></li>
       
    53  * </ol>
       
    54  *
       
    55  * <p> ACL entries are created using an associated {@link Builder} object by
       
    56  * invoking its {@link Builder#build build} method.
       
    57  *
       
    58  * <p> ACL entries are immutable and are safe for use by multiple concurrent
       
    59  * threads.
       
    60  *
       
    61  * @since 1.7
       
    62  */
       
    63 
       
    64 public final class AclEntry {
       
    65 
       
    66     private final AclEntryType type;
       
    67     private final UserPrincipal who;
       
    68     private final Set<AclEntryPermission> perms;
       
    69     private final Set<AclEntryFlag> flags;
       
    70 
       
    71     // cached hash code
       
    72     private volatile int hash;
       
    73 
       
    74     // private constructor
       
    75     private AclEntry(AclEntryType type,
       
    76                      UserPrincipal who,
       
    77                      Set<AclEntryPermission> perms,
       
    78                      Set<AclEntryFlag> flags)
       
    79     {
       
    80         this.type = type;
       
    81         this.who = who;
       
    82         this.perms = perms;
       
    83         this.flags = flags;
       
    84     }
       
    85 
       
    86     /**
       
    87      * A builder of {@link AclEntry} objects.
       
    88      *
       
    89      * <p> A {@code Builder} object is obtained by invoking one of the {@link
       
    90      * AclEntry#newBuilder newBuilder} methods defined by the {@code AclEntry}
       
    91      * class.
       
    92      *
       
    93      * <p> Builder objects are mutable and are not safe for use by multiple
       
    94      * concurrent threads without appropriate synchronization.
       
    95      *
       
    96      * @since 1.7
       
    97      */
       
    98     public static final class Builder {
       
    99         private AclEntryType type;
       
   100         private UserPrincipal who;
       
   101         private Set<AclEntryPermission> perms;
       
   102         private Set<AclEntryFlag> flags;
       
   103 
       
   104         private Builder(AclEntryType type,
       
   105                         UserPrincipal who,
       
   106                         Set<AclEntryPermission> perms,
       
   107                         Set<AclEntryFlag> flags)
       
   108         {
       
   109             assert perms != null && flags != null;
       
   110             this.type = type;
       
   111             this.who = who;
       
   112             this.perms = perms;
       
   113             this.flags = flags;
       
   114         }
       
   115 
       
   116         /**
       
   117          * Constructs an {@link AclEntry} from the components of this builder.
       
   118          * The type and who components are required to have been set in order
       
   119          * to construct an {@code AclEntry}.
       
   120          *
       
   121          * @return  A new ACL entry
       
   122          *
       
   123          * @throws  IllegalStateException
       
   124          *          If the type or who component have not been set.
       
   125          */
       
   126         public AclEntry build() {
       
   127             if (type == null)
       
   128                 throw new IllegalStateException("Missing type component");
       
   129             if (who == null)
       
   130                 throw new IllegalStateException("Missing who component");
       
   131             return new AclEntry(type, who, perms, flags);
       
   132         }
       
   133 
       
   134         /**
       
   135          * Sets the type component of this builder.
       
   136          *
       
   137          * @return  This builder
       
   138          */
       
   139         public Builder setType(AclEntryType type) {
       
   140             if (type == null)
       
   141                 throw new NullPointerException();
       
   142             this.type = type;
       
   143             return this;
       
   144         }
       
   145 
       
   146         /**
       
   147          * Sets the principal component of this builder.
       
   148          *
       
   149          * @return  This builder
       
   150          */
       
   151         public Builder setPrincipal(UserPrincipal who) {
       
   152             if (who == null)
       
   153                 throw new NullPointerException();
       
   154             this.who = who;
       
   155             return this;
       
   156         }
       
   157 
       
   158         // check set only contains elements of the given type
       
   159         private static void checkSet(Set<?> set, Class<?> type) {
       
   160             for (Object e: set) {
       
   161                 if (e == null)
       
   162                     throw new NullPointerException();
       
   163                 type.cast(e);
       
   164             }
       
   165         }
       
   166 
       
   167         /**
       
   168          * Sets the permissions component of this builder. On return, the
       
   169          * permissions component of this builder is a copy of the given set.
       
   170          *
       
   171          * @return  This builder
       
   172          *
       
   173          * @throws  ClassCastException
       
   174          *          If the sets contains elements that are not of type {@code
       
   175          *          AclEntryPermission}
       
   176          */
       
   177         public Builder setPermissions(Set<AclEntryPermission> perms) {
       
   178             // copy and check for erroneous elements
       
   179             perms = new HashSet<AclEntryPermission>(perms);
       
   180             checkSet(perms, AclEntryPermission.class);
       
   181             this.perms = perms;
       
   182             return this;
       
   183         }
       
   184 
       
   185         /**
       
   186          * Sets the permissions component of this builder. On return, the
       
   187          * permissions component of this builder is a copy of the permissions in
       
   188          * the given array.
       
   189          *
       
   190          * @return  This builder
       
   191          */
       
   192         public Builder setPermissions(AclEntryPermission... perms) {
       
   193             Set<AclEntryPermission> set =
       
   194                 new HashSet<AclEntryPermission>(perms.length);
       
   195             // copy and check for null elements
       
   196             for (AclEntryPermission p: perms) {
       
   197                 if (p == null)
       
   198                     throw new NullPointerException();
       
   199                 set.add(p);
       
   200             }
       
   201             this.perms = set;
       
   202             return this;
       
   203         }
       
   204 
       
   205         /**
       
   206          * Sets the flags component of this builder. On return, the flags
       
   207          * component of this builder is a copy of the given set.
       
   208          *
       
   209          * @return  This builder
       
   210          *
       
   211          * @throws  ClassCastException
       
   212          *          If the sets contains elements that are not of type {@code
       
   213          *          AclEntryFlag}
       
   214          */
       
   215         public Builder setFlags(Set<AclEntryFlag> flags) {
       
   216             // copy and check for erroneous elements
       
   217             flags = new HashSet<AclEntryFlag>(flags);
       
   218             checkSet(flags, AclEntryFlag.class);
       
   219             this.flags = flags;
       
   220             return this;
       
   221         }
       
   222 
       
   223         /**
       
   224          * Sets the flags component of this builder. On return, the flags
       
   225          * component of this builder is a copy of the flags in the given
       
   226          * array.
       
   227          *
       
   228          * @return  This builder
       
   229          */
       
   230         public Builder setFlags(AclEntryFlag... flags) {
       
   231             Set<AclEntryFlag> set = new HashSet<AclEntryFlag>(flags.length);
       
   232             // copy and check for null elements
       
   233             for (AclEntryFlag f: flags) {
       
   234                 if (f == null)
       
   235                     throw new NullPointerException();
       
   236                 set.add(f);
       
   237             }
       
   238             this.flags = set;
       
   239             return this;
       
   240         }
       
   241     }
       
   242 
       
   243     /**
       
   244      * Constructs a new builder. The initial value of the type and who
       
   245      * components is {@code null}. The initial value of the permissions and
       
   246      * flags components is the empty set.
       
   247      *
       
   248      * @return  A new builder
       
   249      */
       
   250     public static Builder newBuilder() {
       
   251         Set<AclEntryPermission> perms = Collections.emptySet();
       
   252         Set<AclEntryFlag> flags = Collections.emptySet();
       
   253         return new Builder(null, null, perms, flags);
       
   254     }
       
   255 
       
   256     /**
       
   257      * Constructs a new builder with the components of an existing ACL entry.
       
   258      *
       
   259      * @param   entry
       
   260      *          An ACL entry
       
   261      *
       
   262      * @return  A new builder
       
   263      */
       
   264     public static Builder newBuilder(AclEntry entry) {
       
   265         return new Builder(entry.type, entry.who, entry.perms, entry.flags);
       
   266     }
       
   267 
       
   268     /**
       
   269      * Returns the ACL entry type.
       
   270      */
       
   271     public AclEntryType type() {
       
   272         return type;
       
   273     }
       
   274 
       
   275     /**
       
   276      * Returns the principal component.
       
   277      */
       
   278     public UserPrincipal principal() {
       
   279         return who;
       
   280     }
       
   281 
       
   282     /**
       
   283      * Returns a copy of the permissions component.
       
   284      *
       
   285      * <p> The returned set is a modifiable copy of the permissions.
       
   286      */
       
   287     public Set<AclEntryPermission> permissions() {
       
   288         return new HashSet<AclEntryPermission>(perms);
       
   289     }
       
   290 
       
   291     /**
       
   292      * Returns a copy of the flags component.
       
   293      *
       
   294      * <p> The returned set is a modifiable copy of the flags.
       
   295      */
       
   296     public Set<AclEntryFlag> flags() {
       
   297         return new HashSet<AclEntryFlag>(flags);
       
   298     }
       
   299 
       
   300     /**
       
   301      * Compares the specified object with this ACL entry for equality.
       
   302      *
       
   303      * <p> If the given object is not an {@code AclEntry} then this method
       
   304      * immediately returns {@code false}.
       
   305      *
       
   306      * <p> For two ACL entries to be considered equals requires that they are
       
   307      * both the same type, their who components are equal, their permissions
       
   308      * components are equal, and their flags components are equal.
       
   309      *
       
   310      * <p> This method satisfies the general contract of the {@link
       
   311      * java.lang.Object#equals(Object) Object.equals} method. </p>
       
   312      *
       
   313      * @param   ob   The object to which this object is to be compared
       
   314      *
       
   315      * @return  {@code true} if, and only if, the given object is an AclEntry that
       
   316      *          is identical to this AclEntry
       
   317      */
       
   318     @Override
       
   319     public boolean equals(Object ob) {
       
   320         if (ob == this)
       
   321             return true;
       
   322         if (ob == null || !(ob instanceof AclEntry))
       
   323             return false;
       
   324         AclEntry other = (AclEntry)ob;
       
   325         if (this.type != other.type)
       
   326             return false;
       
   327         if (!this.who.equals(other.who))
       
   328             return false;
       
   329         if (!this.perms.equals(other.perms))
       
   330             return false;
       
   331         if (!this.flags.equals(other.flags))
       
   332             return false;
       
   333         return true;
       
   334     }
       
   335 
       
   336     private static int hash(int h, Object o) {
       
   337         return h * 127 + o.hashCode();
       
   338     }
       
   339 
       
   340     /**
       
   341      * Returns the hash-code value for this ACL entry.
       
   342      *
       
   343      * <p> This method satisfies the general contract of the {@link
       
   344      * Object#hashCode method}.
       
   345      */
       
   346     @Override
       
   347     public int hashCode() {
       
   348         // return cached hash if available
       
   349         if (hash != 0)
       
   350             return hash;
       
   351         int h = type.hashCode();
       
   352         h = hash(h, who);
       
   353         h = hash(h, perms);
       
   354         h = hash(h, flags);
       
   355         hash = h;
       
   356         return hash;
       
   357     }
       
   358 
       
   359     /**
       
   360      * Returns the string representation of this ACL entry.
       
   361      *
       
   362      * @return  The string representation of this entry
       
   363      */
       
   364     @Override
       
   365     public String toString() {
       
   366         StringBuilder sb = new StringBuilder();
       
   367 
       
   368         // who
       
   369         sb.append(who.getName());
       
   370         sb.append(':');
       
   371 
       
   372         // permissions
       
   373         for (AclEntryPermission perm: perms) {
       
   374             sb.append(perm.name());
       
   375             sb.append('/');
       
   376         }
       
   377         sb.setLength(sb.length()-1); // drop final slash
       
   378         sb.append(':');
       
   379 
       
   380         // flags
       
   381         if (!flags.isEmpty()) {
       
   382             for (AclEntryFlag flag: flags) {
       
   383                 sb.append(flag.name());
       
   384                 sb.append('/');
       
   385             }
       
   386             sb.setLength(sb.length()-1);  // drop final slash
       
   387             sb.append(':');
       
   388         }
       
   389 
       
   390         // type
       
   391         sb.append(type.name());
       
   392         return sb.toString();
       
   393     }
       
   394 }