|
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 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 } |