blob: 6512fe7c5347d3fd0402d83e1fa031a9e9ae4f86 [file] [log] [blame]
Richard S. Hall930fecc2005-08-16 18:33:34 +00001/*
2 * $Header: /cvshome/build/org.osgi.framework/src/org/osgi/framework/AdminPermission.java,v 1.12 2005/05/13 20:32:54 hargrave Exp $
3 *
4 * Copyright (c) OSGi Alliance (2000, 2005). All Rights Reserved.
5 *
6 * This program and the accompanying materials are made available under the
7 * terms of the Eclipse Public License v1.0 which accompanies this
8 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html.
9 */
10
11package org.osgi.framework;
12
13import java.io.IOException;
14import java.io.InputStream;
15import java.security.*;
16import java.util.*;
Richard S. Hall5a031592005-08-19 19:53:58 +000017import org.apache.felix.framework.FilterImpl;
Richard S. Hall930fecc2005-08-16 18:33:34 +000018
19/**
20 * Indicates the caller's authority to perform specific privileged administrative
21 * operations on or to get sensitive information about a bundle.
22 *
23 * <ul>
24 * <li>The <code>{@link AdminPermission#METADATA}</code> action allows calls to
25 * <ul>
26 * <li>{@link Bundle#getHeaders()}
27 * <li>{@link Bundle#getHeaders(String)}
28 * <li>{@link Bundle#getLocation()}
29 * </ul>
30 * <li>The <code>{@link AdminPermission#RESOURCE}</code> action allows calls to
31 * <ul>
32 * <li>{@link Bundle#getResource(String)}
33 * <li>{@link Bundle#getEntry(String)}
34 * <li>{@link Bundle#getEntryPaths(String)}
35 * <li>Bundle resource/entry URL creation
36 * </ul>
37 * <li>The <code>{@link AdminPermission#METADATA}</code> action allows calls to
38 * <ul>
39 * <li>{@link Bundle#loadClass(String)}
40 * </ul>
41 * <li>The <code>{@link AdminPermission#LIFECYCLE}</code> action allows calls to
42 * <ul>
43 * <li>{@link BundleContext#installBundle(String)}
44 * <li>{@link BundleContext#installBundle(String, InputStream)}
45 * <li>{@link Bundle#update()}
46 * <li>{@link Bundle#update(InputStream)}
47 * <li>{@link Bundle#uninstall()}
48 * </ul>
49 * <li>The <code>{@link AdminPermission#EXECUTE}</code> action allows calls to
50 * <ul>
51 * <li>{@link Bundle#start()}
52 * <li>{@link Bundle#stop()}
53 * <li>{@link org.osgi.service.startlevel.StartLevel#setBundleStartLevel(Bundle, int)}
54 * </ul>
55 * <li>The <code>{@link AdminPermission#LISTENER}</code> action allows calls to
56 * <ul>
57 * <li>{@link BundleContext#addBundleListener(BundleListener)} for
58 * <code>SynchronousBundleListener</code>
59 * <li>{@link BundleContext#removeBundleListener(BundleListener)} for
60 * <code>SynchronousBundleListener</code>
61 * </ul>
62 * <li>The <code>{@link AdminPermission#PERMISSION}</code> action allows calls to
63 * <ul>
64 * <li>{@link org.osgi.service.permissionadmin.PermissionAdmin#setPermissions(String, PermissionInfo[])}
65 * <li>{@link org.osgi.service.permissionadmin.PermissionAdmin#setDefaultPermissions(PermissionInfo[])}
66 * </ul>
67 * <li>The <code>{@link AdminPermission#RESOLVE}</code> action allows calls to
68 * <ul>
69 * <li>{@link org.osgi.service.packageadmin.PackageAdmin#refreshPackages(Bundle[])}</code>
70 * <li>{@link org.osgi.service.packageadmin.PackageAdmin#resolveBundles(Bundle[])}</code>
71 * </ul>
72 * <li>The <code>{@link AdminPermission#STARTLEVEL}</code> action allows calls to
73 * <ul>
74 * <li>{@link org.osgi.service.startlevel.StartLevel#setStartLevel(int)}
75 * <li>{@link org.osgi.service.startlevel.StartLevel#setInitialBundleStartLevel(int)}
76 * </ul>
77 * </ul>
78 *
79 * The special action "*" will represent all actions.
80 *
81 * @version $Revision: 1.12 $
82 */
83
84public final class AdminPermission extends Permission
85{
86 static final long serialVersionUID = 207051004521261705L;
87
88 /**
89 * The action string <code>class</code> (Value is "class").
90 */
91 public final static String CLASS = "class"; //$NON-NLS-1$
92
93 /**
94 * The action string <code>execute</code> (Value is "execute").
95 */
96 public final static String EXECUTE = "execute"; //$NON-NLS-1$
97
98 /**
99 * The action string <code>lifecycle</code> (Value is "lifecycle").
100 */
101 public final static String LIFECYCLE = "lifecycle"; //$NON-NLS-1$
102
103 /**
104 * The action string <code>listener</code> (Value is "listener").
105 */
106 public final static String LISTENER = "listener"; //$NON-NLS-1$
107
108 /**
109 * The action string <code>metadata</code> (Value is "metadata").
110 */
111 public final static String METADATA = "metadata"; //$NON-NLS-1$
112
113 /**
114 * The action string <code>permission</code> (Value is "permission").
115 */
116 public final static String PERMISSION = "permission"; //$NON-NLS-1$
117
118 /**
119 * The action string <code>resolve</code> (Value is "resolve").
120 */
121 public final static String RESOLVE = "resolve"; //$NON-NLS-1$
122
123 /**
124 * The action string <code>resource</code> (Value is "resource").
125 */
126 public final static String RESOURCE = "resource"; //$NON-NLS-1$
127
128 /**
129 * The action string <code>startlevel</code> (Value is "startlevel").
130 */
131 public final static String STARTLEVEL = "startlevel"; //$NON-NLS-1$
132
133 /**
134 * The action string <code>extensionLifecycle</code> (Value is "extensionLifecycle").
135 */
136 public final static String EXTENSIONLIFECYCLE = "extensionLifecycle"; //$NON-NLS-1$
137
138 private final static int ACTION_CLASS = 0x00000001;
139 private final static int ACTION_EXECUTE = 0x00000002;
140 private final static int ACTION_LIFECYCLE = 0x00000004;
141 private final static int ACTION_LISTENER = 0x00000008;
142 private final static int ACTION_METADATA = 0x00000010;
143 private final static int ACTION_PERMISSION = 0x00000020;
144 private final static int ACTION_RESOLVE = 0x00000040;
145 private final static int ACTION_RESOURCE = 0x00000080;
146 private final static int ACTION_STARTLEVEL = 0x00000100;
147 private final static int ACTION_EXTENSIONLIFECYCLE = 0x00000200;
148 private final static int ACTION_ALL =
149 ACTION_CLASS |
150 ACTION_EXECUTE |
151 ACTION_LIFECYCLE |
152 ACTION_LISTENER |
153 ACTION_METADATA |
154 ACTION_PERMISSION |
155 ACTION_RESOLVE |
156 ACTION_RESOURCE |
157 ACTION_STARTLEVEL |
158 ACTION_EXTENSIONLIFECYCLE;
159 private final static int ACTION_NONE = 0;
160
161 /**
162 * Indicates that this AdminPermission refers to all bundles
163 * @serial
164 */
165 private boolean wildcard;
166
167 /**
168 * An x.500 distinguished name used to match a bundle's signature - only used if
169 * wildcard is false and bundle = null
170 * @serial
171 */
172 private String filter;
173
174 /**
175 * The actions in canonical form.
176 *
177 * @serial
178 */
179 private String actions = null;
180
181 /**
182 * The actions mask.
183 */
184 private transient int action_mask = ACTION_NONE;
185
186 /**
187 * The bundle governed by this AdminPermission - only used if
188 * wildcard is false and filter == null
189 */
190 private transient Bundle bundle;
191
192 /**
193 * If this AdminPermission was constructed with a bundle, this dictionary holds
194 * the properties of that bundle, used to match a filter in implies.
195 * This is not initialized until necessary, and then cached in this object.
196 */
197 private transient Dictionary bundleProperties;
198
199 /**
200 * If this AdminPermission was constructed with a filter, this dictionary holds
201 * a Filter matching object used to evaluate the filter in implies.
202 * This is not initialized until necessary, and then cached in this object
203 */
204 private transient Filter filterImpl;
205
206 /**
207 * Creates a new <code>AdminPermission</code> object that matches
208 * all bundles and has all actions. Equivalent to
209 * AdminPermission("*","*");
210 */
211 public AdminPermission()
212 {
213 this("*",AdminPermission.ACTION_ALL); //$NON-NLS-1$
214 }
215
216 /**
217 * Creates a new <code>AdminPermission</code> object for use by the <code>Policy</code>
218 * object to instantiate new <code>Permission</code> objects.
219 *
220 * Null arguments are equivalent to "*"
221 *
222 * @param filter an X.500 Distinguished Name suffix or "*" to match all bundles
223 * @param actions <code>class</code>, <code>execute</code>, <code>lifecycle</code>,
224 * <code>listener</code>, <code>metadata</code>, <code>permission</code>, <code>resolve</code>,
225 * <code>resource</code>, <code>startlevel</code>, or "*" to indicate all actions
226 */
227 public AdminPermission(String filter, String actions)
228 {
229 //arguments will be null if called from a PermissionInfo defined with
230 //no args
231 this(
232 (filter == null ? "*" : filter), //$NON-NLS-1$
233 getMask((actions == null ? "*" : actions)) //$NON-NLS-1$
234 );
235 }
236
237 /**
238 * Creates a new <code>AdminPermission</code> object for use by the <code>Policy</code>
239 * object to instantiate new <code>Permission</code> objects.
240 *
241 * @param bundle A bundle
242 * @param actions <code>class</code>, <code>execute</code>, <code>lifecycle</code>,
243 * <code>listener</code>, <code>metadata</code>, <code>permission</code>, <code>resolve</code>,
244 * <code>resource</code>, <code>startlevel</code>, or "*" to indicate all actions
245 */
246 public AdminPermission(Bundle bundle, String actions) {
247 super(bundle.toString());
248 this.bundle = bundle;
249 this.wildcard = false;
250 this.filter = null;
251 this.action_mask = getMask(actions);
252 }
253
254 /**
255 * Package private constructor used by AdminPermissionCollection.
256 *
257 * @param filter name filter
258 * @param action_mask mask
259 */
260 AdminPermission(String filter, int action_mask) {
261 super(filter);
262
263 //name must be either * or a filter
264 if (filter.equals("*")) { //$NON-NLS-1$
265 this.wildcard = true;
266 this.filter = null;
267 } else {
268 this.wildcard = false;
269 this.filter = filter;
270 }
271 this.bundle = null;
272 this.action_mask = action_mask;
273 }
274
275 /**
276 * Parse action string into action mask.
277 *
278 * @param actions Action string.
279 * @return action mask.
280 */
281 private static int getMask(String actions) {
282
283 boolean seencomma = false;
284
285 int mask = ACTION_NONE;
286
287 if (actions == null) {
288 return mask;
289 }
290
291 char[] a = actions.toCharArray();
292
293 int i = a.length - 1;
294 if (i < 0)
295 return mask;
296
297 while (i != -1) {
298 char c;
299
300 // skip whitespace
301 while ((i!=-1) && ((c = a[i]) == ' ' ||
302 c == '\r' ||
303 c == '\n' ||
304 c == '\f' ||
305 c == '\t'))
306 i--;
307
308 // check for the known strings
309 int matchlen;
310
311 if (i >= 4 &&
312 (a[i-4] == 'c' || a[i-4] == 'C') &&
313 (a[i-3] == 'l' || a[i-3] == 'L') &&
314 (a[i-2] == 'a' || a[i-2] == 'A') &&
315 (a[i-1] == 's' || a[i-1] == 'S') &&
316 (a[i] == 's' || a[i] == 'S'))
317 {
318 matchlen = 5;
319 mask |= ACTION_CLASS;
320
321 } else if (i >= 6 &&
322 (a[i-6] == 'e' || a[i-6] == 'E') &&
323 (a[i-5] == 'x' || a[i-5] == 'X') &&
324 (a[i-4] == 'e' || a[i-4] == 'E') &&
325 (a[i-3] == 'c' || a[i-3] == 'C') &&
326 (a[i-2] == 'u' || a[i-2] == 'U') &&
327 (a[i-1] == 't' || a[i-1] == 'T') &&
328 (a[i] == 'e' || a[i] == 'E'))
329 {
330 matchlen = 7;
331 mask |= ACTION_EXECUTE;
332
333 } else if (i >= 17 &&
334 (a[i-17] == 'e' || a[i-17] == 'E') &&
335 (a[i-16] == 'x' || a[i-16] == 'X') &&
336 (a[i-15] == 't' || a[i-15] == 'T') &&
337 (a[i-14] == 'e' || a[i-14] == 'E') &&
338 (a[i-13] == 'n' || a[i-13] == 'N') &&
339 (a[i-12] == 's' || a[i-12] == 'S') &&
340 (a[i-11] == 'i' || a[i-11] == 'I') &&
341 (a[i-10] == 'o' || a[i-10] == 'O') &&
342 (a[i-9] == 'n' || a[i-9] == 'N') &&
343 (a[i-8] == 'l' || a[i-8] == 'L') &&
344 (a[i-7] == 'i' || a[i-7] == 'I') &&
345 (a[i-6] == 'f' || a[i-6] == 'F') &&
346 (a[i-5] == 'e' || a[i-5] == 'E') &&
347 (a[i-4] == 'c' || a[i-4] == 'C') &&
348 (a[i-3] == 'y' || a[i-3] == 'Y') &&
349 (a[i-2] == 'c' || a[i-2] == 'C') &&
350 (a[i-1] == 'l' || a[i-1] == 'L') &&
351 (a[i] == 'e' || a[i] == 'E'))
352 {
353 matchlen = 18;
354 mask |= ACTION_EXTENSIONLIFECYCLE;
355
356 } else if (i >= 8 &&
357 (a[i-8] == 'l' || a[i-8] == 'L') &&
358 (a[i-7] == 'i' || a[i-7] == 'I') &&
359 (a[i-6] == 'f' || a[i-6] == 'F') &&
360 (a[i-5] == 'e' || a[i-5] == 'E') &&
361 (a[i-4] == 'c' || a[i-4] == 'C') &&
362 (a[i-3] == 'y' || a[i-3] == 'Y') &&
363 (a[i-2] == 'c' || a[i-2] == 'C') &&
364 (a[i-1] == 'l' || a[i-1] == 'L') &&
365 (a[i] == 'e' || a[i] == 'E'))
366 {
367 matchlen = 9;
368 mask |= ACTION_LIFECYCLE;
369
370 } else if (i >= 7 &&
371 (a[i-7] == 'l' || a[i-7] == 'L') &&
372 (a[i-6] == 'i' || a[i-6] == 'I') &&
373 (a[i-5] == 's' || a[i-5] == 'S') &&
374 (a[i-4] == 't' || a[i-4] == 'T') &&
375 (a[i-3] == 'e' || a[i-3] == 'E') &&
376 (a[i-2] == 'n' || a[i-2] == 'N') &&
377 (a[i-1] == 'e' || a[i-1] == 'E') &&
378 (a[i] == 'r' || a[i] == 'R'))
379 {
380 matchlen = 8;
381 mask |= ACTION_LISTENER;
382
383 } else if (i >= 7 &&
384 (a[i-7] == 'm' || a[i-7] == 'M') &&
385 (a[i-6] == 'e' || a[i-6] == 'E') &&
386 (a[i-5] == 't' || a[i-5] == 'T') &&
387 (a[i-4] == 'a' || a[i-4] == 'A') &&
388 (a[i-3] == 'd' || a[i-3] == 'D') &&
389 (a[i-2] == 'a' || a[i-2] == 'A') &&
390 (a[i-1] == 't' || a[i-1] == 'T') &&
391 (a[i] == 'a' || a[i] == 'A'))
392 {
393 matchlen = 8;
394 mask |= ACTION_METADATA;
395
396 } else if (i >= 9 &&
397 (a[i-9] == 'p' || a[i-9] == 'P') &&
398 (a[i-8] == 'e' || a[i-8] == 'E') &&
399 (a[i-7] == 'r' || a[i-7] == 'R') &&
400 (a[i-6] == 'm' || a[i-6] == 'M') &&
401 (a[i-5] == 'i' || a[i-5] == 'I') &&
402 (a[i-4] == 's' || a[i-4] == 'S') &&
403 (a[i-3] == 's' || a[i-3] == 'S') &&
404 (a[i-2] == 'i' || a[i-2] == 'I') &&
405 (a[i-1] == 'o' || a[i-1] == 'O') &&
406 (a[i] == 'n' || a[i] == 'N'))
407 {
408 matchlen = 10;
409 mask |= ACTION_PERMISSION;
410
411 } else if (i >= 6 &&
412 (a[i-6] == 'r' || a[i-6] == 'R') &&
413 (a[i-5] == 'e' || a[i-5] == 'E') &&
414 (a[i-4] == 's' || a[i-4] == 'S') &&
415 (a[i-3] == 'o' || a[i-3] == 'O') &&
416 (a[i-2] == 'l' || a[i-2] == 'L') &&
417 (a[i-1] == 'v' || a[i-1] == 'V') &&
418 (a[i] == 'e' || a[i] == 'E'))
419 {
420 matchlen = 7;
421 mask |= ACTION_RESOLVE;
422
423 } else if (i >= 7 &&
424 (a[i-7] == 'r' || a[i-7] == 'R') &&
425 (a[i-6] == 'e' || a[i-6] == 'E') &&
426 (a[i-5] == 's' || a[i-5] == 'S') &&
427 (a[i-4] == 'o' || a[i-4] == 'O') &&
428 (a[i-3] == 'u' || a[i-3] == 'U') &&
429 (a[i-2] == 'r' || a[i-2] == 'R') &&
430 (a[i-1] == 'c' || a[i-1] == 'C') &&
431 (a[i] == 'e' || a[i] == 'E'))
432 {
433 matchlen = 8;
434 mask |= ACTION_RESOURCE;
435
436 } else if (i >= 9 &&
437 (a[i-9] == 's' || a[i-9] == 'S') &&
438 (a[i-8] == 't' || a[i-8] == 'T') &&
439 (a[i-7] == 'a' || a[i-7] == 'A') &&
440 (a[i-6] == 'r' || a[i-6] == 'R') &&
441 (a[i-5] == 't' || a[i-5] == 'T') &&
442 (a[i-4] == 'l' || a[i-4] == 'L') &&
443 (a[i-3] == 'e' || a[i-3] == 'E') &&
444 (a[i-2] == 'v' || a[i-2] == 'V') &&
445 (a[i-1] == 'e' || a[i-1] == 'E') &&
446 (a[i] == 'l' || a[i] == 'L'))
447 {
448 matchlen = 10;
449 mask |= ACTION_STARTLEVEL;
450
451 } else if (i >= 0 &&
452 (a[i] == '*'))
453 {
454 matchlen = 1;
455 mask |= ACTION_ALL;
456
457 } else {
458 // parse error
459 throw new IllegalArgumentException(
460 "invalid permission: " + actions);
461 }
462
463 // make sure we didn't just match the tail of a word
464 // like "ackbarfstartlevel". Also, skip to the comma.
465 seencomma = false;
466 while (i >= matchlen && !seencomma) {
467 switch(a[i-matchlen]) {
468 case ',':
469 seencomma = true;
470 /*FALLTHROUGH*/
471 case ' ': case '\r': case '\n':
472 case '\f': case '\t':
473 break;
474 default:
475 throw new IllegalArgumentException(
476 "invalid permission: " + actions);
477 }
478 i--;
479 }
480
481 // point i at the location of the comma minus one (or -1).
482 i -= matchlen;
483 }
484
485 if (seencomma) {
486 throw new IllegalArgumentException("invalid permission: " +
487 actions);
488 }
489
490 return mask;
491 }
492
493 /**
494 * Called by <code><@link AdminPermission#implies(Permission)></code> on an AdminPermission
495 * which was constructed with a Bundle. This method loads a dictionary with the
496 * filter-matchable properties of this bundle. The dictionary is cached so this lookup
497 * only happens once.
498 *
499 * This method should only be called on an AdminPermission which was constructed with a
500 * bundle
501 *
502 * @return a dictionary of properties for this bundle
503 */
504 private Dictionary getProperties() {
505 if (bundleProperties == null) {
506 bundleProperties = new Hashtable();
507
508 AccessController.doPrivileged(new PrivilegedAction() {
509 public Object run() {
510 //set Id
511 bundleProperties.put("id",new Long(bundle.getBundleId())); //$NON-NLS-1$
512
513 //set location
514 bundleProperties.put("location",bundle.getLocation()); //$NON-NLS-1$
515
516 //set name
517 if (bundle.getSymbolicName() != null)
518 bundleProperties.put("name",bundle.getSymbolicName()); //$NON-NLS-1$
519
520 //set signers
521// bundleProperties.put("signer",new SignerWrapper(bundle)); //$NON-NLS-1$
522
523 return null;
524 }
525 });
526 }
527 return bundleProperties;
528 }
529/*
530 private static class SignerWrapper extends Object {
531 private Bundle bundle;
532 private String pattern;
533 public SignerWrapper(String pattern) {
534 this.pattern = pattern;
535 }
536 SignerWrapper(Bundle bundle) {
537 this.bundle = bundle;
538 }
539
540 public boolean equals(Object o) {
541 if (!(o instanceof SignerWrapper))
542 return false;
543 SignerWrapper other = (SignerWrapper) o;
544 AbstractBundle matchBundle = (AbstractBundle) (bundle != null ? bundle : other.bundle);
545 String matchPattern = bundle != null ? other.pattern : pattern;
546 return matchBundle.getBundleData().matchDNChain(matchPattern);
547 }
548 }
549*/
550
551 /**
552 * Called by <tt><@link AdminPermission#implies(Permission)></tt> on an AdminPermission
553 * which was constructed with a filter. This method loads a FilterImpl with the
554 * filter specification of this AdminPermission. The filter is cached so this work
555 * only happens once.
556 *
557 * This method should only be called on an AdminPermission which was constructed with a
558 * filter
559 *
560 * @return a filterImpl for this bundle
561 */
562 private Filter getFilterImpl() {
563 if (filterImpl == null) {
564 try {
565 int pos = filter.indexOf("signer"); //$NON-NLS-1$
566 if (pos != -1){
567
568 //there may be a signer attribute
569 StringBuffer filterBuf = new StringBuffer(filter);
570 int numAsteriskFound = 0; //use as offset to replace in buffer
571
572 int walkbackPos; //temp pos
573
574 //find occurences of (signer= and escape out *'s
575 while (pos != -1) {
576
577 //walk back and look for '(' to see if this is an attr
578 walkbackPos = pos-1;
579
580 //consume whitespace
581 while(walkbackPos >= 0 && Character.isWhitespace(filter.charAt(walkbackPos))) {
582 walkbackPos--;
583 }
584 if (walkbackPos <0) {
585 //filter is invalid - FilterImpl will throw error
586 break;
587 }
588
589 //check to see if we have unescaped '('
590 if (filter.charAt(walkbackPos) != '(' || (walkbackPos > 0 && filter.charAt(walkbackPos-1) == '\\')) {
591 //'(' was escaped or not there
592 pos = filter.indexOf("signer",pos+6); //$NON-NLS-1$
593 continue;
594 }
595 pos+=6; //skip over 'signer'
596
597 //found signer - consume whitespace before '='
598 while (Character.isWhitespace(filter.charAt(pos))) {
599 pos++;
600 }
601
602 //look for '='
603 if (filter.charAt(pos) != '=') {
604 //attr was signerx - keep looking
605 pos = filter.indexOf("signer",pos); //$NON-NLS-1$
606 continue;
607 }
608 pos++; //skip over '='
609
610 //found signer value - escape '*'s
611 while (!(filter.charAt(pos) == ')' && filter.charAt(pos-1) != '\\')) {
612 if (filter.charAt(pos) == '*') {
613 filterBuf.insert(pos+numAsteriskFound,'\\');
614 numAsteriskFound++;
615 }
616 pos++;
617 }
618
619 //end of signer value - look for more?
620 pos = filter.indexOf("signer",pos); //$NON-NLS-1$
621 } //end while (pos != -1)
622 filter = filterBuf.toString();
623 } //end if (pos != -1)
624
625 filterImpl = new FilterImpl(filter);
626 } catch (InvalidSyntaxException e) {
627 //we will return null
628 }
629 }
630 return filterImpl;
631 }
632
633 /**
634 * Determines if the specified permission is implied by this object.
635 * This method throws an exception if the specified permission was not
636 * constructed with a bundle.
637 *
638 * <p>This method returns <code>true</code> if
639 * The specified permission is an AdminPermission AND
640 * <ul>
641 * <li>this object's filter is an X.500 Distinguished name suffix that
642 * matches the specified permission's bundle OR
643 * <li>this object's filter is "*" OR
644 * <li>this object's bundle is a equal to the specified permission's
645 * bundle
646 * </ul>
647 * AND this object's actions include all of the specified permission's actions
648 *
649 * Special case: if the specified permission was constructed with "*", then this method
650 * returns <code>true</code> if this object's filter is "*" and this object's actions include
651 * all of the specified permission's actions
652 *
653 * @param p The permission to interrogate.
654 *
655 * @return <code>true</code> if the specified permission is implied by
656 * this object; <code>false</code> otherwise.
657 * @throws RuntimeException if specified permission was not constructed with
658 * a bundle or "*"
659 */
660 public boolean implies(Permission p)
661 {
662 if (!(p instanceof AdminPermission))
663 return false;
664 AdminPermission target = (AdminPermission)p;
665 //check actions first - much faster
666 if ((action_mask & target.action_mask)!=target.action_mask)
667 return false;
668 //if passed in a filter, puke
669 if (target.filter != null)
670 throw new RuntimeException("Cannot imply a filter");
671 //special case - only wildcard implies wildcard
672 if (target.wildcard)
673 return wildcard;
674
675 //check our name
676 if (filter != null) {
677 //it's a filter
678 Filter filterImpl = getFilterImpl();
679 return filterImpl != null && filterImpl.match(target.getProperties());
680 } else if (wildcard) {
681 //it's "*"
682 return true;
683 } else {
684 //it's a bundle id
685 return bundle.equals(target.bundle);
686 }
687
688 }
689
690 /**
691 * Returns the canonical string representation of the <code>AdminPermission</code> actions.
692 *
693 * <p>Always returns present <code>AdminPermission</code> actions in the following order:
694 * <code>CLASS</code>, <code>EXECUTE</code>, <code>LIFECYCLE</code>, <code>LISTENER</code>,
695 * <code>METADATA</code>, <code>PERMISSION</code>, <code>RESOLVE</code>, <code>RESOURCE</code>,
696 * <code>STARTLEVEL</code>.
697 * @return Canonical string representation of the <code>AdminPermission</code> actions.
698 */
699 public String getActions() {
700 if (actions == null) {
701 if (action_mask == ACTION_ALL) {
702 actions = "*"; //$NON-NLS-1$
703 } else {
704 StringBuffer sb = new StringBuffer();
705
706 if ((action_mask & ACTION_CLASS) == ACTION_CLASS) {
707 sb.append(CLASS);
708 sb.append(',');
709 }
710
711 if ((action_mask & ACTION_EXECUTE) == ACTION_EXECUTE) {
712 sb.append(EXECUTE);
713 sb.append(',');
714 }
715
716 if ((action_mask & ACTION_LIFECYCLE) == ACTION_LIFECYCLE) {
717 sb.append(LIFECYCLE);
718 sb.append(',');
719 }
720
721 if ((action_mask & ACTION_LISTENER) == ACTION_LISTENER) {
722 sb.append(LISTENER);
723 sb.append(',');
724 }
725
726 if ((action_mask & ACTION_METADATA) == ACTION_METADATA) {
727 sb.append(METADATA);
728 sb.append(',');
729 }
730
731 if ((action_mask & ACTION_PERMISSION) == ACTION_PERMISSION) {
732 sb.append(PERMISSION);
733 sb.append(',');
734 }
735
736 if ((action_mask & ACTION_RESOLVE) == ACTION_RESOLVE) {
737 sb.append(RESOLVE);
738 sb.append(',');
739 }
740
741 if ((action_mask & ACTION_RESOURCE) == ACTION_RESOURCE) {
742 sb.append(RESOURCE);
743 sb.append(',');
744 }
745
746 if ((action_mask & ACTION_STARTLEVEL) == ACTION_STARTLEVEL) {
747 sb.append(STARTLEVEL);
748 sb.append(',');
749 }
750
751 if ((action_mask & ACTION_EXTENSIONLIFECYCLE) == ACTION_EXTENSIONLIFECYCLE) {
752 sb.append(EXTENSIONLIFECYCLE);
753 sb.append(',');
754 }
755
756 //remove trailing comma
757 if (sb.length() > 0) {
758 sb.deleteCharAt(sb.length()-1);
759 }
760
761 actions = sb.toString();
762 }
763 }
764 return actions;
765 }
766
767 /**
768 * Determines the equality of two <code>AdminPermission</code> objects. <p>Two
769 * <code>AdminPermission</code> objects are equal.
770 *
771 * @param obj The object being compared for equality with this object.
772 * @return <code>true</code> if <code>obj</code> is equivalent to this
773 * <code>AdminPermission</code>; <code>false</code> otherwise.
774 */
775 public boolean equals(Object obj)
776 {
777 if (obj == this) {
778 return true;
779 }
780
781 if (!(obj instanceof AdminPermission))
782 {
783 return false;
784 }
785
786 AdminPermission a = (AdminPermission) obj;
787
788 return (action_mask == a.action_mask) &&
789 (wildcard == a.wildcard) &&
790 (bundle == null ? a.bundle == null : (a.bundle == null ? false : bundle.getBundleId() == a.bundle.getBundleId())) &&
791 (filter == null ? a.filter == null : filter.equals(a.filter));
792 }
793
794 /**
795 * Returns the hash code value for this object.
796 *
797 * @return Hash code value for this object.
798 */
799 public int hashCode() {
800 return getName().hashCode() ^ getActions().hashCode();
801 }
802
803 private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException {
804 // Write out the actions. The superclass takes care of the name
805 // call getActions to make sure actions field is initialized
806 if (actions == null)
807 getActions();
808 if (filter == null && !wildcard)
809 throw new UnsupportedOperationException("cannot serialize");
810 s.defaultWriteObject();
811 }
812
813 /**
814 * readObject is called to restore the state of this permission from a
815 * stream.
816 */
817 private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
818 // Read in the action, then initialize the rest
819 s.defaultReadObject();
820 action_mask = getMask(actions);
821 }
822
823 /**
824 * Returns a new <code>PermissionCollection</code> object suitable for storing
825 * <code>AdminPermission</code>s.
826 *
827 * @return A new <code>PermissionCollection</code> object.
828 */
829 public PermissionCollection newPermissionCollection()
830 {
831 return(new AdminPermissionCollection());
832 }
833
834 /**
835 * Stores a collection of <code>AdminPermission</code>s.
836 */
837 private final class AdminPermissionCollection extends PermissionCollection
838 {
839 private static final long serialVersionUID = 3906372644575328048L;
840 /**
841 * Collection of permissions.
842 *
843 * @serial
844 */
845 private Hashtable permissions;
846
847 /**
848 * Create an empty AdminPermissions object.
849 *
850 */
851
852 public AdminPermissionCollection()
853 {
854 permissions = new Hashtable();
855 }
856
857 /**
858 * Adds a permission to the <code>AdminPermission</code> objects. The key for
859 * the hashtable is the name
860 *
861 * @param permission The <code>AdminPermission</code> object to add.
862 *
863 * @exception IllegalArgumentException If the permission is not an
864 * <code>AdminPermission</code> instance.
865 *
866 * @exception SecurityException If this <code>AdminPermissionCollection</code>
867 * object has been marked read-only.
868 */
869 public void add(Permission permission)
870 {
871 if (! (permission instanceof AdminPermission))
872 throw new IllegalArgumentException("invalid permission: "+
873 permission);
874 if (isReadOnly())
875 throw new SecurityException("attempt to add a Permission to a " +
876 "readonly AdminCollection");
877 AdminPermission ap = (AdminPermission) permission;
878 AdminPermission existing = (AdminPermission) permissions.get(ap.getName());
879 if (existing != null){
880 int oldMask = existing.action_mask;
881 int newMask = ap.action_mask;
882
883 if (oldMask != newMask) {
884 permissions.put(existing.getName(),
885 new AdminPermission(existing.getName(), oldMask | newMask));
886 }
887 } else {
888 permissions.put(ap.getName(), ap);
889 }
890 }
891
892
893 /**
894 * Determines if the specified permissions implies the permissions
895 * expressed in <code>permission</code>.
896 *
897 * @param permission The Permission object to compare with the <code>AdminPermission</code>
898 * objects in this collection.
899 *
900 * @return <code>true</code> if <code>permission</code> is implied by an
901 * <code>AdminPermission</code> in this collection, <code>false</code> otherwise.
902 */
903 public boolean implies(Permission permission)
904 {
905 if (!(permission instanceof AdminPermission))
906 return(false);
907
908 AdminPermission target = (AdminPermission) permission;
909
910 //just iterate one by one
911 Iterator permItr = permissions.values().iterator();
912
913 while(permItr.hasNext())
914 if (((AdminPermission)permItr.next()).implies(target))
915 return true;
916 return false;
917 }
918
919
920 /**
921 * Returns an enumeration of all <code>AdminPermission</code> objects in the
922 * container.
923 *
924 * @return Enumeration of all <code>AdminPermission</code> objects.
925 */
926
927 public Enumeration elements()
928 {
929 return(Collections.enumeration(permissions.values()));
930 }
931 }
932}