|
Lines 33-39
Link Here
|
| 33 |
import java.util.Enumeration; |
33 |
import java.util.Enumeration; |
| 34 |
import java.util.HashMap; |
34 |
import java.util.HashMap; |
| 35 |
import java.util.HashSet; |
35 |
import java.util.HashSet; |
| 36 |
import java.util.Hashtable; |
|
|
| 37 |
import java.util.List; |
36 |
import java.util.List; |
| 38 |
import java.util.Map; |
37 |
import java.util.Map; |
| 39 |
import java.util.Set; |
38 |
import java.util.Set; |
|
Lines 48-59
Link Here
|
| 48 |
* </ul> |
47 |
* </ul> |
| 49 |
* |
48 |
* |
| 50 |
* @ThreadSafe |
49 |
* @ThreadSafe |
| 51 |
* @version $Id: 11e47883a0c36de7cd69d0436287d41f8bd30f17 $ |
50 |
* @version $Id: 4017ce21a422bbf0d4a9d0f192104eced96bec30 $ |
| 52 |
* @since 1.6 |
51 |
* @since 1.6 |
| 53 |
*/ |
52 |
*/ |
| 54 |
|
53 |
|
| 55 |
public final class CapabilityPermission extends BasicPermission { |
54 |
public final class CapabilityPermission extends BasicPermission { |
| 56 |
static final long serialVersionUID = -7662148639076511574L; |
55 |
static final long serialVersionUID = -7662148639076511574L; |
| 57 |
/** |
56 |
/** |
| 58 |
* The action string {@code require}. |
57 |
* The action string {@code require}. |
| 59 |
*/ |
58 |
*/ |
|
Lines 63-123
Link Here
|
| 63 |
*/ |
62 |
*/ |
| 64 |
public final static String PROVIDE = "provide"; |
63 |
public final static String PROVIDE = "provide"; |
| 65 |
|
64 |
|
| 66 |
private final static int ACTION_REQUIRE = 0x00000001; |
65 |
private final static int ACTION_REQUIRE = 0x00000001; |
| 67 |
private final static int ACTION_PROVIDE = 0x00000002; |
66 |
private final static int ACTION_PROVIDE = 0x00000002; |
| 68 |
private final static int ACTION_ALL = ACTION_REQUIRE |
67 |
private final static int ACTION_ALL = ACTION_REQUIRE |
| 69 |
| ACTION_PROVIDE; |
68 |
| ACTION_PROVIDE; |
| 70 |
final static int ACTION_NONE = 0; |
69 |
final static int ACTION_NONE = 0; |
| 71 |
|
70 |
|
| 72 |
/** |
71 |
/** |
| 73 |
* The actions mask. |
72 |
* The actions mask. |
| 74 |
*/ |
73 |
*/ |
| 75 |
transient int action_mask; |
74 |
transient int action_mask; |
| 76 |
|
75 |
|
| 77 |
/** |
76 |
/** |
| 78 |
* The actions in canonical form. |
77 |
* The actions in canonical form. |
| 79 |
* |
78 |
* |
| 80 |
* @serial |
79 |
* @serial |
| 81 |
*/ |
80 |
*/ |
| 82 |
private volatile String actions = null; |
81 |
private volatile String actions = null; |
| 83 |
|
82 |
|
| 84 |
/** |
83 |
/** |
| 85 |
* The service used by this ServicePermission. Must be null if not |
84 |
* The attributes of the requested capability. Must be null if not |
| 86 |
* constructed with a service. |
85 |
* constructed with attributes. |
| 87 |
*/ |
86 |
*/ |
| 88 |
transient final ServiceReference< ? > service; |
87 |
transient final Map<String, Object> attributes; |
| 89 |
|
88 |
|
| 90 |
/** |
89 |
/** |
| 91 |
* The object classes for this ServicePermission. Must be null if not |
90 |
* The bundle of the requested capability. Must be null if not constructed |
| 92 |
* constructed with a service. |
91 |
* with bundle. |
| 93 |
*/ |
92 |
*/ |
| 94 |
transient final String[] objectClass; |
93 |
transient final Bundle bundle; |
| 95 |
|
94 |
|
| 96 |
/** |
95 |
/** |
| 97 |
* If this ServicePermission was constructed with a filter, this holds a |
96 |
* If this CapabilityPermission was constructed with a filter, this holds a |
| 98 |
* Filter matching object used to evaluate the filter in implies. |
97 |
* Filter matching object used to evaluate the filter in implies. |
| 99 |
*/ |
98 |
*/ |
| 100 |
transient Filter filter; |
99 |
transient Filter filter; |
| 101 |
|
100 |
|
| 102 |
/** |
101 |
/** |
| 103 |
* This dictionary holds the properties of the permission, used to match a |
102 |
* This map holds the properties of the permission, used to match a filter |
| 104 |
* filter in implies. This is not initialized until necessary, and then |
103 |
* in implies. This is not initialized until necessary, and then cached in |
| 105 |
* cached in this object. |
104 |
* this object. |
| 106 |
*/ |
105 |
*/ |
| 107 |
private transient volatile Map<String, Object> properties; |
106 |
private transient volatile Map<String, Object> properties; |
| 108 |
|
107 |
|
| 109 |
/** |
108 |
/** |
| 110 |
* True if constructed with a name and the name is "*" or ends with ".*". |
|
|
| 111 |
*/ |
| 112 |
private transient boolean wildcard; |
| 113 |
|
| 114 |
/** |
| 115 |
* If constructed with a name and the name ends with ".*", this contains the |
| 116 |
* name without the final "*". |
| 117 |
*/ |
| 118 |
private transient String prefix; |
| 119 |
|
| 120 |
/** |
| 121 |
* Create a new CapabilityPermission. |
109 |
* Create a new CapabilityPermission. |
| 122 |
* |
110 |
* |
| 123 |
* <p> |
111 |
* <p> |
|
Lines 187-235
Link Here
|
| 187 |
* @param providingBundle The bundle providing the requested capability. |
175 |
* @param providingBundle The bundle providing the requested capability. |
| 188 |
* @param actions The action {@code require}. |
176 |
* @param actions The action {@code require}. |
| 189 |
* @throws IllegalArgumentException If the specified action is not |
177 |
* @throws IllegalArgumentException If the specified action is not |
| 190 |
* {@code require} or any parameters are {@code null}. |
178 |
* {@code require} or attributes or providingBundle are {@code null} |
|
|
179 |
* . |
| 191 |
*/ |
180 |
*/ |
| 192 |
public CapabilityPermission(String namespace, Map<String, ? > attributes, |
181 |
public CapabilityPermission(String namespace, Map<String, ? > attributes, |
| 193 |
Bundle providingBundle, String actions) { |
182 |
Bundle providingBundle, String actions) { |
| 194 |
super(namespace); |
183 |
super(namespace); |
| 195 |
this.objectClass = null; |
184 |
setTransients(namespace, parseActions(actions)); |
| 196 |
this.service = null; |
185 |
if (attributes == null) { |
| 197 |
// setTransients(null, parseActions(actions)); |
186 |
throw new IllegalArgumentException("attributes must not be null"); |
| 198 |
// this.service = reference; |
187 |
} |
| 199 |
// this.objectClass = (String[]) reference |
188 |
if (providingBundle == null) { |
| 200 |
// .getProperty(Constants.OBJECTCLASS); |
189 |
throw new IllegalArgumentException("bundle must not be null"); |
|
|
190 |
} |
| 191 |
this.attributes = new HashMap<String, Object>(attributes); |
| 192 |
this.bundle = providingBundle; |
| 201 |
if ((action_mask & ACTION_ALL) != ACTION_REQUIRE) { |
193 |
if ((action_mask & ACTION_ALL) != ACTION_REQUIRE) { |
| 202 |
throw new IllegalArgumentException("invalid action string"); |
194 |
throw new IllegalArgumentException("invalid action string"); |
| 203 |
} |
195 |
} |
| 204 |
} |
196 |
} |
| 205 |
|
197 |
|
| 206 |
/** |
198 |
/** |
| 207 |
* Create a permission name from a ServiceReference |
199 |
* Package private constructor used by CapabilityPermissionCollection. |
| 208 |
* |
|
|
| 209 |
* @param reference ServiceReference to use to create permission name. |
| 210 |
* @return permission name. |
| 211 |
*/ |
| 212 |
private static String createName(ServiceReference< ? > reference) { |
| 213 |
if (reference == null) { |
| 214 |
throw new IllegalArgumentException("reference must not be null"); |
| 215 |
} |
| 216 |
StringBuffer sb = new StringBuffer("(service.id="); |
| 217 |
sb.append(reference.getProperty(Constants.SERVICE_ID)); |
| 218 |
sb.append(")"); |
| 219 |
return sb.toString(); |
| 220 |
} |
| 221 |
|
| 222 |
/** |
| 223 |
* Package private constructor used by ServicePermissionCollection. |
| 224 |
* |
200 |
* |
| 225 |
* @param name class name |
201 |
* @param name class name |
| 226 |
* @param mask action mask |
202 |
* @param mask action mask |
| 227 |
*/ |
203 |
*/ |
| 228 |
CapabilityPermission(String name, int mask) { |
204 |
CapabilityPermission(String name, int mask) { |
| 229 |
super(name); |
205 |
super(name); |
| 230 |
setTransients(parseFilter(name), mask); |
206 |
setTransients(name, mask); |
| 231 |
this.service = null; |
207 |
this.attributes = null; |
| 232 |
this.objectClass = null; |
208 |
this.bundle = null; |
| 233 |
} |
209 |
} |
| 234 |
|
210 |
|
| 235 |
/** |
211 |
/** |
|
Lines 237-258
Link Here
|
| 237 |
* |
213 |
* |
| 238 |
* @param mask action mask |
214 |
* @param mask action mask |
| 239 |
*/ |
215 |
*/ |
| 240 |
private void setTransients(Filter f, int mask) { |
216 |
private void setTransients(String name, int mask) { |
| 241 |
if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { |
217 |
if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { |
| 242 |
throw new IllegalArgumentException("invalid action string"); |
218 |
throw new IllegalArgumentException("invalid action string"); |
| 243 |
} |
219 |
} |
| 244 |
action_mask = mask; |
220 |
action_mask = mask; |
| 245 |
filter = f; |
221 |
filter = parseFilter(name); |
| 246 |
if (f == null) { |
|
|
| 247 |
String name = getName(); |
| 248 |
int l = name.length(); |
| 249 |
/* if "*" or endsWith ".*" */ |
| 250 |
wildcard = ((name.charAt(l - 1) == '*') && ((l == 1) || (name |
| 251 |
.charAt(l - 2) == '.'))); |
| 252 |
if (wildcard && (l > 1)) { |
| 253 |
prefix = name.substring(0, l - 1); |
| 254 |
} |
| 255 |
} |
| 256 |
} |
222 |
} |
| 257 |
|
223 |
|
| 258 |
/** |
224 |
/** |
|
Lines 288-312
Link Here
|
| 288 |
// check for the known strings |
254 |
// check for the known strings |
| 289 |
int matchlen; |
255 |
int matchlen; |
| 290 |
|
256 |
|
| 291 |
if (i >= 2 && (a[i - 2] == 'g' || a[i - 2] == 'G') |
257 |
if (i >= 6 && (a[i - 6] == 'r' || a[i - 6] == 'R') |
| 292 |
&& (a[i - 1] == 'e' || a[i - 1] == 'E') |
258 |
&& (a[i - 5] == 'e' || a[i - 5] == 'E') |
| 293 |
&& (a[i] == 't' || a[i] == 'T')) { |
259 |
&& (a[i - 4] == 'q' || a[i - 4] == 'Q') |
| 294 |
matchlen = 3; |
260 |
&& (a[i - 3] == 'u' || a[i - 3] == 'U') |
|
|
261 |
&& (a[i - 2] == 'i' || a[i - 2] == 'I') |
| 262 |
&& (a[i - 1] == 'r' || a[i - 1] == 'R') |
| 263 |
&& (a[i] == 'e' || a[i] == 'E')) { |
| 264 |
matchlen = 7; |
| 295 |
mask |= ACTION_REQUIRE; |
265 |
mask |= ACTION_REQUIRE; |
| 296 |
|
|
|
| 297 |
} |
266 |
} |
| 298 |
else |
267 |
else |
| 299 |
if (i >= 7 && (a[i - 7] == 'r' || a[i - 7] == 'R') |
268 |
if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P') |
| 300 |
&& (a[i - 6] == 'e' || a[i - 6] == 'E') |
269 |
&& (a[i - 5] == 'r' || a[i - 5] == 'R') |
| 301 |
&& (a[i - 5] == 'g' || a[i - 5] == 'G') |
270 |
&& (a[i - 4] == 'o' || a[i - 4] == 'O') |
| 302 |
&& (a[i - 4] == 'i' || a[i - 4] == 'I') |
271 |
&& (a[i - 3] == 'v' || a[i - 3] == 'V') |
| 303 |
&& (a[i - 3] == 's' || a[i - 3] == 'S') |
272 |
&& (a[i - 2] == 'i' || a[i - 2] == 'I') |
| 304 |
&& (a[i - 2] == 't' || a[i - 2] == 'T') |
273 |
&& (a[i - 1] == 'd' || a[i - 1] == 'D') |
| 305 |
&& (a[i - 1] == 'e' || a[i - 1] == 'E') |
274 |
&& (a[i] == 'e' || a[i] == 'E')) { |
| 306 |
&& (a[i] == 'r' || a[i] == 'R')) { |
275 |
matchlen = 7; |
| 307 |
matchlen = 8; |
|
|
| 308 |
mask |= ACTION_PROVIDE; |
276 |
mask |= ACTION_PROVIDE; |
| 309 |
|
|
|
| 310 |
} |
277 |
} |
| 311 |
else { |
278 |
else { |
| 312 |
// parse error |
279 |
// parse error |
|
Lines 315-327
Link Here
|
| 315 |
} |
282 |
} |
| 316 |
|
283 |
|
| 317 |
// make sure we didn't just match the tail of a word |
284 |
// make sure we didn't just match the tail of a word |
| 318 |
// like "ackbarfregister". Also, skip to the comma. |
285 |
// like "ackbarfprovide". Also, skip to the comma. |
| 319 |
seencomma = false; |
286 |
seencomma = false; |
| 320 |
while (i >= matchlen && !seencomma) { |
287 |
while (i >= matchlen && !seencomma) { |
| 321 |
switch (a[i - matchlen]) { |
288 |
switch (a[i - matchlen]) { |
| 322 |
case ',' : |
289 |
case ',' : |
| 323 |
seencomma = true; |
290 |
seencomma = true; |
| 324 |
/* FALLTHROUGH */ |
291 |
/* FALLTHROUGH */ |
| 325 |
case ' ' : |
292 |
case ' ' : |
| 326 |
case '\r' : |
293 |
case '\r' : |
| 327 |
case '\n' : |
294 |
case '\n' : |
|
Lines 384-390
Link Here
|
| 384 |
return false; |
351 |
return false; |
| 385 |
} |
352 |
} |
| 386 |
CapabilityPermission requested = (CapabilityPermission) p; |
353 |
CapabilityPermission requested = (CapabilityPermission) p; |
| 387 |
if (service != null) { |
354 |
if (bundle != null) { |
| 388 |
return false; |
355 |
return false; |
| 389 |
} |
356 |
} |
| 390 |
// if requested permission has a filter, then it is an invalid argument |
357 |
// if requested permission has a filter, then it is an invalid argument |
|
Lines 398-405
Link Here
|
| 398 |
* Internal implies method. Used by the implies and the permission |
365 |
* Internal implies method. Used by the implies and the permission |
| 399 |
* collection implies methods. |
366 |
* collection implies methods. |
| 400 |
* |
367 |
* |
| 401 |
* @param requested The requested ServicePermission which has already be |
368 |
* @param requested The requested CapabilityPermission which has already be |
| 402 |
* validated as a proper argument. The requested ServicePermission |
369 |
* validated as a proper argument. The requested CapabilityPermission |
| 403 |
* must not have a filter expression. |
370 |
* must not have a filter expression. |
| 404 |
* @param effective The effective actions with which to start. |
371 |
* @param effective The effective actions with which to start. |
| 405 |
* @return {@code true} if the specified permission is implied by this |
372 |
* @return {@code true} if the specified permission is implied by this |
|
Lines 412-451
Link Here
|
| 412 |
if ((effective & desired) != desired) { |
379 |
if ((effective & desired) != desired) { |
| 413 |
return false; |
380 |
return false; |
| 414 |
} |
381 |
} |
| 415 |
/* we have name of "*" */ |
382 |
/* Get filter if any */ |
| 416 |
if (wildcard && (prefix == null)) { |
|
|
| 417 |
return true; |
| 418 |
} |
| 419 |
/* if we have a filter */ |
| 420 |
Filter f = filter; |
383 |
Filter f = filter; |
| 421 |
if (f != null) { |
384 |
if (f == null) { |
| 422 |
return f.matches(requested.getProperties()); |
|
|
| 423 |
} |
| 424 |
/* if requested permission not created with ServiceReference */ |
| 425 |
String[] requestedNames = requested.objectClass; |
| 426 |
if (requestedNames == null) { |
| 427 |
return super.implies(requested); |
385 |
return super.implies(requested); |
| 428 |
} |
386 |
} |
| 429 |
/* requested permission created with ServiceReference */ |
387 |
return f.matches(requested.getProperties()); |
| 430 |
if (wildcard) { |
|
|
| 431 |
int pl = prefix.length(); |
| 432 |
for (int i = 0, l = requestedNames.length; i < l; i++) { |
| 433 |
String requestedName = requestedNames[i]; |
| 434 |
if ((requestedName.length() > pl) |
| 435 |
&& requestedName.startsWith(prefix)) { |
| 436 |
return true; |
| 437 |
} |
| 438 |
} |
| 439 |
} |
| 440 |
else { |
| 441 |
String name = getName(); |
| 442 |
for (int i = 0, l = requestedNames.length; i < l; i++) { |
| 443 |
if (requestedNames[i].equals(name)) { |
| 444 |
return true; |
| 445 |
} |
| 446 |
} |
| 447 |
} |
| 448 |
return false; |
| 449 |
} |
388 |
} |
| 450 |
|
389 |
|
| 451 |
/** |
390 |
/** |
|
Lines 510-521
Link Here
|
| 510 |
return false; |
449 |
return false; |
| 511 |
} |
450 |
} |
| 512 |
|
451 |
|
| 513 |
CapabilityPermission sp = (CapabilityPermission) obj; |
452 |
CapabilityPermission cp = (CapabilityPermission) obj; |
| 514 |
|
453 |
|
| 515 |
return (action_mask == sp.action_mask) |
454 |
return (action_mask == cp.action_mask) |
| 516 |
&& getName().equals(sp.getName()) |
455 |
&& getName().equals(cp.getName()) |
| 517 |
&& ((service == sp.service) || ((service != null) && (service |
456 |
&& ((attributes == cp.attributes) || ((attributes != null) && (attributes |
| 518 |
.compareTo(sp.service) == 0))); |
457 |
.equals(cp.attributes)))) |
|
|
458 |
&& ((bundle == cp.bundle) || ((bundle != null) && bundle |
| 459 |
.equals(cp.bundle))); |
| 519 |
} |
460 |
} |
| 520 |
|
461 |
|
| 521 |
/** |
462 |
/** |
|
Lines 526-533
Link Here
|
| 526 |
public int hashCode() { |
467 |
public int hashCode() { |
| 527 |
int h = 31 * 17 + getName().hashCode(); |
468 |
int h = 31 * 17 + getName().hashCode(); |
| 528 |
h = 31 * h + getActions().hashCode(); |
469 |
h = 31 * h + getActions().hashCode(); |
| 529 |
if (service != null) { |
470 |
if (attributes != null) { |
| 530 |
h = 31 * h + service.hashCode(); |
471 |
h = 31 * h + attributes.hashCode(); |
|
|
472 |
} |
| 473 |
if (bundle != null) { |
| 474 |
h = 31 * h + bundle.hashCode(); |
| 531 |
} |
475 |
} |
| 532 |
return h; |
476 |
return h; |
| 533 |
} |
477 |
} |
|
Lines 538-544
Link Here
|
| 538 |
*/ |
482 |
*/ |
| 539 |
private synchronized void writeObject(java.io.ObjectOutputStream s) |
483 |
private synchronized void writeObject(java.io.ObjectOutputStream s) |
| 540 |
throws IOException { |
484 |
throws IOException { |
| 541 |
if (service != null) { |
485 |
if (bundle != null) { |
| 542 |
throw new NotSerializableException("cannot serialize"); |
486 |
throw new NotSerializableException("cannot serialize"); |
| 543 |
} |
487 |
} |
| 544 |
// Write out the actions. The superclass takes care of the name |
488 |
// Write out the actions. The superclass takes care of the name |
|
Lines 556-610
Link Here
|
| 556 |
throws IOException, ClassNotFoundException { |
500 |
throws IOException, ClassNotFoundException { |
| 557 |
// Read in the action, then initialize the rest |
501 |
// Read in the action, then initialize the rest |
| 558 |
s.defaultReadObject(); |
502 |
s.defaultReadObject(); |
| 559 |
setTransients(parseFilter(getName()), parseActions(actions)); |
503 |
setTransients(getName(), parseActions(actions)); |
| 560 |
} |
504 |
} |
|
|
505 |
|
| 561 |
/** |
506 |
/** |
| 562 |
* Called by {@code <@link ServicePermission#implies(Permission)>}. |
507 |
* Called by {@code <@link CapabilityPermission#implies(Permission)>}. This |
|
|
508 |
* method is only called on a requested permission which cannot have a |
| 509 |
* filter set. |
| 563 |
* |
510 |
* |
| 564 |
* @return a dictionary of properties for this permission. |
511 |
* @return a map of properties for this permission. |
| 565 |
*/ |
512 |
*/ |
| 566 |
private Map<String, Object> getProperties() { |
513 |
private Map<String, Object> getProperties() { |
| 567 |
Map<String, Object> result = properties; |
514 |
Map<String, Object> result = properties; |
| 568 |
if (result != null) { |
515 |
if (result != null) { |
| 569 |
return result; |
516 |
return result; |
| 570 |
} |
517 |
} |
| 571 |
if (service == null) { |
518 |
final Map<String, Object> props = new HashMap<String, Object>(5); |
| 572 |
result = new HashMap<String, Object>(1); |
519 |
props.put("capability.namespace", getName()); |
| 573 |
if (filter == null) { |
520 |
if (bundle == null) { |
| 574 |
result.put(Constants.OBJECTCLASS, new String[] {getName()}); |
521 |
return properties = props; |
| 575 |
} |
522 |
} |
| 576 |
return properties = result; |
523 |
AccessController.doPrivileged(new PrivilegedAction<Object>() { |
| 577 |
} |
524 |
public Object run() { |
| 578 |
final Map<String, Object> props = new HashMap<String, Object>(4); |
525 |
props.put("id", new Long(bundle.getBundleId())); |
| 579 |
final Bundle bundle = service.getBundle(); |
526 |
props.put("location", bundle.getLocation()); |
| 580 |
if (bundle != null) { |
527 |
String name = bundle.getSymbolicName(); |
| 581 |
AccessController.doPrivileged(new PrivilegedAction<Object>() { |
528 |
if (name != null) { |
| 582 |
public Object run() { |
529 |
props.put("name", name); |
| 583 |
props.put("id", new Long(bundle.getBundleId())); |
530 |
} |
| 584 |
props.put("location", bundle.getLocation()); |
531 |
SignerProperty signer = new SignerProperty(bundle); |
| 585 |
String name = bundle.getSymbolicName(); |
532 |
if (signer.isBundleSigned()) { |
| 586 |
if (name != null) { |
533 |
props.put("signer", signer); |
| 587 |
props.put("name", name); |
|
|
| 588 |
} |
| 589 |
SignerProperty signer = new SignerProperty(bundle); |
| 590 |
if (signer.isBundleSigned()) { |
| 591 |
props.put("signer", signer); |
| 592 |
} |
| 593 |
return null; |
| 594 |
} |
534 |
} |
| 595 |
}); |
535 |
return null; |
| 596 |
} |
536 |
} |
| 597 |
return properties = new Properties(props, service); |
537 |
}); |
|
|
538 |
return properties = new Properties(props, attributes); |
| 598 |
} |
539 |
} |
| 599 |
|
540 |
|
| 600 |
private static class Properties extends AbstractMap<String, Object> { |
541 |
private static class Properties extends AbstractMap<String, Object> { |
| 601 |
private final Map<String, Object> properties; |
542 |
private final Map<String, Object> properties; |
| 602 |
private final ServiceReference< ? > service; |
543 |
private final Map<String, Object> attributes; |
| 603 |
private transient volatile Set<Map.Entry<String, Object>> entries; |
544 |
private transient volatile Set<Map.Entry<String, Object>> entries; |
| 604 |
|
545 |
|
| 605 |
Properties(Map<String, Object> properties, ServiceReference< ? > service) { |
546 |
Properties(Map<String, Object> properties, |
|
|
547 |
Map<String, Object> attributes) { |
| 606 |
this.properties = properties; |
548 |
this.properties = properties; |
| 607 |
this.service = service; |
549 |
this.attributes = attributes; |
| 608 |
entries = null; |
550 |
entries = null; |
| 609 |
} |
551 |
} |
| 610 |
|
552 |
|
|
Lines 614-626
Link Here
|
| 614 |
} |
556 |
} |
| 615 |
String key = (String) k; |
557 |
String key = (String) k; |
| 616 |
if (key.charAt(0) == '@') { |
558 |
if (key.charAt(0) == '@') { |
| 617 |
return service.getProperty(key.substring(1)); |
559 |
return attributes.get(key.substring(1)); |
| 618 |
} |
560 |
} |
| 619 |
Object value = properties.get(key); |
561 |
Object value = properties.get(key); |
| 620 |
if (value != null) { // fall back to service properties |
562 |
if (value != null) { // fall back to service properties |
| 621 |
return value; |
563 |
return value; |
| 622 |
} |
564 |
} |
| 623 |
return service.getProperty(key); |
565 |
return attributes.get(key); |
| 624 |
} |
566 |
} |
| 625 |
|
567 |
|
| 626 |
public Set<Map.Entry<String, Object>> entrySet() { |
568 |
public Set<Map.Entry<String, Object>> entrySet() { |
|
Lines 628-705
Link Here
|
| 628 |
return entries; |
570 |
return entries; |
| 629 |
} |
571 |
} |
| 630 |
Set<Map.Entry<String, Object>> all = new HashSet<Map.Entry<String, Object>>( |
572 |
Set<Map.Entry<String, Object>> all = new HashSet<Map.Entry<String, Object>>( |
| 631 |
properties.entrySet()); |
573 |
attributes.size() + properties.size()); |
| 632 |
add: for (String key : service.getPropertyKeys()) { |
574 |
all.addAll(attributes.entrySet()); |
| 633 |
for (String k : properties.keySet()) { |
575 |
all.addAll(properties.entrySet()); |
| 634 |
if (key.equalsIgnoreCase(k)) { |
|
|
| 635 |
continue add; |
| 636 |
} |
| 637 |
} |
| 638 |
all.add(new Entry(key, service.getProperty(key))); |
| 639 |
} |
| 640 |
return entries = Collections.unmodifiableSet(all); |
576 |
return entries = Collections.unmodifiableSet(all); |
| 641 |
} |
577 |
} |
| 642 |
|
|
|
| 643 |
private static class Entry implements Map.Entry<String, Object> { |
| 644 |
private final String k; |
| 645 |
private final Object v; |
| 646 |
|
| 647 |
Entry(String key, Object value) { |
| 648 |
this.k = key; |
| 649 |
this.v = value; |
| 650 |
} |
| 651 |
public String getKey() { |
| 652 |
return k; |
| 653 |
} |
| 654 |
public Object getValue() { |
| 655 |
return v; |
| 656 |
} |
| 657 |
public Object setValue(Object value) { |
| 658 |
throw new UnsupportedOperationException(); |
| 659 |
} |
| 660 |
public String toString() { |
| 661 |
return k + "=" + v; |
| 662 |
} |
| 663 |
public int hashCode() { |
| 664 |
return ((k == null) ? 0 : k.hashCode()) |
| 665 |
^ ((v == null) ? 0 : v.hashCode()); |
| 666 |
} |
| 667 |
public boolean equals(Object obj) { |
| 668 |
if (obj == this) { |
| 669 |
return true; |
| 670 |
} |
| 671 |
if (!(obj instanceof Map.Entry)) { |
| 672 |
return false; |
| 673 |
} |
| 674 |
Map.Entry< ? , ? > e = (Map.Entry< ? , ? >) obj; |
| 675 |
final Object key = e.getKey(); |
| 676 |
if ((k == key) || ((k != null) && k.equals(key))) { |
| 677 |
final Object value = e.getValue(); |
| 678 |
if ((v == value) || ((v != null) && v.equals(value))) { |
| 679 |
return true; |
| 680 |
} |
| 681 |
} |
| 682 |
return false; |
| 683 |
} |
| 684 |
} |
| 685 |
} |
578 |
} |
| 686 |
} |
579 |
} |
| 687 |
|
580 |
|
| 688 |
/** |
581 |
/** |
| 689 |
* Stores a set of ServicePermission permissions. |
582 |
* Stores a set of CapabilityPermission permissions. |
| 690 |
* |
583 |
* |
| 691 |
* @see java.security.Permission |
584 |
* @see java.security.Permission |
| 692 |
* @see java.security.Permissions |
585 |
* @see java.security.Permissions |
| 693 |
* @see java.security.PermissionCollection |
586 |
* @see java.security.PermissionCollection |
| 694 |
*/ |
587 |
*/ |
| 695 |
final class CapabilityPermissionCollection extends PermissionCollection { |
588 |
final class CapabilityPermissionCollection extends PermissionCollection { |
| 696 |
static final long serialVersionUID = 662615640374640621L; |
589 |
static final long serialVersionUID = -615322242639008920L; |
|
|
590 |
|
| 697 |
/** |
591 |
/** |
| 698 |
* Table of permissions. |
592 |
* Table of permissions. |
| 699 |
* |
593 |
* |
|
|
594 |
* @serial |
| 700 |
* @GuardedBy this |
595 |
* @GuardedBy this |
| 701 |
*/ |
596 |
*/ |
| 702 |
private transient Map<String, CapabilityPermission> permissions; |
597 |
private Map<String, CapabilityPermission> permissions; |
| 703 |
|
598 |
|
| 704 |
/** |
599 |
/** |
| 705 |
* Boolean saying if "*" is in the collection. |
600 |
* Boolean saying if "*" is in the collection. |
|
Lines 707-713
Link Here
|
| 707 |
* @serial |
602 |
* @serial |
| 708 |
* @GuardedBy this |
603 |
* @GuardedBy this |
| 709 |
*/ |
604 |
*/ |
| 710 |
private boolean all_allowed; |
605 |
private boolean all_allowed; |
| 711 |
|
606 |
|
| 712 |
/** |
607 |
/** |
| 713 |
* Table of permissions with filter expressions. |
608 |
* Table of permissions with filter expressions. |
|
Lines 715-721
Link Here
|
| 715 |
* @serial |
610 |
* @serial |
| 716 |
* @GuardedBy this |
611 |
* @GuardedBy this |
| 717 |
*/ |
612 |
*/ |
| 718 |
private Map<String, CapabilityPermission> filterPermissions; |
613 |
private Map<String, CapabilityPermission> filterPermissions; |
| 719 |
|
614 |
|
| 720 |
/** |
615 |
/** |
| 721 |
* Creates an empty CapabilityPermissionCollection object. |
616 |
* Creates an empty CapabilityPermissionCollection object. |
|
Lines 730-739
Link Here
|
| 730 |
* |
625 |
* |
| 731 |
* @param permission The Permission object to add. |
626 |
* @param permission The Permission object to add. |
| 732 |
* @throws IllegalArgumentException If the specified permission is not a |
627 |
* @throws IllegalArgumentException If the specified permission is not a |
| 733 |
* ServicePermission object. |
628 |
* CapabilityPermission object. |
| 734 |
* @throws SecurityException If this |
629 |
* @throws SecurityException If this {@code CapabilityPermissionCollection} |
| 735 |
* {@code ServicePermissionCollection} object has been marked |
630 |
* object has been marked read-only. |
| 736 |
* read-only. |
|
|
| 737 |
*/ |
631 |
*/ |
| 738 |
public void add(final Permission permission) { |
632 |
public void add(final Permission permission) { |
| 739 |
if (!(permission instanceof CapabilityPermission)) { |
633 |
if (!(permission instanceof CapabilityPermission)) { |
|
Lines 745-758
Link Here
|
| 745 |
+ "readonly PermissionCollection"); |
639 |
+ "readonly PermissionCollection"); |
| 746 |
} |
640 |
} |
| 747 |
|
641 |
|
| 748 |
final CapabilityPermission sp = (CapabilityPermission) permission; |
642 |
final CapabilityPermission cp = (CapabilityPermission) permission; |
| 749 |
if (sp.service != null) { |
643 |
if (cp.bundle != null) { |
| 750 |
throw new IllegalArgumentException("cannot add to collection: " |
644 |
throw new IllegalArgumentException("cannot add to collection: " |
| 751 |
+ sp); |
645 |
+ cp); |
| 752 |
} |
646 |
} |
| 753 |
|
647 |
|
| 754 |
final String name = sp.getName(); |
648 |
final String name = cp.getName(); |
| 755 |
final Filter f = sp.filter; |
649 |
final Filter f = cp.filter; |
| 756 |
synchronized (this) { |
650 |
synchronized (this) { |
| 757 |
/* select the bucket for the permission */ |
651 |
/* select the bucket for the permission */ |
| 758 |
Map<String, CapabilityPermission> pc; |
652 |
Map<String, CapabilityPermission> pc; |
|
Lines 766-785
Link Here
|
| 766 |
pc = permissions; |
660 |
pc = permissions; |
| 767 |
} |
661 |
} |
| 768 |
final CapabilityPermission existing = pc.get(name); |
662 |
final CapabilityPermission existing = pc.get(name); |
| 769 |
|
663 |
|
| 770 |
if (existing != null) { |
664 |
if (existing != null) { |
| 771 |
final int oldMask = existing.action_mask; |
665 |
final int oldMask = existing.action_mask; |
| 772 |
final int newMask = sp.action_mask; |
666 |
final int newMask = cp.action_mask; |
| 773 |
if (oldMask != newMask) { |
667 |
if (oldMask != newMask) { |
| 774 |
pc |
668 |
pc.put(name, new CapabilityPermission(name, oldMask |
| 775 |
.put(name, new CapabilityPermission(name, oldMask |
|
|
| 776 |
| newMask)); |
669 |
| newMask)); |
| 777 |
} |
670 |
} |
| 778 |
} |
671 |
} |
| 779 |
else { |
672 |
else { |
| 780 |
pc.put(name, sp); |
673 |
pc.put(name, cp); |
| 781 |
} |
674 |
} |
| 782 |
|
675 |
|
| 783 |
if (!all_allowed) { |
676 |
if (!all_allowed) { |
| 784 |
if (name.equals("*")) { |
677 |
if (name.equals("*")) { |
| 785 |
all_allowed = true; |
678 |
all_allowed = true; |
|
Lines 793-801
Link Here
|
| 793 |
* {@code permission}. |
686 |
* {@code permission}. |
| 794 |
* |
687 |
* |
| 795 |
* @param permission The Permission object to compare. |
688 |
* @param permission The Permission object to compare. |
| 796 |
* @return {@code true} if {@code permission} is a proper |
689 |
* @return {@code true} if {@code permission} is a proper subset of a |
| 797 |
* subset of a permission in the set; {@code false} |
690 |
* permission in the set; {@code false} otherwise. |
| 798 |
* otherwise. |
|
|
| 799 |
*/ |
691 |
*/ |
| 800 |
public boolean implies(final Permission permission) { |
692 |
public boolean implies(final Permission permission) { |
| 801 |
if (!(permission instanceof CapabilityPermission)) { |
693 |
if (!(permission instanceof CapabilityPermission)) { |
|
Lines 807-850
Link Here
|
| 807 |
return false; |
699 |
return false; |
| 808 |
} |
700 |
} |
| 809 |
|
701 |
|
|
|
702 |
String requestedName = requested.getName(); |
| 703 |
final int desired = requested.action_mask; |
| 810 |
int effective = CapabilityPermission.ACTION_NONE; |
704 |
int effective = CapabilityPermission.ACTION_NONE; |
|
|
705 |
|
| 811 |
Collection<CapabilityPermission> perms; |
706 |
Collection<CapabilityPermission> perms; |
| 812 |
synchronized (this) { |
707 |
synchronized (this) { |
| 813 |
final int desired = requested.action_mask; |
708 |
Map<String, CapabilityPermission> pc = permissions; |
|
|
709 |
CapabilityPermission cp; |
| 814 |
/* short circuit if the "*" Permission was added */ |
710 |
/* short circuit if the "*" Permission was added */ |
| 815 |
if (all_allowed) { |
711 |
if (all_allowed) { |
| 816 |
CapabilityPermission sp = permissions.get("*"); |
712 |
cp = pc.get("*"); |
| 817 |
if (sp != null) { |
713 |
if (cp != null) { |
| 818 |
effective |= sp.action_mask; |
714 |
effective |= cp.action_mask; |
| 819 |
if ((effective & desired) == desired) { |
715 |
if ((effective & desired) == desired) { |
| 820 |
return true; |
716 |
return true; |
| 821 |
} |
717 |
} |
| 822 |
} |
718 |
} |
| 823 |
} |
719 |
} |
| 824 |
|
720 |
|
| 825 |
String[] requestedNames = requested.objectClass; |
721 |
/* |
| 826 |
/* if requested permission not created with ServiceReference */ |
722 |
* strategy: Check for full match first. Then work our way up the |
| 827 |
if (requestedNames == null) { |
723 |
* name looking for matches on a.b.* |
| 828 |
effective |= effective(requested.getName(), desired, effective); |
724 |
*/ |
|
|
725 |
cp = pc.get(requestedName); |
| 726 |
if (cp != null) { |
| 727 |
/* we have a direct hit! */ |
| 728 |
effective |= cp.action_mask; |
| 829 |
if ((effective & desired) == desired) { |
729 |
if ((effective & desired) == desired) { |
| 830 |
return true; |
730 |
return true; |
| 831 |
} |
731 |
} |
| 832 |
} |
732 |
} |
| 833 |
/* requested permission created with ServiceReference */ |
733 |
/* work our way up the tree... */ |
| 834 |
else { |
734 |
int last; |
| 835 |
for (int i = 0, l = requestedNames.length; i < l; i++) { |
735 |
int offset = requestedName.length() - 1; |
| 836 |
if ((effective(requestedNames[i], desired, effective) & desired) == desired) { |
736 |
while ((last = requestedName.lastIndexOf(".", offset)) != -1) { |
|
|
737 |
requestedName = requestedName.substring(0, last + 1) + "*"; |
| 738 |
cp = pc.get(requestedName); |
| 739 |
if (cp != null) { |
| 740 |
effective |= cp.action_mask; |
| 741 |
if ((effective & desired) == desired) { |
| 837 |
return true; |
742 |
return true; |
| 838 |
} |
743 |
} |
| 839 |
} |
744 |
} |
|
|
745 |
offset = last - 1; |
| 840 |
} |
746 |
} |
| 841 |
Map<String, CapabilityPermission> pc = filterPermissions; |
747 |
/* |
|
|
748 |
* we don't have to check for "*" as it was already checked before |
| 749 |
* we were called. |
| 750 |
*/ |
| 751 |
pc = filterPermissions; |
| 842 |
if (pc == null) { |
752 |
if (pc == null) { |
| 843 |
return false; |
753 |
return false; |
| 844 |
} |
754 |
} |
| 845 |
perms = pc.values(); |
755 |
perms = pc.values(); |
| 846 |
} |
756 |
} |
| 847 |
|
|
|
| 848 |
/* iterate one by one over filteredPermissions */ |
757 |
/* iterate one by one over filteredPermissions */ |
| 849 |
for (CapabilityPermission perm : perms) { |
758 |
for (CapabilityPermission perm : perms) { |
| 850 |
if (perm.implies0(requested, effective)) { |
759 |
if (perm.implies0(requested, effective)) { |
|
Lines 855-908
Link Here
|
| 855 |
} |
764 |
} |
| 856 |
|
765 |
|
| 857 |
/** |
766 |
/** |
| 858 |
* Consult permissions map to compute the effective permission for the |
767 |
* Returns an enumeration of all the {@code CapabilityPermission} objects in |
| 859 |
* requested permission name. |
768 |
* the container. |
| 860 |
* |
|
|
| 861 |
* @param requestedName The requested service name. |
| 862 |
* @param desired The desired actions. |
| 863 |
* @param effective The effective actions. |
| 864 |
* @return The new effective actions. |
| 865 |
*/ |
| 866 |
private int effective(String requestedName, final int desired, |
| 867 |
int effective) { |
| 868 |
final Map<String, CapabilityPermission> pc = permissions; |
| 869 |
CapabilityPermission sp = pc.get(requestedName); |
| 870 |
// strategy: |
| 871 |
// Check for full match first. Then work our way up the |
| 872 |
// name looking for matches on a.b.* |
| 873 |
if (sp != null) { |
| 874 |
// we have a direct hit! |
| 875 |
effective |= sp.action_mask; |
| 876 |
if ((effective & desired) == desired) { |
| 877 |
return effective; |
| 878 |
} |
| 879 |
} |
| 880 |
// work our way up the tree... |
| 881 |
int last; |
| 882 |
int offset = requestedName.length() - 1; |
| 883 |
while ((last = requestedName.lastIndexOf(".", offset)) != -1) { |
| 884 |
requestedName = requestedName.substring(0, last + 1) + "*"; |
| 885 |
sp = pc.get(requestedName); |
| 886 |
if (sp != null) { |
| 887 |
effective |= sp.action_mask; |
| 888 |
if ((effective & desired) == desired) { |
| 889 |
return effective; |
| 890 |
} |
| 891 |
} |
| 892 |
offset = last - 1; |
| 893 |
} |
| 894 |
/* |
| 895 |
* we don't have to check for "*" as it was already checked before we |
| 896 |
* were called. |
| 897 |
*/ |
| 898 |
return effective; |
| 899 |
} |
| 900 |
|
| 901 |
/** |
| 902 |
* Returns an enumeration of all the {@code ServicePermission} |
| 903 |
* objects in the container. |
| 904 |
* |
769 |
* |
| 905 |
* @return Enumeration of all the ServicePermission objects. |
770 |
* @return Enumeration of all the CapabilityPermission objects. |
| 906 |
*/ |
771 |
*/ |
| 907 |
public synchronized Enumeration<Permission> elements() { |
772 |
public synchronized Enumeration<Permission> elements() { |
| 908 |
List<Permission> all = new ArrayList<Permission>(permissions.values()); |
773 |
List<Permission> all = new ArrayList<Permission>(permissions.values()); |
|
Lines 912-930
Link Here
|
| 912 |
} |
777 |
} |
| 913 |
return Collections.enumeration(all); |
778 |
return Collections.enumeration(all); |
| 914 |
} |
779 |
} |
| 915 |
|
780 |
|
| 916 |
/* serialization logic */ |
781 |
/* serialization logic */ |
| 917 |
private static final ObjectStreamField[] serialPersistentFields = { |
782 |
private static final ObjectStreamField[] serialPersistentFields = { |
| 918 |
new ObjectStreamField("permissions", Hashtable.class), |
783 |
new ObjectStreamField("permissions", HashMap.class), |
| 919 |
new ObjectStreamField("all_allowed", Boolean.TYPE), |
784 |
new ObjectStreamField("all_allowed", Boolean.TYPE), |
| 920 |
new ObjectStreamField("filterPermissions", HashMap.class) }; |
785 |
new ObjectStreamField("filterPermissions", HashMap.class) }; |
| 921 |
|
786 |
|
| 922 |
private synchronized void writeObject(ObjectOutputStream out) |
787 |
private synchronized void writeObject(ObjectOutputStream out) |
| 923 |
throws IOException { |
788 |
throws IOException { |
| 924 |
Hashtable<String, CapabilityPermission> hashtable = new Hashtable<String, CapabilityPermission>( |
|
|
| 925 |
permissions); |
| 926 |
ObjectOutputStream.PutField pfields = out.putFields(); |
789 |
ObjectOutputStream.PutField pfields = out.putFields(); |
| 927 |
pfields.put("permissions", hashtable); |
790 |
pfields.put("permissions", permissions); |
| 928 |
pfields.put("all_allowed", all_allowed); |
791 |
pfields.put("all_allowed", all_allowed); |
| 929 |
pfields.put("filterPermissions", filterPermissions); |
792 |
pfields.put("filterPermissions", filterPermissions); |
| 930 |
out.writeFields(); |
793 |
out.writeFields(); |
|
Lines 933-941
Link Here
|
| 933 |
private synchronized void readObject(java.io.ObjectInputStream in) |
796 |
private synchronized void readObject(java.io.ObjectInputStream in) |
| 934 |
throws IOException, ClassNotFoundException { |
797 |
throws IOException, ClassNotFoundException { |
| 935 |
ObjectInputStream.GetField gfields = in.readFields(); |
798 |
ObjectInputStream.GetField gfields = in.readFields(); |
| 936 |
Hashtable<String, CapabilityPermission> hashtable = (Hashtable<String, CapabilityPermission>) gfields |
799 |
HashMap<String, CapabilityPermission> p = (HashMap<String, CapabilityPermission>) gfields |
| 937 |
.get("permissions", null); |
800 |
.get("permissions", null); |
| 938 |
permissions = new HashMap<String, CapabilityPermission>(hashtable); |
801 |
permissions = p; |
| 939 |
all_allowed = gfields.get("all_allowed", false); |
802 |
all_allowed = gfields.get("all_allowed", false); |
| 940 |
HashMap<String, CapabilityPermission> fp = (HashMap<String, CapabilityPermission>) gfields |
803 |
HashMap<String, CapabilityPermission> fp = (HashMap<String, CapabilityPermission>) gfields |
| 941 |
.get("filterPermissions", null); |
804 |
.get("filterPermissions", null); |