| /* |
| * 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(); |
| } |
| } |