DaemonPermission.java

  1. /*
  2.  *  Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */

  17. package org.apache.commons.daemon;

  18. import java.security.Permission;
  19. import java.util.StringTokenizer;

  20. /**
  21.  * Represents the permissions to control and query the status of
  22.  * a {@code Daemon}. A {@code DaemonPermission} consists of a
  23.  * target name and a list of actions associated with it.
  24.  * <p>
  25.  * In this specification version the only available target name for this
  26.  * permission is &quot;control&quot;, but further releases may add more target
  27.  * names to fine-tune the access that needs to be granted to the caller.
  28.  * </p>
  29.  * <p>
  30.  * Actions are defined by a string of comma-separated values, as shown in the
  31.  * table below. The empty string implies no permission at all, while the
  32.  * special &quot;*&quot; value implies all permissions for the given
  33.  * name:
  34.  * </p>
  35.  * <table border="1">
  36.  *  <caption>Supported Actions</caption>
  37.  *  <tr>
  38.  *   <th>Target&quot;Name</th>
  39.  *   <th>Action</th>
  40.  *   <th>Description</th>
  41.  *  </tr>
  42.  *  <tr>
  43.  *   <td rowspan="5">&quot;control&quot;</td>
  44.  *   <td>&quot;start&quot;</td>
  45.  *   <td>
  46.  *    The permission to call the {@code start()} method in an instance
  47.  *    of a {@code DaemonController} interface.
  48.  *   </td>
  49.  *  </tr>
  50.  *  <tr>
  51.  *   <td>&quot;stop&quot;</td>
  52.  *   <td>
  53.  *    The permission to call the {@code stop()} method in an instance
  54.  *    of a {@code DaemonController} interface.
  55.  *   </td>
  56.  *  </tr>
  57.  *  <tr>
  58.  *   <td>&quot;shutdown&quot;</td>
  59.  *   <td>
  60.  *    The permission to call the {@code shutdown()} method in an instance
  61.  *    of a {@code DaemonController} interface.
  62.  *   </td>
  63.  *  </tr>
  64.  *  <tr>
  65.  *   <td>&quot;reload&quot;</td>
  66.  *   <td>
  67.  *    The permission to call the {@code reload()} method in an instance
  68.  *    of a {@code DaemonController} interface.
  69.  *   </td>
  70.  *  </tr>
  71.  *  <tr>
  72.  *   <td>&quot;*&quot;</td>
  73.  *   <td>
  74.  *    The special wildcard action implies all above-mentioned action. This is
  75.  *    equal to construct a permission with the &quot;start, stop, shutdown,
  76.  *    reload&quot; list of actions.
  77.  *   </td>
  78.  *  </tr>
  79.  * </table>
  80.  */
  81. public final class DaemonPermission extends Permission
  82. {

  83.     /* ====================================================================
  84.      * Constants.
  85.      */

  86.     private static final long serialVersionUID = -8682149075879731987L;

  87.     /**
  88.      * The target name when associated with control actions
  89.      * (&quot;control&quot;).
  90.      */
  91.     protected static final String CONTROL = "control";

  92.     /**
  93.      * The target type when associated with control actions.
  94.      */
  95.     protected static final int TYPE_CONTROL = 1;

  96.     /**
  97.      * The action name associated with the permission to call the
  98.      * {@code DaemonController.start()} method.
  99.      */
  100.     protected static final String CONTROL_START = "start";

  101.     /**
  102.      * The action name associated with the permission to call the
  103.      * {@code DaemonController.stop()} method.
  104.      */
  105.     protected static final String CONTROL_STOP = "stop";

  106.     /**
  107.      * The action name associated with the permission to call the
  108.      * {@code DaemonController.shutdown()} method.
  109.      */
  110.     protected static final String CONTROL_SHUTDOWN = "shutdown";

  111.     /**
  112.      * The action name associated with the permission to call the
  113.      * {@code DaemonController.reload()} method.
  114.      */
  115.     protected static final String CONTROL_RELOAD = "reload";

  116.     /**
  117.      * The action mask associated with the permission to call the
  118.      * {@code DaemonController.start()} method.
  119.      */
  120.     protected static final int MASK_CONTROL_START = 0x01;

  121.     /**
  122.      * The action mask associated with the permission to call the
  123.      * {@code DaemonController.stop()} method.
  124.      */
  125.     protected static final int MASK_CONTROL_STOP = 0x02;

  126.     /**
  127.      * The action mask associated with the permission to call the
  128.      * {@code DaemonController.shutdown()} method.
  129.      */
  130.     protected static final int MASK_CONTROL_SHUTDOWN = 0x04;

  131.     /**
  132.      * The action mask associated with the permission to call the
  133.      * {@code DaemonController.reload()} method.
  134.      */
  135.     protected static final int MASK_CONTROL_RELOAD = 0x08;

  136.     /**
  137.      * The &quot;wildcard&quot; action implying all actions for the given
  138.      * target name.
  139.      */
  140.     protected static final String WILDCARD = "*";

  141.     /* ====================================================================
  142.      * Instance variables
  143.      */

  144.     /** The type of this permission object. */
  145.     private transient int type;
  146.     /** The permission mask associated with this permission object. */
  147.     private transient int mask;
  148.     /** The String representation of this permission object. */
  149.     private transient String desc;

  150.     /* ====================================================================
  151.      * Constructors
  152.      */

  153.     /**
  154.      * Creates a new {@code DaemonPermission} instance with a specified
  155.      * permission name.
  156.      * <p>
  157.      * This constructor will create a new {@code DaemonPermission}
  158.      * instance that <strong>will not</strong> grant any permission to the caller.
  159.      *
  160.      * @param target The target name of this permission.
  161.      * @throws IllegalArgumentException If the specified target name is not
  162.      *                supported.
  163.      */
  164.     public DaemonPermission(final String target)
  165.         throws IllegalArgumentException
  166.     {
  167.         // Set up the target name of this permission object.
  168.         super(target);

  169.         // Check if the permission target name was specified
  170.         if (target == null) {
  171.             throw new IllegalArgumentException("Null permission name");
  172.         }

  173.         // Check if this is a "control" permission and set up accordingly.
  174.         if (CONTROL.equalsIgnoreCase(target)) {
  175.             type = TYPE_CONTROL;
  176.             return;
  177.         }

  178.         // If we got here, we have an invalid permission name.
  179.         throw new IllegalArgumentException("Invalid permission name \"" +
  180.                                            target + "\" specified");
  181.     }

  182.     /**
  183.      * Creates a new {@code DaemonPermission} instance with a specified
  184.      * permission name and a specified list of actions.
  185.      *
  186.      * @param target The target name of this permission.
  187.      * @param actions The list of actions permitted by this permission.
  188.      * @throws IllegalArgumentException If the specified target name is not
  189.      *                supported, or the specified list of actions includes an
  190.      *                invalid value.
  191.      */
  192.     public DaemonPermission(final String target, final String actions)
  193.         throws IllegalArgumentException
  194.     {
  195.         // Setup this instance's target name.
  196.         this(target);

  197.         // Create the appropriate mask if this is a control permission.
  198.         if (this.type == TYPE_CONTROL) {
  199.             this.mask = createControlMask(actions);
  200.         }
  201.     }

  202.     /* ====================================================================
  203.      * Public methods
  204.      */

  205.     /**
  206.      * Returns the list of actions permitted by this instance of
  207.      * {@code DaemonPermission} in its canonical form.
  208.      *
  209.      * @return The canonicalized list of actions.
  210.      */
  211.     @Override
  212.     public String getActions()
  213.     {
  214.         if (this.type == TYPE_CONTROL) {
  215.             return createControlActions(this.mask);
  216.         }
  217.         return "";
  218.     }

  219.     /**
  220.      * Returns the hash code for this {@code DaemonPermission} instance.
  221.      *
  222.      * @return An hash code value.
  223.      */
  224.     @Override
  225.     public int hashCode()
  226.     {
  227.         setupDescription();
  228.         return this.desc.hashCode();
  229.     }

  230.     /**
  231.      * Checks if a specified object equals {@code DaemonPermission}.
  232.      *
  233.      * @return <strong>true</strong> or <strong>false</strong> whether the specified object equals
  234.      *         this {@code DaemonPermission} instance or not.
  235.      */
  236.     @Override
  237.     public boolean equals(final Object object)
  238.     {
  239.         if (object == this) {
  240.             return true;
  241.         }

  242.         if (!(object instanceof DaemonPermission)) {
  243.             return false;
  244.         }

  245.         final DaemonPermission that = (DaemonPermission) object;

  246.         if (this.type != that.type) {
  247.             return false;
  248.         }
  249.         return this.mask == that.mask;
  250.     }

  251.     /**
  252.      * Checks if this {@code DaemonPermission} implies another
  253.      * {@code Permission}.
  254.      *
  255.      * @return <strong>true</strong> or <strong>false</strong> whether the specified permission
  256.      *         is implied by this {@code DaemonPermission} instance or
  257.      *         not.
  258.      */
  259.     @Override
  260.     public boolean implies(final Permission permission)
  261.     {
  262.         if (permission == this) {
  263.             return true;
  264.         }

  265.         if (!(permission instanceof DaemonPermission)) {
  266.             return false;
  267.         }

  268.         final DaemonPermission that = (DaemonPermission) permission;

  269.         if (this.type != that.type) {
  270.             return false;
  271.         }
  272.         return (this.mask & that.mask) == that.mask;
  273.     }

  274.     /**
  275.      * Returns a {@code String} representation of this instance.
  276.      *
  277.      * @return A {@code String} representing this
  278.      *         {@code DaemonPermission} instance.
  279.      */
  280.     @Override
  281.     public String toString()
  282.     {
  283.         setupDescription();
  284.         return this.desc;
  285.     }

  286.     /* ====================================================================
  287.      * Private methods
  288.      */

  289.     /**
  290.      * Creates a String description for this permission instance.
  291.      */
  292.     private void setupDescription()
  293.     {
  294.         if (this.desc != null) {
  295.             return;
  296.         }

  297.         final StringBuilder buf = new StringBuilder();
  298.         buf.append(this.getClass().getName());
  299.         buf.append('[');
  300.         switch (this.type) {
  301.             case TYPE_CONTROL:
  302.                 buf.append(CONTROL);
  303.             break;
  304.             default:
  305.                 buf.append("UNKNOWN");
  306.             break;
  307.         }
  308.         buf.append(':');
  309.         buf.append(getActions());
  310.         buf.append(']');

  311.         this.desc = buf.toString();
  312.     }

  313.     /**
  314.      * Creates a permission mask for a given control actions string.
  315.      */
  316.     private int createControlMask(final String actions)
  317.         throws IllegalArgumentException
  318.     {
  319.         if (actions == null) {
  320.             return 0;
  321.         }

  322.         int mask = 0;
  323.         final StringTokenizer tok = new StringTokenizer(actions, ",", false);

  324.         while (tok.hasMoreTokens()) {
  325.             final String val = tok.nextToken().trim();

  326.             if (WILDCARD.equals(val)) {
  327.                 return MASK_CONTROL_START | MASK_CONTROL_STOP |
  328.                        MASK_CONTROL_SHUTDOWN | MASK_CONTROL_RELOAD;
  329.             }
  330.             if (CONTROL_START.equalsIgnoreCase(val)) {
  331.                 mask |= MASK_CONTROL_START;
  332.             }
  333.             else if (CONTROL_STOP.equalsIgnoreCase(val)) {
  334.                 mask |= MASK_CONTROL_STOP;
  335.             }
  336.             else if (CONTROL_SHUTDOWN.equalsIgnoreCase(val)) {
  337.                 mask |= MASK_CONTROL_SHUTDOWN;
  338.             }
  339.             else if (CONTROL_RELOAD.equalsIgnoreCase(val)) {
  340.                 mask |= MASK_CONTROL_RELOAD;
  341.             }
  342.             else {
  343.                 throw new IllegalArgumentException("Invalid action name \"" +
  344.                                                    val + "\" specified");
  345.             }
  346.         }
  347.         return mask;
  348.     }

  349.     /** Creates an actions list for a given control permission mask. */
  350.     private String createControlActions(final int mask)
  351.     {
  352.         final StringBuilder buf = new StringBuilder();
  353.         boolean sep = false;

  354.         if ((mask & MASK_CONTROL_START) == MASK_CONTROL_START) {
  355.             sep = true;
  356.             buf.append(CONTROL_START);
  357.         }

  358.         if ((mask & MASK_CONTROL_STOP) == MASK_CONTROL_STOP) {
  359.             if (sep) {
  360.                 buf.append(",");
  361.             }
  362.             else {
  363.                 sep = true;
  364.             }
  365.             buf.append(CONTROL_STOP);
  366.         }

  367.         if ((mask & MASK_CONTROL_SHUTDOWN) == MASK_CONTROL_SHUTDOWN) {
  368.             if (sep) {
  369.                 buf.append(",");
  370.             }
  371.             else {
  372.                 sep = true;
  373.             }
  374.             buf.append(CONTROL_SHUTDOWN);
  375.         }

  376.         if ((mask & MASK_CONTROL_RELOAD) == MASK_CONTROL_RELOAD) {
  377.             if (sep) {
  378.                 buf.append(",");
  379.             }
  380.             else {
  381.                 sep = true;
  382.             }
  383.             buf.append(CONTROL_RELOAD);
  384.         }

  385.         return buf.toString();
  386.     }
  387. }