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 018package org.apache.commons.daemon; 019 020import java.security.Permission; 021import java.util.StringTokenizer; 022 023/** 024 * 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 $Id: DaemonPermission.java 1204010 2011-11-19 16:15:23Z ggregory $ 087 */ 088public 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 * Creates 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 * Creates 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 * Returns 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 * Returns 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 * Checks 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 * Checks 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 * Returns 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 /** 322 * Creates a String description for this permission instance. 323 */ 324 private void setupDescription() 325 { 326 if (this.desc != null) 327 return; 328 329 StringBuffer buf = new StringBuffer(); 330 buf.append(this.getClass().getName()); 331 buf.append('['); 332 switch (this.type) { 333 case TYPE_CONTROL: 334 buf.append(CONTROL); 335 break; 336 default: 337 buf.append("UNKNOWN"); 338 break; 339 } 340 buf.append(':'); 341 buf.append(this.getActions()); 342 buf.append(']'); 343 344 this.desc = buf.toString(); 345 } 346 347 /** 348 * Creates a permission mask for a given control actions string. 349 */ 350 private int createControlMask(String actions) 351 throws IllegalArgumentException 352 { 353 if (actions == null) 354 return 0; 355 356 int mask = 0; 357 StringTokenizer tok = new StringTokenizer(actions, ",", false); 358 359 while (tok.hasMoreTokens()) { 360 String val = tok.nextToken().trim(); 361 362 if (WILDCARD.equals(val)) { 363 return MASK_CONTROL_START | MASK_CONTROL_STOP | 364 MASK_CONTROL_SHUTDOWN | MASK_CONTROL_RELOAD; 365 } 366 else if (CONTROL_START.equalsIgnoreCase(val)) { 367 mask = mask | MASK_CONTROL_START; 368 } 369 else if (CONTROL_STOP.equalsIgnoreCase(val)) { 370 mask = mask | MASK_CONTROL_STOP; 371 } 372 else if (CONTROL_SHUTDOWN.equalsIgnoreCase(val)) { 373 mask = mask | MASK_CONTROL_SHUTDOWN; 374 } 375 else if (CONTROL_RELOAD.equalsIgnoreCase(val)) { 376 mask = mask | MASK_CONTROL_RELOAD; 377 } 378 else { 379 throw new IllegalArgumentException("Invalid action name \"" + 380 val + "\" specified"); 381 } 382 } 383 return mask; 384 } 385 386 /** Creates a actions list for a given control permission mask. */ 387 private String createControlActions(int mask) 388 { 389 StringBuffer buf = new StringBuffer(); 390 boolean sep = false; 391 392 if ((mask & MASK_CONTROL_START) == MASK_CONTROL_START) { 393 sep = true; 394 buf.append(CONTROL_START); 395 } 396 397 if ((mask & MASK_CONTROL_STOP) == MASK_CONTROL_STOP) { 398 if (sep) 399 buf.append(","); 400 else 401 sep = true; 402 buf.append(CONTROL_STOP); 403 } 404 405 if ((mask & MASK_CONTROL_SHUTDOWN) == MASK_CONTROL_SHUTDOWN) { 406 if (sep) 407 buf.append(","); 408 else 409 sep = true; 410 buf.append(CONTROL_SHUTDOWN); 411 } 412 413 if ((mask & MASK_CONTROL_RELOAD) == MASK_CONTROL_RELOAD) { 414 if (sep) 415 buf.append(","); 416 else 417 sep = true; 418 buf.append(CONTROL_RELOAD); 419 } 420 421 return buf.toString(); 422 } 423} 424