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 }