001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.daemon;
019
020 import java.security.Permission;
021 import java.util.StringTokenizer;
022
023 /**
024 * This class represents the permissions to control and query the status of
025 * a <code>Daemon</code>. A <code>DaemonPermission</code> consists of a
026 * target name and a list of actions associated with it.
027 * <p>
028 * In this specification version the only available target name for this
029 * permission is "control", but further releases may add more target
030 * names to fine-tune the access that needs to be granted to the caller.
031 * </p>
032 * <p>
033 * Actions are defined by a string of comma-separated values, as shown in the
034 * table below. The empty string implies no permission at all, while the
035 * special "*" value implies all permissions for the given
036 * name:
037 * </p>
038 * <p>
039 * <table width="100%" border="1">
040 * <tr>
041 * <th>Target"Name</th>
042 * <th>Action</th>
043 * <th>Description</th>
044 * </tr>
045 * <tr>
046 * <td rowspan="5">"control"</td>
047 * <td>"start"</td>
048 * <td>
049 * The permission to call the <code>start()</code> method in an instance
050 * of a <code>DaemonController</code> interface.
051 * </td>
052 * </tr>
053 * <tr>
054 * <td>"stop"</td>
055 * <td>
056 * The permission to call the <code>stop()</code> method in an instance
057 * of a <code>DaemonController</code> interface.
058 * </td>
059 * </tr>
060 * <tr>
061 * <td>"shutdown"</td>
062 * <td>
063 * The permission to call the <code>shutdown()</code> method in an instance
064 * of a <code>DaemonController</code> interface.
065 * </td>
066 * </tr>
067 * <tr>
068 * <td>"reload"</td>
069 * <td>
070 * The permission to call the <code>reload()</code> method in an instance
071 * of a <code>DaemonController</code> interface.
072 * </td>
073 * </tr>
074 * <tr>
075 * <td>"*"</td>
076 * <td>
077 * The special wildcard action implies all above-mentioned action. This is
078 * equal to construct a permission with the "start, stop, shutdown,
079 * reload" list of actions.
080 * </td>
081 * </tr>
082 * </table>
083 * </p>
084 *
085 * @author Pier Fumagalli
086 * @version 1.0 <i>(SVN $Revision: 937348 $)</i>
087 */
088 public final class DaemonPermission extends Permission
089 {
090
091 /* ====================================================================
092 * Constants.
093 */
094
095 /**
096 * The target name when associated with control actions
097 * ("control").
098 */
099 protected static final String CONTROL = "control";
100
101 /**
102 * The target type when associated with control actions.
103 */
104 protected static final int TYPE_CONTROL = 1;
105
106 /**
107 * The action name associated with the permission to call the
108 * <code>DaemonController.start()</code> method.
109 */
110 protected static final String CONTROL_START = "start";
111
112 /**
113 * The action name associated with the permission to call the
114 * <code>DaemonController.stop()</code> method.
115 */
116 protected static final String CONTROL_STOP = "stop";
117
118 /**
119 * The action name associated with the permission to call the
120 * <code>DaemonController.shutdown()</code> method.
121 */
122 protected static final String CONTROL_SHUTDOWN = "shutdown";
123
124 /**
125 * The action name associated with the permission to call the
126 * <code>DaemonController.reload()</code> method.
127 */
128 protected static final String CONTROL_RELOAD = "reload";
129
130 /**
131 * The action mask associated with the permission to call the
132 * <code>DaemonController.start()</code> method.
133 */
134 protected static final int MASK_CONTROL_START = 0x01;
135
136 /**
137 * The action mask associated with the permission to call the
138 * <code>DaemonController.stop()</code> method.
139 */
140 protected static final int MASK_CONTROL_STOP = 0x02;
141
142 /**
143 * The action mask associated with the permission to call the
144 * <code>DaemonController.shutdown()</code> method.
145 */
146 protected static final int MASK_CONTROL_SHUTDOWN = 0x04;
147
148 /**
149 * The action mask associated with the permission to call the
150 * <code>DaemonController.reload()</code> method.
151 */
152 protected static final int MASK_CONTROL_RELOAD = 0x08;
153
154 /**
155 * The "wildcard" action implying all actions for the given
156 * target name.
157 */
158 protected static final String WILDCARD = "*";
159
160 /* ====================================================================
161 * Instance variables
162 */
163
164 /** The type of this permission object. */
165 private transient int type = 0;
166 /** The permission mask associated with this permission object. */
167 private transient int mask = 0;
168 /** The String representation of this permission object. */
169 private transient String desc = null;
170
171 /* ====================================================================
172 * Constructors
173 */
174
175 /**
176 * Create a new <code>DaemonPermission</code> instance with a specified
177 * permission name.
178 * <p>
179 * This constructor will create a new <code>DaemonPermission</code>
180 * instance that <b>will not</b> grant any permission to the caller.
181 *
182 * @param target The target name of this permission.
183 * @exception IllegalArgumentException If the specified target name is not
184 * supported.
185 */
186 public DaemonPermission(String target)
187 throws IllegalArgumentException
188 {
189 // Setup the target name of this permission object.
190 super(target);
191
192 // Check if the permission target name was specified
193 if (target == null)
194 throw new IllegalArgumentException("Null permission name");
195
196 // Check if this is a "control" permission and set up accordingly.
197 if (CONTROL.equalsIgnoreCase(target)) {
198 type = TYPE_CONTROL;
199 return;
200 }
201
202 // If we got here, we have an invalid permission name.
203 throw new IllegalArgumentException("Invalid permission name \"" +
204 target + "\" specified");
205 }
206
207 /**
208 * Create a new <code>DaemonPermission</code> instance with a specified
209 * permission name and a specified list of actions.
210 * <p>
211 * </p>
212 *
213 * @param target The target name of this permission.
214 * @param actions The list of actions permitted by this permission.
215 * @exception IllegalArgumentException If the specified target name is not
216 * supported, or the specified list of actions includes an
217 * invalid value.
218 */
219 public DaemonPermission(String target, String actions)
220 throws IllegalArgumentException
221 {
222 // Setup this instance's target name.
223 this(target);
224
225 // Create the appropriate mask if this is a control permission.
226 if (this.type == TYPE_CONTROL) {
227 this.mask = this.createControlMask(actions);
228 return;
229 }
230 }
231
232 /* ====================================================================
233 * Public methods
234 */
235
236 /**
237 * Return the list of actions permitted by this instance of
238 * <code>DaemonPermission</code> in its canonical form.
239 *
240 * @return The canonicalized list of actions.
241 */
242 public String getActions()
243 {
244 if (this.type == TYPE_CONTROL) {
245 return this.createControlActions(this.mask);
246 }
247 return "";
248 }
249
250 /**
251 * Return the hash code for this <code>DaemonPermission</code> instance.
252 *
253 * @return An hash code value.
254 */
255 public int hashCode()
256 {
257 this.setupDescription();
258 return this.desc.hashCode();
259 }
260
261 /**
262 * Check if a specified object equals <code>DaemonPermission</code>.
263 *
264 * @return <b>true</b> or <b>false</b> wether the specified object equals
265 * this <code>DaemonPermission</code> instance or not.
266 */
267 public boolean equals(Object object)
268 {
269 if (object == this)
270 return true;
271
272 if (!(object instanceof DaemonPermission))
273 return false;
274
275 DaemonPermission that = (DaemonPermission) object;
276
277 if (this.type != that.type)
278 return false;
279 return this.mask == that.mask;
280 }
281
282 /**
283 * Check if this <code>DaemonPermission</code> implies another
284 * <code>Permission</code>.
285 *
286 * @return <b>true</b> or <b>false</b> wether the specified permission
287 * is implied by this <code>DaemonPermission</code> instance or
288 * not.
289 */
290 public boolean implies(Permission permission)
291 {
292 if (permission == this)
293 return true;
294
295 if (!(permission instanceof DaemonPermission))
296 return false;
297
298 DaemonPermission that = (DaemonPermission) permission;
299
300 if (this.type != that.type)
301 return false;
302 return (this.mask & that.mask) == that.mask;
303 }
304
305 /**
306 * Return a <code>String</code> representation of this instance.
307 *
308 * @return A <code>String</code> representing this
309 * <code>DaemonPermission</code> instance.
310 */
311 public String toString()
312 {
313 this.setupDescription();
314 return this.desc;
315 }
316
317 /* ====================================================================
318 * Private methods
319 */
320
321 /** Create a String description for this permission instance.
322 */
323 private void setupDescription()
324 {
325 if (this.desc != null)
326 return;
327
328 StringBuffer buf = new StringBuffer();
329 buf.append(this.getClass().getName());
330 buf.append('[');
331 switch (this.type) {
332 case TYPE_CONTROL:
333 buf.append(CONTROL);
334 break;
335 default:
336 buf.append("UNKNOWN");
337 break;
338 }
339 buf.append(':');
340 buf.append(this.getActions());
341 buf.append(']');
342
343 this.desc = buf.toString();
344 }
345
346 /** Create a permission mask for a given control actions string.
347 */
348 private int createControlMask(String actions)
349 throws IllegalArgumentException
350 {
351 if (actions == null)
352 return 0;
353
354 int mask = 0;
355 StringTokenizer tok = new StringTokenizer(actions, ",", false);
356
357 while (tok.hasMoreTokens()) {
358 String val = tok.nextToken().trim();
359
360 if (WILDCARD.equals(val)) {
361 return MASK_CONTROL_START | MASK_CONTROL_STOP |
362 MASK_CONTROL_SHUTDOWN | MASK_CONTROL_RELOAD;
363 }
364 else if (CONTROL_START.equalsIgnoreCase(val)) {
365 mask = mask | MASK_CONTROL_START;
366 }
367 else if (CONTROL_STOP.equalsIgnoreCase(val)) {
368 mask = mask | MASK_CONTROL_STOP;
369 }
370 else if (CONTROL_SHUTDOWN.equalsIgnoreCase(val)) {
371 mask = mask | MASK_CONTROL_SHUTDOWN;
372 }
373 else if (CONTROL_RELOAD.equalsIgnoreCase(val)) {
374 mask = mask | MASK_CONTROL_RELOAD;
375 }
376 else {
377 throw new IllegalArgumentException("Invalid action name \"" +
378 val + "\" specified");
379 }
380 }
381 return mask;
382 }
383
384 /** Create a actions list for a given control permission mask. */
385 private String createControlActions(int mask)
386 {
387 StringBuffer buf = new StringBuffer();
388 boolean sep = false;
389
390 if ((mask & MASK_CONTROL_START) == MASK_CONTROL_START) {
391 sep = true;
392 buf.append(CONTROL_START);
393 }
394
395 if ((mask & MASK_CONTROL_STOP) == MASK_CONTROL_STOP) {
396 if (sep)
397 buf.append(",");
398 else
399 sep = true;
400 buf.append(CONTROL_STOP);
401 }
402
403 if ((mask & MASK_CONTROL_SHUTDOWN) == MASK_CONTROL_SHUTDOWN) {
404 if (sep)
405 buf.append(",");
406 else
407 sep = true;
408 buf.append(CONTROL_SHUTDOWN);
409 }
410
411 if ((mask & MASK_CONTROL_RELOAD) == MASK_CONTROL_RELOAD) {
412 if (sep)
413 buf.append(",");
414 else
415 sep = true;
416 buf.append(CONTROL_RELOAD);
417 }
418
419 return buf.toString();
420 }
421 }
422