KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > osgi > service > event > TopicPermission


1 /*
2  * $Header: /cvshome/build/org.osgi.service.event/src/org/osgi/service/event/TopicPermission.java,v 1.11 2006/06/16 16:31:48 hargrave Exp $
3  *
4  * Copyright (c) OSGi Alliance (2005, 2006). All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 package org.osgi.service.event;
20
21 import java.io.IOException JavaDoc;
22 import java.security.Permission JavaDoc;
23 import java.security.PermissionCollection JavaDoc;
24 import java.util.Enumeration JavaDoc;
25 import java.util.Hashtable JavaDoc;
26
27 /**
28  * A bundle's authority to publish or subscribe to event on a topic.
29  *
30  * <p>
31  * A topic is a slash-separated string that defines a topic.
32  * <p>
33  * For example:
34  *
35  * <pre>
36  * org/osgi/service/foo/FooEvent/ACTION
37  * </pre>
38  *
39  * <p>
40  * <code>TopicPermission</code> has two actions: <code>publish</code> and
41  * <code>subscribe</code>.
42  *
43  * @version $Revision: 1.11 $
44  */

45 public final class TopicPermission extends Permission JavaDoc {
46     static final long serialVersionUID = -5855563886961618300L;
47     /**
48      * The action string <code>publish</code>.
49      */

50     public final static String JavaDoc PUBLISH = "publish"; //$NON-NLS-1$
51
/**
52      * The action string <code>subscribe</code>.
53      */

54     public final static String JavaDoc SUBSCRIBE = "subscribe"; //$NON-NLS-1$
55
private final static int ACTION_PUBLISH = 0x00000001;
56     private final static int ACTION_SUBSCRIBE = 0x00000002;
57     private final static int ACTION_ALL = ACTION_PUBLISH
58                                                             | ACTION_SUBSCRIBE;
59     private final static int ACTION_NONE = 0;
60     /**
61      * The actions mask.
62      */

63     private transient int action_mask = ACTION_NONE;
64
65     /**
66      * prefix if the name is wildcarded.
67      */

68     private transient String JavaDoc prefix;
69
70     /**
71      * The actions in canonical form.
72      *
73      * @serial
74      */

75     private String JavaDoc actions = null;
76
77     /**
78      * Defines the authority to publich and/or subscribe to a topic within the
79      * EventAdmin service.
80      * <p>
81      * The name is specified as a slash-separated string. Wildcards may be used.
82      * For example:
83      *
84      * <pre>
85      * org/osgi/service/fooFooEvent/ACTION
86      * com/isv/*
87      * *
88      * </pre>
89      *
90      * <p>
91      * A bundle that needs to publish events on a topic must have the
92      * appropriate <code>TopicPermission</code> for that topic; similarly, a
93      * bundle that needs to subscribe to events on a topic must have the
94      * appropriate <code>TopicPermssion</code> for that topic.
95      * <p>
96      *
97      * @param name Topic name.
98      * @param actions <code>publish</code>,<code>subscribe</code>
99      * (canonical order).
100      */

101     public TopicPermission(String JavaDoc name, String JavaDoc actions) {
102         this(name, getMask(actions));
103     }
104
105     /**
106      * Package private constructor used by TopicPermissionCollection.
107      *
108      * @param name class name
109      * @param mask action mask
110      */

111     TopicPermission(String JavaDoc name, int mask) {
112         super(name);
113         init(name, mask);
114     }
115
116     /**
117      * Called by constructors and when deserialized.
118      *
119      * @param name topic name
120      * @param mask action mask
121      */

122     private void init(String JavaDoc name, int mask) {
123         if ((name == null) || name.length() == 0) {
124             throw new IllegalArgumentException JavaDoc("invalid name"); //$NON-NLS-1$
125
}
126
127         if (name.equals("*")) {
128             prefix = "";
129         }
130         else
131             if (name.endsWith("/*")) {
132                 prefix = name.substring(0, name.length() - 1);
133             }
134             else {
135                 prefix = null;
136             }
137
138         if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) {
139             throw new IllegalArgumentException JavaDoc("invalid action string"); //$NON-NLS-1$
140
}
141         action_mask = mask;
142     }
143
144     /**
145      * Parse action string into action mask.
146      *
147      * @param actions Action string.
148      * @return action mask.
149      */

150     private static int getMask(String JavaDoc actions) {
151         boolean seencomma = false;
152         int mask = ACTION_NONE;
153         if (actions == null) {
154             return mask;
155         }
156         char[] a = actions.toCharArray();
157         int i = a.length - 1;
158         if (i < 0)
159             return mask;
160         while (i != -1) {
161             char c;
162             // skip whitespace
163
while ((i != -1)
164                     && ((c = a[i]) == ' ' || c == '\r' || c == '\n'
165                             || c == '\f' || c == '\t'))
166                 i--;
167             // check for the known strings
168
int matchlen;
169             if (i >= 8 && (a[i - 8] == 's' || a[i - 8] == 'S')
170                     && (a[i - 7] == 'u' || a[i - 7] == 'U')
171                     && (a[i - 6] == 'b' || a[i - 6] == 'B')
172                     && (a[i - 5] == 's' || a[i - 5] == 'S')
173                     && (a[i - 4] == 'c' || a[i - 4] == 'C')
174                     && (a[i - 3] == 'r' || a[i - 3] == 'R')
175                     && (a[i - 2] == 'i' || a[i - 2] == 'I')
176                     && (a[i - 1] == 'b' || a[i - 1] == 'B')
177                     && (a[i] == 'e' || a[i] == 'E')) {
178                 matchlen = 9;
179                 mask |= ACTION_SUBSCRIBE;
180             }
181             else
182                 if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P')
183                         && (a[i - 5] == 'u' || a[i - 5] == 'U')
184                         && (a[i - 4] == 'b' || a[i - 4] == 'B')
185                         && (a[i - 3] == 'l' || a[i - 3] == 'L')
186                         && (a[i - 2] == 'i' || a[i - 2] == 'I')
187                         && (a[i - 1] == 's' || a[i - 1] == 'S')
188                         && (a[i] == 'h' || a[i] == 'H')) {
189                     matchlen = 7;
190                     mask |= ACTION_PUBLISH;
191                 }
192                 else {
193                     // parse error
194
throw new IllegalArgumentException JavaDoc("invalid permission: " //$NON-NLS-1$
195
+ actions);
196                 }
197             // make sure we didn't just match the tail of a word
198
// like "ackbarfpublish". Also, skip to the comma.
199
seencomma = false;
200             while (i >= matchlen && !seencomma) {
201                 switch (a[i - matchlen]) {
202                     case ',' :
203                         seencomma = true;
204                     /* FALLTHROUGH */
205                     case ' ' :
206                     case '\r' :
207                     case '\n' :
208                     case '\f' :
209                     case '\t' :
210                         break;
211                     default :
212                         throw new IllegalArgumentException JavaDoc(
213                                 "invalid permission: " + actions); //$NON-NLS-1$
214
}
215                 i--;
216             }
217             // point i at the location of the comma minus one (or -1).
218
i -= matchlen;
219         }
220         if (seencomma) {
221             throw new IllegalArgumentException JavaDoc("invalid permission: " + actions); //$NON-NLS-1$
222
}
223         return mask;
224     }
225
226     /**
227      * Determines if the specified permission is implied by this object.
228      *
229      * <p>
230      * This method checks that the topic name of the target is implied by the
231      * topic name of this object. The list of <code>TopicPermission</code>
232      * actions must either match or allow for the list of the target object to
233      * imply the target <code>TopicPermission</code> action.
234      *
235      * <pre>
236      * x/y/*,&quot;publish&quot; -&gt; x/y/z,&quot;publish&quot; is true
237      * *,&quot;subscribe&quot; -&gt; x/y,&quot;subscribe&quot; is true
238      * *,&quot;publish&quot; -&gt; x/y,&quot;subscribe&quot; is false
239      * x/y,&quot;publish&quot; -&gt; x/y/z,&quot;publish&quot; is false
240      * </pre>
241      *
242      * @param p The target permission to interrogate.
243      * @return <code>true</code> if the specified <code>TopicPermission</code>
244      * action is implied by this object; <code>false</code> otherwise.
245      */

246     public boolean implies(Permission JavaDoc p) {
247         if (p instanceof TopicPermission) {
248             TopicPermission target = (TopicPermission) p;
249             if ((action_mask & target.action_mask) == target.action_mask) {
250                 if (prefix != null) {
251                     return target.getName().startsWith(prefix);
252                 }
253
254                 return target.getName().equals(getName());
255             }
256         }
257         return false;
258     }
259
260     /**
261      * Returns the canonical string representation of the
262      * <code>TopicPermission</code> actions.
263      *
264      * <p>
265      * Always returns present <code>TopicPermission</code> actions in the
266      * following order: <code>publish</code>,<code>subscribe</code>.
267      *
268      * @return Canonical string representation of the
269      * <code>TopicPermission</code> actions.
270      */

271     public String JavaDoc getActions() {
272         if (actions == null) {
273             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
274             boolean comma = false;
275             if ((action_mask & ACTION_PUBLISH) == ACTION_PUBLISH) {
276                 sb.append(PUBLISH);
277                 comma = true;
278             }
279             if ((action_mask & ACTION_SUBSCRIBE) == ACTION_SUBSCRIBE) {
280                 if (comma)
281                     sb.append(',');
282                 sb.append(SUBSCRIBE);
283             }
284             actions = sb.toString();
285         }
286         return actions;
287     }
288
289     /**
290      * Returns a new <code>PermissionCollection</code> object suitable for
291      * storing <code>TopicPermission</code> objects.
292      *
293      * @return A new <code>PermissionCollection</code> object.
294      */

295     public PermissionCollection JavaDoc newPermissionCollection() {
296         return new TopicPermissionCollection();
297     }
298
299     /**
300      * Determines the equality of two <code>TopicPermission</code> objects.
301      *
302      * This method checks that specified <code>TopicPermission</code> has the same topic name and
303      * actions as this
304      * <code>TopicPermission</code> object.
305      *
306      * @param obj The object to test for equality with this
307      * <code>TopicPermission</code> object.
308      * @return <code>true</code> if <code>obj</code> is a
309      * <code>TopicPermission</code>, and has the same topic name and
310      * actions as this <code>TopicPermission</code> object;
311      * <code>false</code> otherwise.
312      */

313     public boolean equals(Object JavaDoc obj) {
314         if (obj == this) {
315             return true;
316         }
317         if (!(obj instanceof TopicPermission)) {
318             return false;
319         }
320         TopicPermission p = (TopicPermission) obj;
321         return (action_mask == p.action_mask) && getName().equals(p.getName());
322     }
323
324     /**
325      * Returns the hash code value for this object.
326      *
327      * @return A hash code value for this object.
328      */

329     public int hashCode() {
330         return getName().hashCode() ^ getActions().hashCode();
331     }
332
333     /**
334      * Returns the current action mask.
335      * <p>
336      * Used by the TopicPermissionCollection class.
337      *
338      * @return Current action mask.
339      */

340     int getMask() {
341         return action_mask;
342     }
343
344     /**
345      * WriteObject is called to save the state of this permission object to a
346      * stream. The actions are serialized, and the superclass takes care of the
347      * name.
348      */

349     private synchronized void writeObject(java.io.ObjectOutputStream JavaDoc s)
350             throws IOException JavaDoc {
351         // Write out the actions. The superclass takes care of the name
352
// call getActions to make sure actions field is initialized
353
if (actions == null)
354             getActions();
355         s.defaultWriteObject();
356     }
357
358     /**
359      * readObject is called to restore the state of this permission from a
360      * stream.
361      */

362     private synchronized void readObject(java.io.ObjectInputStream JavaDoc s)
363             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
364         // Read in the action, then initialize the rest
365
s.defaultReadObject();
366         init(getName(), getMask(actions));
367     }
368 }
369
370 /**
371  * Stores a set of <code>TopicPermission</code> permissions.
372  *
373  * @see java.security.Permission
374  * @see java.security.Permissions
375  * @see java.security.PermissionCollection
376  */

377 final class TopicPermissionCollection extends PermissionCollection JavaDoc {
378     static final long serialVersionUID = -614647783533924048L;
379     /**
380      * Table of permissions.
381      *
382      * @serial
383      */

384     private Hashtable JavaDoc permissions;
385     /**
386      * Boolean saying if "*" is in the collection.
387      *
388      * @serial
389      */

390     private boolean all_allowed;
391
392     /**
393      * Create an empty TopicPermissions object.
394      *
395      */

396     public TopicPermissionCollection() {
397         permissions = new Hashtable JavaDoc();
398         all_allowed = false;
399     }
400
401     /**
402      * Adds a permission to the <code>TopicPermission</code> objects. The key
403      * for the hash is the name.
404      *
405      * @param permission The <code>TopicPermission</code> object to add.
406      *
407      * @throws IllegalArgumentException If the permission is not a
408      * <code>TopicPermission</code> instance.
409      *
410      * @throws SecurityException If this
411      * <code>TopicPermissionCollection</code> object has been
412      * marked read-only.
413      */

414     public void add(Permission JavaDoc permission) {
415         if (!(permission instanceof TopicPermission))
416             throw new IllegalArgumentException JavaDoc("invalid permission: " //$NON-NLS-1$
417
+ permission);
418         if (isReadOnly())
419             throw new SecurityException JavaDoc("attempt to add a Permission to a " //$NON-NLS-1$
420
+ "readonly PermissionCollection"); //$NON-NLS-1$
421
TopicPermission pp = (TopicPermission) permission;
422         String JavaDoc name = pp.getName();
423         TopicPermission existing = (TopicPermission) permissions.get(name);
424         if (existing != null) {
425             int oldMask = existing.getMask();
426             int newMask = pp.getMask();
427             if (oldMask != newMask) {
428                 permissions.put(name, new TopicPermission(name, oldMask
429                         | newMask));
430             }
431         }
432         else {
433             permissions.put(name, permission);
434         }
435         if (!all_allowed) {
436             if (name.equals("*")) //$NON-NLS-1$
437
all_allowed = true;
438         }
439     }
440
441     /**
442      * Determines if the specified permissions implies the permissions expressed
443      * in <code>permission</code>.
444      *
445      * @param permission The Permission object to compare with this
446      * <code>TopicPermission</code> object.
447      *
448      * @return <code>true</code> if <code>permission</code> is a proper
449      * subset of a permission in the set; <code>false</code>
450      * otherwise.
451      */

452     public boolean implies(Permission JavaDoc permission) {
453         if (!(permission instanceof TopicPermission))
454             return false;
455         TopicPermission pp = (TopicPermission) permission;
456         TopicPermission x;
457         int desired = pp.getMask();
458         int effective = 0;
459         // short circuit if the "*" Permission was added
460
if (all_allowed) {
461             x = (TopicPermission) permissions.get("*"); //$NON-NLS-1$
462
if (x != null) {
463                 effective |= x.getMask();
464                 if ((effective & desired) == desired)
465                     return true;
466             }
467         }
468         // strategy:
469
// Check for full match first. Then work our way up the
470
// name looking for matches on a/b/*
471
String JavaDoc name = pp.getName();
472         x = (TopicPermission) permissions.get(name);
473         if (x != null) {
474             // we have a direct hit!
475
effective |= x.getMask();
476             if ((effective & desired) == desired)
477                 return true;
478         }
479         // work our way up the tree...
480
int last, offset;
481         offset = name.length() - 1;
482         while ((last = name.lastIndexOf("/", offset)) != -1) { //$NON-NLS-1$
483
name = name.substring(0, last + 1) + "*"; //$NON-NLS-1$
484
x = (TopicPermission) permissions.get(name);
485             if (x != null) {
486                 effective |= x.getMask();
487                 if ((effective & desired) == desired)
488                     return true;
489             }
490             offset = last - 1;
491         }
492         // we don't have to check for "*" as it was already checked
493
// at the top (all_allowed), so we just return false
494
return false;
495     }
496
497     /**
498      * Returns an enumeration of all <code>TopicPermission</code> objects in
499      * the container.
500      *
501      * @return Enumeration of all <code>TopicPermission</code> objects.
502      */

503     public Enumeration JavaDoc elements() {
504         return permissions.elements();
505     }
506 }
507
Popular Tags