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>(CVS $Revision: 480475 $)</i>
087 */
088 public final class DaemonPermission extends Permission {
089
090 /* ==================================================================== */
091 /* Constants. */
092
093 /**
094 * The target name when associated with control actions
095 * ("control").
096 */
097 protected static final String CONTROL = "control";
098
099 /**
100 * The target type when associated with control actions.
101 */
102 protected static final int TYPE_CONTROL = 1;
103
104 /**
105 * The action name associated with the permission to call the
106 * <code>DaemonController.start()</code> method.
107 */
108 protected static final String CONTROL_START = "start";
109
110 /**
111 * The action name associated with the permission to call the
112 * <code>DaemonController.stop()</code> method.
113 */
114 protected static final String CONTROL_STOP = "stop";
115
116 /**
117 * The action name associated with the permission to call the
118 * <code>DaemonController.shutdown()</code> method.
119 */
120 protected static final String CONTROL_SHUTDOWN = "shutdown";
121
122 /**
123 * The action name associated with the permission to call the
124 * <code>DaemonController.reload()</code> method.
125 */
126 protected static final String CONTROL_RELOAD = "reload";
127
128 /**
129 * The action mask associated with the permission to call the
130 * <code>DaemonController.start()</code> method.
131 */
132 protected static final int MASK_CONTROL_START = 0x01;
133
134 /**
135 * The action mask associated with the permission to call the
136 * <code>DaemonController.stop()</code> method.
137 */
138 protected static final int MASK_CONTROL_STOP = 0x02;
139
140 /**
141 * The action mask associated with the permission to call the
142 * <code>DaemonController.shutdown()</code> method.
143 */
144 protected static final int MASK_CONTROL_SHUTDOWN = 0x04;
145
146 /**
147 * The action mask associated with the permission to call the
148 * <code>DaemonController.reload()</code> method.
149 */
150 protected static final int MASK_CONTROL_RELOAD = 0x08;
151
152 /**
153 * The "wildcard" action implying all actions for the given
154 * target name.
155 */
156 protected static final String WILDCARD = "*";
157
158 /* ==================================================================== */
159 /* Instance variables */
160
161 /** The type of this permission object. */
162 private transient int type = 0;
163 /** The permission mask associated with this permission object. */
164 private transient int mask = 0;
165 /** The String representation of this permission object. */
166 private transient String desc = null;
167
168 /* ==================================================================== */
169 /* Constructors */
170
171 /**
172 * Create a new <code>DaemonPermission</code> instance with a specified
173 * permission name.
174 * <p>
175 * This constructor will create a new <code>DaemonPermission</code>
176 * instance that <b>will not</b> grant any permission to the caller.
177 *
178 * @param target The target name of this permission.
179 * @exception IllegalArgumentException If the specified target name is not
180 * supported.
181 */
182 public DaemonPermission (String target)
183 throws IllegalArgumentException {
184 // Setup the target name of this permission object.
185 super(target);
186
187 // Check if the permission target name was specified
188 if (target==null)
189 throw new IllegalArgumentException("Null permission name");
190
191 // Check if this is a "control" permission and set up accordingly.
192 if (CONTROL.equalsIgnoreCase(target)) {
193 type=TYPE_CONTROL;
194 return;
195 }
196
197 // If we got here, we have an invalid permission name.
198 throw new IllegalArgumentException("Invalid permission name \""+
199 target+"\" specified");
200 }
201
202 /**
203 * Create a new <code>DaemonPermission</code> instance with a specified
204 * permission name and a specified list of actions.
205 * <p>
206 * </p>
207 *
208 * @param target The target name of this permission.
209 * @param actions The list of actions permitted by this permission.
210 * @exception IllegalArgumentException If the specified target name is not
211 * supported, or the specified list of actions includes an
212 * invalid value.
213 */
214 public DaemonPermission(String target, String actions)
215 throws IllegalArgumentException {
216 // Setup this instance's target name.
217 this(target);
218
219 // Create the appropriate mask if this is a control permission.
220 if (this.type==TYPE_CONTROL) {
221 this.mask=this.createControlMask(actions);
222 return;
223 }
224 }
225
226 /* ==================================================================== */
227 /* Public methods */
228
229 /**
230 * Return the list of actions permitted by this instance of
231 * <code>DaemonPermission</code> in its canonical form.
232 *
233 * @return The canonicalized list of actions.
234 */
235 public String getActions() {
236 if (this.type==TYPE_CONTROL) {
237 return(this.createControlActions(this.mask));
238 }
239 return("");
240 }
241
242 /**
243 * Return the hash code for this <code>DaemonPermission</code> instance.
244 *
245 * @return An hash code value.
246 */
247 public int hashCode() {
248 this.setupDescription();
249 return(this.desc.hashCode());
250 }
251
252 /**
253 * Check if a specified object equals <code>DaemonPermission</code>.
254 *
255 * @return <b>true</b> or <b>false</b> wether the specified object equals
256 * this <code>DaemonPermission</code> instance or not.
257 */
258 public boolean equals(Object object) {
259 if (object == this) return(true);
260
261 if (!(object instanceof DaemonPermission)) return false;
262
263 DaemonPermission that = (DaemonPermission)object;
264
265 if (this.type!=that.type) return(false);
266 return(this.mask==that.mask);
267 }
268
269 /**
270 * Check if this <code>DaemonPermission</code> implies another
271 * <code>Permission</code>.
272 *
273 * @return <b>true</b> or <b>false</b> wether the specified permission
274 * is implied by this <code>DaemonPermission</code> instance or
275 * not.
276 */
277 public boolean implies(Permission permission) {
278 if (permission == this) return(true);
279
280 if (!(permission instanceof DaemonPermission)) return false;
281
282 DaemonPermission that = (DaemonPermission)permission;
283
284 if (this.type!=that.type) return(false);
285 return((this.mask&that.mask)==that.mask);
286 }
287
288 /**
289 * Return a <code>String</code> representation of this instance.
290 *
291 * @return A <code>String</code> representing this
292 * <code>DaemonPermission</code> instance.
293 */
294 public String toString() {
295 this.setupDescription();
296 return(new String(this.desc));
297 }
298
299 /* ==================================================================== */
300 /* Private methods */
301
302 /** Create a String description for this permission instance. */
303 private void setupDescription() {
304 if (this.desc!=null) return;
305
306 StringBuffer buf=new StringBuffer();
307 buf.append(this.getClass().getName());
308 buf.append('[');
309 switch (this.type) {
310 case (TYPE_CONTROL): {
311 buf.append(CONTROL);
312 break;
313 }
314 default: {
315 buf.append("UNKNOWN");
316 break;
317 }
318 }
319 buf.append(':');
320 buf.append(this.getActions());
321 buf.append(']');
322
323 this.desc=buf.toString();
324 }
325
326 /** Create a permission mask for a given control actions string. */
327 private int createControlMask(String actions)
328 throws IllegalArgumentException {
329 if (actions==null) return(0);
330
331 int mask=0;
332 StringTokenizer tok=new StringTokenizer(actions,",",false);
333 while (tok.hasMoreTokens()) {
334 String val=tok.nextToken().trim();
335
336 if (WILDCARD.equals(val)) {
337 return(MASK_CONTROL_START|MASK_CONTROL_STOP|
338 MASK_CONTROL_SHUTDOWN|MASK_CONTROL_RELOAD);
339 } else if (CONTROL_START.equalsIgnoreCase(val)) {
340 mask=mask|MASK_CONTROL_START;
341 } else if (CONTROL_STOP.equalsIgnoreCase(val)) {
342 mask=mask|MASK_CONTROL_STOP;
343 } else if (CONTROL_SHUTDOWN.equalsIgnoreCase(val)) {
344 mask=mask|MASK_CONTROL_SHUTDOWN;
345 } else if (CONTROL_RELOAD.equalsIgnoreCase(val)) {
346 mask=mask|MASK_CONTROL_RELOAD;
347 } else {
348 throw new IllegalArgumentException("Invalid action name \""+
349 val+"\" specified");
350 }
351 }
352 return(mask);
353 }
354
355 /** Create a actions list for a given control permission mask. */
356 private String createControlActions(int mask) {
357 StringBuffer buf=new StringBuffer();
358 boolean sep=false;
359
360 if ((mask&MASK_CONTROL_START)==MASK_CONTROL_START) {
361 sep=true;
362 buf.append(CONTROL_START);
363 }
364
365 if ((mask&MASK_CONTROL_STOP)==MASK_CONTROL_STOP) {
366 if (sep) buf.append(",");
367 else sep=true;
368 buf.append(CONTROL_STOP);
369 }
370
371 if ((mask&MASK_CONTROL_SHUTDOWN)==MASK_CONTROL_SHUTDOWN) {
372 if (sep) buf.append(",");
373 else sep=true;
374 buf.append(CONTROL_SHUTDOWN);
375 }
376
377 if ((mask&MASK_CONTROL_RELOAD)==MASK_CONTROL_RELOAD) {
378 if (sep) buf.append(",");
379 else sep=true;
380 buf.append(CONTROL_RELOAD);
381 }
382
383 return buf.toString();
384 }
385 }