/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.daemon; import java.security.Permission; import java.util.StringTokenizer; /** * Represents the permissions to control and query the status of * a <code>Daemon</code>. A <code>DaemonPermission</code> consists of a * target name and a list of actions associated with it. * <p> * In this specification version the only available target name for this * permission is "control", but further releases may add more target * names to fine-tune the access that needs to be granted to the caller. * </p> * <p> * Actions are defined by a string of comma-separated values, as shown in the * table below. The empty string implies no permission at all, while the * special "*" value implies all permissions for the given * name: * </p> * <p> * <table width="100%" border="1"> * <tr> * <th>Target"Name</th> * <th>Action</th> * <th>Description</th> * </tr> * <tr> * <td rowspan="5">"control"</td> * <td>"start"</td> * <td> * The permission to call the <code>start()</code> method in an instance * of a <code>DaemonController</code> interface. * </td> * </tr> * <tr> * <td>"stop"</td> * <td> * The permission to call the <code>stop()</code> method in an instance * of a <code>DaemonController</code> interface. * </td> * </tr> * <tr> * <td>"shutdown"</td> * <td> * The permission to call the <code>shutdown()</code> method in an instance * of a <code>DaemonController</code> interface. * </td> * </tr> * <tr> * <td>"reload"</td> * <td> * The permission to call the <code>reload()</code> method in an instance * of a <code>DaemonController</code> interface. * </td> * </tr> * <tr> * <td>"*"</td> * <td> * The special wildcard action implies all above-mentioned action. This is * equal to construct a permission with the "start, stop, shutdown, * reload" list of actions. * </td> * </tr> * </table> * </p> * * @author Pier Fumagalli * @version $Id: DaemonPermission.java 1204010 2011-11-19 16:15:23Z ggregory $ */ public final class DaemonPermission extends Permission { /* ==================================================================== * Constants. */ /** * The target name when associated with control actions * ("control"). */ protected static final String CONTROL = "control"; /** * The target type when associated with control actions. */ protected static final int TYPE_CONTROL = 1; /** * The action name associated with the permission to call the * <code>DaemonController.start()</code> method. */ protected static final String CONTROL_START = "start"; /** * The action name associated with the permission to call the * <code>DaemonController.stop()</code> method. */ protected static final String CONTROL_STOP = "stop"; /** * The action name associated with the permission to call the * <code>DaemonController.shutdown()</code> method. */ protected static final String CONTROL_SHUTDOWN = "shutdown"; /** * The action name associated with the permission to call the * <code>DaemonController.reload()</code> method. */ protected static final String CONTROL_RELOAD = "reload"; /** * The action mask associated with the permission to call the * <code>DaemonController.start()</code> method. */ protected static final int MASK_CONTROL_START = 0x01; /** * The action mask associated with the permission to call the * <code>DaemonController.stop()</code> method. */ protected static final int MASK_CONTROL_STOP = 0x02; /** * The action mask associated with the permission to call the * <code>DaemonController.shutdown()</code> method. */ protected static final int MASK_CONTROL_SHUTDOWN = 0x04; /** * The action mask associated with the permission to call the * <code>DaemonController.reload()</code> method. */ protected static final int MASK_CONTROL_RELOAD = 0x08; /** * The "wildcard" action implying all actions for the given * target name. */ protected static final String WILDCARD = "*"; /* ==================================================================== * Instance variables */ /** The type of this permission object. */ private transient int type = 0; /** The permission mask associated with this permission object. */ private transient int mask = 0; /** The String representation of this permission object. */ private transient String desc = null; /* ==================================================================== * Constructors */ /** * Creates a new <code>DaemonPermission</code> instance with a specified * permission name. * <p> * This constructor will create a new <code>DaemonPermission</code> * instance that <b>will not</b> grant any permission to the caller. * * @param target The target name of this permission. * @exception IllegalArgumentException If the specified target name is not * supported. */ public DaemonPermission(String target) throws IllegalArgumentException { // Setup the target name of this permission object. super(target); // Check if the permission target name was specified if (target == null) throw new IllegalArgumentException("Null permission name"); // Check if this is a "control" permission and set up accordingly. if (CONTROL.equalsIgnoreCase(target)) { type = TYPE_CONTROL; return; } // If we got here, we have an invalid permission name. throw new IllegalArgumentException("Invalid permission name \"" + target + "\" specified"); } /** * Creates a new <code>DaemonPermission</code> instance with a specified * permission name and a specified list of actions. * <p> * </p> * * @param target The target name of this permission. * @param actions The list of actions permitted by this permission. * @exception IllegalArgumentException If the specified target name is not * supported, or the specified list of actions includes an * invalid value. */ public DaemonPermission(String target, String actions) throws IllegalArgumentException { // Setup this instance's target name. this(target); // Create the appropriate mask if this is a control permission. if (this.type == TYPE_CONTROL) { this.mask = this.createControlMask(actions); return; } } /* ==================================================================== * Public methods */ /** * Returns the list of actions permitted by this instance of * <code>DaemonPermission</code> in its canonical form. * * @return The canonicalized list of actions. */ public String getActions() { if (this.type == TYPE_CONTROL) { return this.createControlActions(this.mask); } return ""; } /** * Returns the hash code for this <code>DaemonPermission</code> instance. * * @return An hash code value. */ public int hashCode() { this.setupDescription(); return this.desc.hashCode(); } /** * Checks if a specified object equals <code>DaemonPermission</code>. * * @return <b>true</b> or <b>false</b> wether the specified object equals * this <code>DaemonPermission</code> instance or not. */ public boolean equals(Object object) { if (object == this) return true; if (!(object instanceof DaemonPermission)) return false; DaemonPermission that = (DaemonPermission) object; if (this.type != that.type) return false; return this.mask == that.mask; } /** * Checks if this <code>DaemonPermission</code> implies another * <code>Permission</code>. * * @return <b>true</b> or <b>false</b> wether the specified permission * is implied by this <code>DaemonPermission</code> instance or * not. */ public boolean implies(Permission permission) { if (permission == this) return true; if (!(permission instanceof DaemonPermission)) return false; DaemonPermission that = (DaemonPermission) permission; if (this.type != that.type) return false; return (this.mask & that.mask) == that.mask; } /** * Returns a <code>String</code> representation of this instance. * * @return A <code>String</code> representing this * <code>DaemonPermission</code> instance. */ public String toString() { this.setupDescription(); return this.desc; } /* ==================================================================== * Private methods */ /** * Creates a String description for this permission instance. */ private void setupDescription() { if (this.desc != null) return; StringBuffer buf = new StringBuffer(); buf.append(this.getClass().getName()); buf.append('['); switch (this.type) { case TYPE_CONTROL: buf.append(CONTROL); break; default: buf.append("UNKNOWN"); break; } buf.append(':'); buf.append(this.getActions()); buf.append(']'); this.desc = buf.toString(); } /** * Creates a permission mask for a given control actions string. */ private int createControlMask(String actions) throws IllegalArgumentException { if (actions == null) return 0; int mask = 0; StringTokenizer tok = new StringTokenizer(actions, ",", false); while (tok.hasMoreTokens()) { String val = tok.nextToken().trim(); if (WILDCARD.equals(val)) { return MASK_CONTROL_START | MASK_CONTROL_STOP | MASK_CONTROL_SHUTDOWN | MASK_CONTROL_RELOAD; } else if (CONTROL_START.equalsIgnoreCase(val)) { mask = mask | MASK_CONTROL_START; } else if (CONTROL_STOP.equalsIgnoreCase(val)) { mask = mask | MASK_CONTROL_STOP; } else if (CONTROL_SHUTDOWN.equalsIgnoreCase(val)) { mask = mask | MASK_CONTROL_SHUTDOWN; } else if (CONTROL_RELOAD.equalsIgnoreCase(val)) { mask = mask | MASK_CONTROL_RELOAD; } else { throw new IllegalArgumentException("Invalid action name \"" + val + "\" specified"); } } return mask; } /** Creates a actions list for a given control permission mask. */ private String createControlActions(int mask) { StringBuffer buf = new StringBuffer(); boolean sep = false; if ((mask & MASK_CONTROL_START) == MASK_CONTROL_START) { sep = true; buf.append(CONTROL_START); } if ((mask & MASK_CONTROL_STOP) == MASK_CONTROL_STOP) { if (sep) buf.append(","); else sep = true; buf.append(CONTROL_STOP); } if ((mask & MASK_CONTROL_SHUTDOWN) == MASK_CONTROL_SHUTDOWN) { if (sep) buf.append(","); else sep = true; buf.append(CONTROL_SHUTDOWN); } if ((mask & MASK_CONTROL_RELOAD) == MASK_CONTROL_RELOAD) { if (sep) buf.append(","); else sep = true; buf.append(CONTROL_RELOAD); } return buf.toString(); } }