/* | 
|
 * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package java.nio.file.attribute;  | 
|
import java.util.*;  | 
|
/**  | 
|
* An entry in an access control list (ACL).  | 
|
*  | 
|
* <p> The ACL entry represented by this class is based on the ACL model  | 
|
* specified in <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC 3530:  | 
|
* Network File System (NFS) version 4 Protocol</i></a>. Each entry has four  | 
|
* components as follows:  | 
|
*  | 
|
* <ol>  | 
|
 *    <li><p> The {@link #type() type} component determines if the entry | 
|
* grants or denies access. </p></li>  | 
|
*  | 
|
 *    <li><p> The {@link #principal() principal} component, sometimes called the | 
|
 *    "who" component, is a {@link UserPrincipal} corresponding to the identity | 
|
* that the entry grants or denies access  | 
|
* </p></li>  | 
|
*  | 
|
 *    <li><p> The {@link #permissions permissions} component is a set of | 
|
 *    {@link AclEntryPermission permissions} | 
|
* </p></li>  | 
|
*  | 
|
 *    <li><p> The {@link #flags flags} component is a set of {@link AclEntryFlag | 
|
* flags} to indicate how entries are inherited and propagated </p></li>  | 
|
* </ol>  | 
|
*  | 
|
 * <p> ACL entries are created using an associated {@link Builder} object by | 
|
 * invoking its {@link Builder#build build} method. | 
|
*  | 
|
* <p> ACL entries are immutable and are safe for use by multiple concurrent  | 
|
* threads.  | 
|
*  | 
|
* @since 1.7  | 
|
*/  | 
|
public final class AclEntry { | 
|
private final AclEntryType type;  | 
|
private final UserPrincipal who;  | 
|
private final Set<AclEntryPermission> perms;  | 
|
private final Set<AclEntryFlag> flags;  | 
|
    // cached hash code | 
|
private volatile int hash;  | 
|
    // private constructor | 
|
private AclEntry(AclEntryType type,  | 
|
UserPrincipal who,  | 
|
Set<AclEntryPermission> perms,  | 
|
Set<AclEntryFlag> flags)  | 
|
    { | 
|
this.type = type;  | 
|
this.who = who;  | 
|
this.perms = perms;  | 
|
this.flags = flags;  | 
|
}  | 
|
    /** | 
|
     * A builder of {@link AclEntry} objects. | 
|
     * | 
|
     * <p> A {@code Builder} object is obtained by invoking one of the {@link | 
|
     * AclEntry#newBuilder newBuilder} methods defined by the {@code AclEntry} | 
|
     * class. | 
|
     * | 
|
     * <p> Builder objects are mutable and are not safe for use by multiple | 
|
     * concurrent threads without appropriate synchronization. | 
|
     * | 
|
     * @since 1.7 | 
|
*/  | 
|
    public static final class Builder { | 
|
private AclEntryType type;  | 
|
private UserPrincipal who;  | 
|
private Set<AclEntryPermission> perms;  | 
|
private Set<AclEntryFlag> flags;  | 
|
private Builder(AclEntryType type,  | 
|
UserPrincipal who,  | 
|
Set<AclEntryPermission> perms,  | 
|
Set<AclEntryFlag> flags)  | 
|
        { | 
|
assert perms != null && flags != null;  | 
|
this.type = type;  | 
|
this.who = who;  | 
|
this.perms = perms;  | 
|
this.flags = flags;  | 
|
}  | 
|
        /** | 
|
         * Constructs an {@link AclEntry} from the components of this builder. | 
|
         * The type and who components are required to have been set in order | 
|
         * to construct an {@code AclEntry}. | 
|
         * | 
|
         * @return  a new ACL entry | 
|
         * | 
|
         * @throws  IllegalStateException | 
|
         *          if the type or who component have not been set | 
|
*/  | 
|
public AclEntry build() {  | 
|
if (type == null)  | 
|
throw new IllegalStateException("Missing type component");  | 
|
if (who == null)  | 
|
throw new IllegalStateException("Missing who component");  | 
|
return new AclEntry(type, who, perms, flags);  | 
|
}  | 
|
        /** | 
|
         * Sets the type component of this builder. | 
|
         * | 
|
         * @param   type  the component type | 
|
         * @return  this builder | 
|
*/  | 
|
public Builder setType(AclEntryType type) {  | 
|
if (type == null)  | 
|
throw new NullPointerException();  | 
|
this.type = type;  | 
|
return this;  | 
|
}  | 
|
        /** | 
|
         * Sets the principal component of this builder. | 
|
         * | 
|
         * @param   who  the principal component | 
|
         * @return  this builder | 
|
*/  | 
|
public Builder setPrincipal(UserPrincipal who) {  | 
|
if (who == null)  | 
|
throw new NullPointerException();  | 
|
this.who = who;  | 
|
return this;  | 
|
}  | 
|
        // check set only contains elements of the given type | 
|
private static void checkSet(Set<?> set, Class<?> type) {  | 
|
for (Object e: set) {  | 
|
if (e == null)  | 
|
throw new NullPointerException();  | 
|
type.cast(e);  | 
|
}  | 
|
}  | 
|
        /** | 
|
         * Sets the permissions component of this builder. On return, the | 
|
         * permissions component of this builder is a copy of the given set. | 
|
         * | 
|
         * @param   perms  the permissions component | 
|
         * @return  this builder | 
|
         * | 
|
         * @throws  ClassCastException | 
|
         *          if the set contains elements that are not of type {@code | 
|
         *          AclEntryPermission} | 
|
*/  | 
|
public Builder setPermissions(Set<AclEntryPermission> perms) {  | 
|
if (perms.isEmpty()) {  | 
|
                // EnumSet.copyOf does not allow empty set | 
|
perms = Collections.emptySet();  | 
|
            } else { | 
|
                // copy and check for erroneous elements | 
|
perms = EnumSet.copyOf(perms);  | 
|
checkSet(perms, AclEntryPermission.class);  | 
|
}  | 
|
this.perms = perms;  | 
|
return this;  | 
|
}  | 
|
        /** | 
|
         * Sets the permissions component of this builder. On return, the | 
|
         * permissions component of this builder is a copy of the permissions in | 
|
         * the given array. | 
|
         * | 
|
         * @param   perms  the permissions component | 
|
         * @return  this builder | 
|
*/  | 
|
public Builder setPermissions(AclEntryPermission... perms) {  | 
|
Set<AclEntryPermission> set = EnumSet.noneOf(AclEntryPermission.class);  | 
|
            // copy and check for null elements | 
|
for (AclEntryPermission p: perms) {  | 
|
if (p == null)  | 
|
throw new NullPointerException();  | 
|
set.add(p);  | 
|
}  | 
|
this.perms = set;  | 
|
return this;  | 
|
}  | 
|
        /** | 
|
         * Sets the flags component of this builder. On return, the flags | 
|
         * component of this builder is a copy of the given set. | 
|
         * | 
|
         * @param   flags  the flags component | 
|
         * @return  this builder | 
|
         * | 
|
         * @throws  ClassCastException | 
|
         *          if the set contains elements that are not of type {@code | 
|
         *          AclEntryFlag} | 
|
*/  | 
|
public Builder setFlags(Set<AclEntryFlag> flags) {  | 
|
if (flags.isEmpty()) {  | 
|
                // EnumSet.copyOf does not allow empty set | 
|
flags = Collections.emptySet();  | 
|
            } else { | 
|
                // copy and check for erroneous elements | 
|
flags = EnumSet.copyOf(flags);  | 
|
checkSet(flags, AclEntryFlag.class);  | 
|
}  | 
|
this.flags = flags;  | 
|
return this;  | 
|
}  | 
|
        /** | 
|
         * Sets the flags component of this builder. On return, the flags | 
|
         * component of this builder is a copy of the flags in the given | 
|
         * array. | 
|
         * | 
|
         * @param   flags  the flags component | 
|
         * @return  this builder | 
|
*/  | 
|
public Builder setFlags(AclEntryFlag... flags) {  | 
|
Set<AclEntryFlag> set = EnumSet.noneOf(AclEntryFlag.class);  | 
|
            // copy and check for null elements | 
|
for (AclEntryFlag f: flags) {  | 
|
if (f == null)  | 
|
throw new NullPointerException();  | 
|
set.add(f);  | 
|
}  | 
|
this.flags = set;  | 
|
return this;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Constructs a new builder. The initial value of the type and who | 
|
     * components is {@code null}. The initial value of the permissions and | 
|
     * flags components is the empty set. | 
|
     * | 
|
     * @return  a new builder | 
|
*/  | 
|
    public static Builder newBuilder() { | 
|
Set<AclEntryPermission> perms = Collections.emptySet();  | 
|
Set<AclEntryFlag> flags = Collections.emptySet();  | 
|
return new Builder(null, null, perms, flags);  | 
|
}  | 
|
    /** | 
|
     * Constructs a new builder with the components of an existing ACL entry. | 
|
     * | 
|
     * @param   entry  an ACL entry | 
|
     * @return  a new builder | 
|
*/  | 
|
public static Builder newBuilder(AclEntry entry) {  | 
|
return new Builder(entry.type, entry.who, entry.perms, entry.flags);  | 
|
}  | 
|
    /** | 
|
     * Returns the ACL entry type. | 
|
     * | 
|
     * @return the ACL entry type | 
|
*/  | 
|
public AclEntryType type() {  | 
|
return type;  | 
|
}  | 
|
    /** | 
|
     * Returns the principal component. | 
|
     * | 
|
     * @return the principal component | 
|
*/  | 
|
public UserPrincipal principal() {  | 
|
return who;  | 
|
}  | 
|
    /** | 
|
     * Returns a copy of the permissions component. | 
|
     * | 
|
     * <p> The returned set is a modifiable copy of the permissions. | 
|
     * | 
|
     * @return the permissions component | 
|
*/  | 
|
public Set<AclEntryPermission> permissions() {  | 
|
return new HashSet<AclEntryPermission>(perms);  | 
|
}  | 
|
    /** | 
|
     * Returns a copy of the flags component. | 
|
     * | 
|
     * <p> The returned set is a modifiable copy of the flags. | 
|
     * | 
|
     * @return the flags component | 
|
*/  | 
|
public Set<AclEntryFlag> flags() {  | 
|
return new HashSet<AclEntryFlag>(flags);  | 
|
}  | 
|
    /** | 
|
     * Compares the specified object with this ACL entry for equality. | 
|
     * | 
|
     * <p> If the given object is not an {@code AclEntry} then this method | 
|
     * immediately returns {@code false}. | 
|
     * | 
|
     * <p> For two ACL entries to be considered equals requires that they are | 
|
     * both the same type, their who components are equal, their permissions | 
|
     * components are equal, and their flags components are equal. | 
|
     * | 
|
     * <p> This method satisfies the general contract of the {@link | 
|
     * java.lang.Object#equals(Object) Object.equals} method. </p> | 
|
     * | 
|
     * @param   ob   the object to which this object is to be compared | 
|
     * | 
|
     * @return  {@code true} if, and only if, the given object is an AclEntry that | 
|
     *          is identical to this AclEntry | 
|
*/  | 
|
@Override  | 
|
public boolean equals(Object ob) {  | 
|
if (ob == this)  | 
|
return true;  | 
|
if (ob == null || !(ob instanceof AclEntry))  | 
|
return false;  | 
|
AclEntry other = (AclEntry)ob;  | 
|
if (this.type != other.type)  | 
|
return false;  | 
|
if (!this.who.equals(other.who))  | 
|
return false;  | 
|
if (!this.perms.equals(other.perms))  | 
|
return false;  | 
|
if (!this.flags.equals(other.flags))  | 
|
return false;  | 
|
return true;  | 
|
}  | 
|
private static int hash(int h, Object o) {  | 
|
return h * 127 + o.hashCode();  | 
|
}  | 
|
    /** | 
|
     * Returns the hash-code value for this ACL entry. | 
|
     * | 
|
     * <p> This method satisfies the general contract of the {@link | 
|
     * Object#hashCode} method. | 
|
*/  | 
|
@Override  | 
|
    public int hashCode() { | 
|
        // return cached hash if available | 
|
if (hash != 0)  | 
|
return hash;  | 
|
int h = type.hashCode();  | 
|
h = hash(h, who);  | 
|
h = hash(h, perms);  | 
|
h = hash(h, flags);  | 
|
hash = h;  | 
|
return hash;  | 
|
}  | 
|
    /** | 
|
     * Returns the string representation of this ACL entry. | 
|
     * | 
|
     * @return  the string representation of this entry | 
|
*/  | 
|
@Override  | 
|
public String toString() {  | 
|
StringBuilder sb = new StringBuilder();  | 
|
        // who | 
|
sb.append(who.getName());  | 
|
sb.append(':');  | 
|
        // permissions | 
|
for (AclEntryPermission perm: perms) {  | 
|
sb.append(perm.name());  | 
|
sb.append('/');  | 
|
}  | 
|
sb.setLength(sb.length()-1); // drop final slash  | 
|
sb.append(':');  | 
|
        // flags | 
|
if (!flags.isEmpty()) {  | 
|
for (AclEntryFlag flag: flags) {  | 
|
sb.append(flag.name());  | 
|
sb.append('/');  | 
|
}  | 
|
sb.setLength(sb.length()-1); // drop final slash  | 
|
sb.append(':');  | 
|
}  | 
|
        // type | 
|
sb.append(type.name());  | 
|
return sb.toString();  | 
|
}  | 
|
}  |