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