1 /* 2 * Copyright (c) 2007, 2009, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 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 set 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 = new HashSet<>(perms.length); 194 // copy and check for null elements 195 for (AclEntryPermission p: perms) { 196 if (p == null) 197 throw new NullPointerException(); 198 set.add(p); 199 } 200 this.perms = set; 201 return this; 202 } 203 204 /** 205 * Sets the flags component of this builder. On return, the flags 206 * component of this builder is a copy of the given set. 207 * 208 * @return this builder 209 * 210 * @throws ClassCastException 211 * if the set contains elements that are not of type {@code 212 * AclEntryFlag} 213 */ 214 public Builder setFlags(Set<AclEntryFlag> flags) { 215 // copy and check for erroneous elements 216 flags = new HashSet<AclEntryFlag>(flags); 217 checkSet(flags, AclEntryFlag.class); 218 this.flags = flags; 219 return this; 220 } 221 222 /** 223 * Sets the flags component of this builder. On return, the flags 224 * component of this builder is a copy of the flags in the given 225 * array. 226 * 227 * @return this builder 228 */ 229 public Builder setFlags(AclEntryFlag... flags) { 230 Set<AclEntryFlag> set = new HashSet<>(flags.length); 231 // copy and check for null elements 232 for (AclEntryFlag f: flags) { 233 if (f == null) 234 throw new NullPointerException(); 235 set.add(f); 236 } 237 this.flags = set; 238 return this; 239 } 240 } 241 242 /** 243 * Constructs a new builder. The initial value of the type and who 244 * components is {@code null}. The initial value of the permissions and 245 * flags components is the empty set. 246 * 247 * @return a new builder 248 */ 249 public static Builder newBuilder() { 250 Set<AclEntryPermission> perms = Collections.emptySet(); 251 Set<AclEntryFlag> flags = Collections.emptySet(); 252 return new Builder(null, null, perms, flags); 253 } 254 255 /** 256 * Constructs a new builder with the components of an existing ACL entry. 257 * 258 * @param entry 259 * an ACL entry 260 * 261 * @return a new builder 262 */ 263 public static Builder newBuilder(AclEntry entry) { 264 return new Builder(entry.type, entry.who, entry.perms, entry.flags); 265 } 266 267 /** 268 * Returns the ACL entry type. 269 */ 270 public AclEntryType type() { 271 return type; 272 } 273 274 /** 275 * Returns the principal component. 276 */ 277 public UserPrincipal principal() { 278 return who; 279 } 280 281 /** 282 * Returns a copy of the permissions component. 283 * 284 * <p> The returned set is a modifiable copy of the permissions. 285 */ 286 public Set<AclEntryPermission> permissions() { 287 return new HashSet<AclEntryPermission>(perms); 288 } 289 290 /** 291 * Returns a copy of the flags component. 292 * 293 * <p> The returned set is a modifiable copy of the flags. 294 */ 295 public Set<AclEntryFlag> flags() { 296 return new HashSet<AclEntryFlag>(flags); 297 } 298 299 /** 300 * Compares the specified object with this ACL entry for equality. 301 * 302 * <p> If the given object is not an {@code AclEntry} then this method 303 * immediately returns {@code false}. 304 * 305 * <p> For two ACL entries to be considered equals requires that they are 306 * both the same type, their who components are equal, their permissions 307 * components are equal, and their flags components are equal. 308 * 309 * <p> This method satisfies the general contract of the {@link 310 * java.lang.Object#equals(Object) Object.equals} method. </p> 311 * 312 * @param ob the object to which this object is to be compared 313 * 314 * @return {@code true} if, and only if, the given object is an AclEntry that 315 * is identical to this AclEntry 316 */ 317 @Override 318 public boolean equals(Object ob) { 319 if (ob == this) 320 return true; 321 if (ob == null || !(ob instanceof AclEntry)) 322 return false; 323 AclEntry other = (AclEntry)ob; 324 if (this.type != other.type) 325 return false; 326 if (!this.who.equals(other.who)) 327 return false; 328 if (!this.perms.equals(other.perms)) 329 return false; 330 if (!this.flags.equals(other.flags)) 331 return false; 332 return true; 333 } 334 335 private static int hash(int h, Object o) { 336 return h * 127 + o.hashCode(); 337 } 338 339 /** 340 * Returns the hash-code value for this ACL entry. 341 * 342 * <p> This method satisfies the general contract of the {@link 343 * Object#hashCode} method. 344 */ 345 @Override 346 public int hashCode() { 347 // return cached hash if available 348 if (hash != 0) 349 return hash; 350 int h = type.hashCode(); 351 h = hash(h, who); 352 h = hash(h, perms); 353 h = hash(h, flags); 354 hash = h; 355 return hash; 356 } 357 358 /** 359 * Returns the string representation of this ACL entry. 360 * 361 * @return the string representation of this entry 362 */ 363 @Override 364 public String toString() { 365 StringBuilder sb = new StringBuilder(); 366 367 // who 368 sb.append(who.getName()); 369 sb.append(':'); 370 371 // permissions 372 for (AclEntryPermission perm: perms) { 373 sb.append(perm.name()); 374 sb.append('/'); 375 } 376 sb.setLength(sb.length()-1); // drop final slash 377 sb.append(':'); 378 379 // flags 380 if (!flags.isEmpty()) { 381 for (AclEntryFlag flag: flags) { 382 sb.append(flag.name()); 383 sb.append('/'); 384 } 385 sb.setLength(sb.length()-1); // drop final slash 386 sb.append(':'); 387 } 388 389 // type 390 sb.append(type.name()); 391 return sb.toString(); 392 } 393 }