AdHocCommand.java 10.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/**
 * $Revision: 3023 $
 * $Date: 2005-11-02 18:00:15 -0300 (Wed, 02 Nov 2005) $
 *
 * Copyright (C) 2005 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution.
 */

package org.jivesoftware.wildfire.commands;

import org.dom4j.Element;
import org.jivesoftware.wildfire.XMPPServer;
15
import org.xmpp.packet.JID;
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

import java.util.List;

/**
 * An ad-hoc command is a stateless object responsbile for executing the provided service. Each
 * subclass will only have one instance that will be shared across all users sessions. Therefore,
 * it is important to not keep any information related to executions as permanent data
 * (i.e. as instance or static variables). Each command has a <tt>code</tt> that should be
 * unique within a given JID.<p>
 *
 * Commands may have zero or more stages. Each stage is usually used for gathering information
 * required for the command execution. Users are able to move forward or backward across the
 * different stages. Commands may not be cancelled while they are beig executed. However, users
 * may request the "cancel" action when submiting a stage response indicating that the command
 * execution should be aborted. Thus, releasing any collected information. Commands that require
 * user interaction (i.e. have more than one stage) will have to provide the data forms the user
 * must complete in each stage and the allowed actions the user might perform during each stage
 * (e.g. go to the previous stage or go to the next stage).
 *
 * @author Gaston Dombiak
 */
public abstract class AdHocCommand {

    /**
     * Label of the command. This information may be used to display the command as a button
     * or menu item.
     */
    private String label = getDefaultLabel();

    public AdHocCommand() {
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    /**
     * Returns true if the requester is allowed to execute this command. By default only admins
     * are allowed to execute commands. Subclasses may redefine this method with any specific
     * logic.<p>
     *
     * Note: The bare JID of the requester will be compared with the bare JID of the admins.
     *
     * @param requester the JID of the user requesting to execute this command.
     * @return true if the requester is allowed to execute this command.
     */
    public boolean hasPermission(JID requester) {
        String requesterBareJID = requester.toBareJID();
        for (JID adminJID : XMPPServer.getInstance().getAdmins()) {
            if (adminJID.toBareJID().equals(requesterBareJID)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns the unique identifier for this command for the containing JID. The code will
     * be used as the node in the disco#items or the node when executing the command.
     *
     * @return the unique identifier for this command for the containing JID.
     */
    public abstract String getCode();

    /**
Gaston Dombiak's avatar
Gaston Dombiak committed
85 86 87
     * Returns the default label used for describing this commmand. This information is usually
     * used when returning commands as disco#items. Admins can later use {@link #setLabel(String)}
     * to set a new label and reset to the default value at any time.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
     *
     * @return the default label used for describing this commmand.
     */
    public abstract String getDefaultLabel();

    /**
     * Returns the max number of stages for this command. The number of stages may vary according
     * to the collected data in previous stages. Therefore, a SessionData object is passed as a
     * parameter. When the max number of stages has been reached then the command is ready to
     * be executed.
     *
     * @param data the gathered data through the command stages or <tt>null</tt> if the
     *        command does not have stages or the requester is requesting the execution for the
     *        first time.
     * @return the max number of stages for this command.
     */
    public abstract int getMaxStages(SessionData data);

    /**
     * Executes the command with the specified session data.
     *
     * @param data the gathered data through the command stages or <tt>null</tt> if the
     *        command does not have stages.
111 112
     * @param command the command element to be sent to the command requester with a reported
     *        data result or note element with the answer of the execution.
113
     */
114
    public abstract void execute(SessionData data, Element command);
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158

    /**
     * Adds to the command element the data form or notes required by the current stage. The
     * current stage is specified in the SessionData. This method will never be invoked for
     * commands that have no stages.
     *
     * @param data the gathered data through the command stages or <tt>null</tt> if the
     *        command does not have stages or the requester is requesting the execution for the
     *        first time.
     * @param command the command element to be sent to the command requester.
     */
    protected abstract void addStageInformation(SessionData data, Element command);

    /**
     * Returns a collection with the allowed actions based on the current stage as defined
     * in the SessionData. Possible actions are: <tt>prev</tt>, <tt>next</tt> and <tt>complete</tt>.
     * This method will never be invoked for commands that have no stages.
     *
     * @param data the gathered data through the command stages or <tt>null</tt> if the
     *        command does not have stages or the requester is requesting the execution for the
     *        first time.
     * @return a collection with the allowed actions based on the current stage as defined
     *         in the SessionData.
     */
    protected abstract List<Action> getActions(SessionData data);

    /**
     * Returns which of the actions available for the current stage is considered the equivalent
     * to "execute". When the requester sends his reply, if no action was defined in the command
     * then the action will be assumed "execute" thus assuming the action returned by this
     * method. This method will never be invoked for commands that have no stages.
     *
     * @param data the gathered data through the command stages or <tt>null</tt> if the
     *        command does not have stages or the requester is requesting the execution for the
     *        first time.
     * @return which of the actions available for the current stage is considered the equivalent
     *         to "execute".
     */
    protected abstract Action getExecuteAction(SessionData data);

    /**
     * Increments the stage number by one and adds to the command element the new data form and
     * new allowed actions that the user might perform.
     *
159
     * @param data the gathered data through the command stages.
160 161 162 163 164 165 166 167 168 169 170 171 172 173
     * @param command the command element to be sent to the command requester.
     */
    public void addNextStageInformation(SessionData data, Element command) {
        // Increment the stage number to the next stage
        data.setStage(data.getStage() + 1);
        // Return the data form of the current stage to the command requester. The
        // requester will need to specify the action to follow (e.g. execute, prev,
        // cancel, etc.) and complete the form is going "forward"
        addStageInformation(data, command);
        // Include the available actions at this stage
        addStageActions(data, command);
    }

    /**
174
     * Decrements the stage number by one and adds to the command the data form and allowed
175 176
     * actions that the user might perform of the previous stage.
     *
177
     * @param data the gathered data through the command stages.
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
     * @param command the command element to be sent to the command requester.
     */
    public void addPreviousStageInformation(SessionData data, Element command) {
        // Decrement the stage number to the previous stage
        data.setStage(data.getStage() - 1);
        // Return the data form of the current stage to the command requester. The
        // requester will need to specify the action to follow (e.g. execute, prev,
        // cancel, etc.) and complete the form is going "forward"
        addStageInformation(data, command);
        // Include the available actions at this stage
        addStageActions(data, command);
    }

    /**
     * Adds the allowed actions to follow from the current stage. Possible actions are:
     * <tt>prev</tt>, <tt>next</tt> and <tt>complete</tt>.
     *
     * @param data the gathered data through the command stages or <tt>null</tt> if the
     *        command does not have stages or the requester is requesting the execution for the
     *        first time.
     * @param command the command element to be sent to the command requester.
     */
    protected void addStageActions(SessionData data, Element command) {
        // Add allowed actions to the response
        Element actions = command.addElement("actions");
        List<Action> validActions = getActions(data);
        for (AdHocCommand.Action action : validActions) {
            actions.addElement(action.name());
        }
        Action executeAction = getExecuteAction(data);
        // Add default execute action to the response
        actions.addAttribute("execute", executeAction.name());

        // Store the allowed actions that the user can follow from this stage
        data.setAllowedActions(validActions);
        // Store the default execute action to follow if the user does not specify an
        // action in his command
        data.setExecuteAction(executeAction);
    }

    public enum Status {

        /**
         * The command is being executed.
         */
        executing,

        /**
         * The command has completed. The command session has ended.
         */
        completed,

        /**
         * The command has been canceled. The command session has ended.
         */
Gaston Dombiak's avatar
Gaston Dombiak committed
233
        canceled
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
    }

    public enum Action {

        /**
         * The command should be executed or continue to be executed. This is the default value.
         */
        execute,

        /**
         * The command should be canceled.
         */
        cancel,

        /**
         * The command should be digress to the previous stage of execution.
         */
        prev,

        /**
         * The command should progress to the next stage of execution.
         */
        next,

        /**
         * The command should be completed (if possible).
         */
Gaston Dombiak's avatar
Gaston Dombiak committed
261
        complete
262 263
    }
}