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 &quot;control&quot;, 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 &quot;*&quot; value implies all permissions for the given
036     * name:
037     * </p>
038     * <p>
039     * <table width="100%" border="1">
040     *  <tr>
041     *   <th>Target&quot;Name</th>
042     *   <th>Action</th>
043     *   <th>Description</th>
044     *  </tr>
045     *  <tr>
046     *   <td rowspan="5">&quot;control&quot;</td>
047     *   <td>&quot;start&quot;</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>&quot;stop&quot;</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>&quot;shutdown&quot;</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>&quot;reload&quot;</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>&quot;*&quot;</td>
076     *   <td>
077     *    The special wildcard action implies all above-mentioned action. This is
078     *    equal to construct a permission with the &quot;start, stop, shutdown,
079     *    reload&quot; 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         * (&quot;control&quot;).
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 &quot;wildcard&quot; 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    }