/** | |
* $RCSfile$ | |
* $Revision$ | |
* $Date$ | |
* | |
* Copyright 2005-2007 Jive Software. | |
* | |
* All rights reserved. Licensed 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.jivesoftware.smackx.commands; | |
import org.jivesoftware.smack.XMPPException; | |
import org.jivesoftware.smack.packet.XMPPError; | |
import org.jivesoftware.smackx.Form; | |
import org.jivesoftware.smackx.packet.AdHocCommandData; | |
import java.util.List; | |
/** | |
* An ad-hoc command is responsible for executing the provided service and | |
* storing the result of the execution. Each new request will create a new | |
* instance of the command, allowing information related to executions to be | |
* stored in it. For example suppose that a command that retrieves the list of | |
* users on a server is implemented. When the command is executed it gets that | |
* list and the result is stored as a form in the command instance, i.e. the | |
* <code>getForm</code> method retrieves a form with all the users. | |
* <p> | |
* Each command has a <tt>node</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 being executed. However, users may request the | |
* "cancel" action when submitting 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). | |
* <p> | |
* All the actions may throw an XMPPException if there is a problem executing | |
* them. The <code>XMPPError</code> of that exception may have some specific | |
* information about the problem. The possible extensions are: | |
* | |
* <li><i>malformed-action</i>. Extension of a <i>bad-request</i> error.</li> | |
* <li><i>bad-action</i>. Extension of a <i>bad-request</i> error.</li> | |
* <li><i>bad-locale</i>. Extension of a <i>bad-request</i> error.</li> | |
* <li><i>bad-payload</i>. Extension of a <i>bad-request</i> error.</li> | |
* <li><i>bad-sessionid</i>. Extension of a <i>bad-request</i> error.</li> | |
* <li><i>session-expired</i>. Extension of a <i>not-allowed</i> error.</li> | |
* <p> | |
* See the <code>SpecificErrorCondition</code> class for detailed description | |
* of each one. | |
* <p> | |
* Use the <code>getSpecificErrorConditionFrom</code> to obtain the specific | |
* information from an <code>XMPPError</code>. | |
* | |
* @author Gabriel Guardincerri | |
* | |
*/ | |
public abstract class AdHocCommand { | |
// TODO: Analyze the redesign of command by having an ExecutionResponse as a | |
// TODO: result to the execution of every action. That result should have all the | |
// TODO: information related to the execution, e.g. the form to fill. Maybe this | |
// TODO: design is more intuitive and simpler than the current one that has all in | |
// TODO: one class. | |
private AdHocCommandData data; | |
public AdHocCommand() { | |
super(); | |
data = new AdHocCommandData(); | |
} | |
/** | |
* Returns the specific condition of the <code>error</code> or <tt>null</tt> if the | |
* error doesn't have any. | |
* | |
* @param error the error the get the specific condition from. | |
* @return the specific condition of this error, or null if it doesn't have | |
* any. | |
*/ | |
public static SpecificErrorCondition getSpecificErrorCondition(XMPPError error) { | |
// This method is implemented to provide an easy way of getting a packet | |
// extension of the XMPPError. | |
for (SpecificErrorCondition condition : SpecificErrorCondition.values()) { | |
if (error.getExtension(condition.toString(), | |
AdHocCommandData.SpecificError.namespace) != null) { | |
return condition; | |
} | |
} | |
return null; | |
} | |
/** | |
* Set the the human readable name of the command, usually used for | |
* displaying in a UI. | |
* | |
* @param name the name. | |
*/ | |
public void setName(String name) { | |
data.setName(name); | |
} | |
/** | |
* Returns the human readable name of the command. | |
* | |
* @return the human readable name of the command | |
*/ | |
public String getName() { | |
return data.getName(); | |
} | |
/** | |
* Sets the unique identifier of the command. This value must be unique for | |
* the <code>OwnerJID</code>. | |
* | |
* @param node the unique identifier of the command. | |
*/ | |
public void setNode(String node) { | |
data.setNode(node); | |
} | |
/** | |
* Returns the unique identifier of the command. It is unique for the | |
* <code>OwnerJID</code>. | |
* | |
* @return the unique identifier of the command. | |
*/ | |
public String getNode() { | |
return data.getNode(); | |
} | |
/** | |
* Returns the full JID of the owner of this command. This JID is the "to" of a | |
* execution request. | |
* | |
* @return the owner JID. | |
*/ | |
public abstract String getOwnerJID(); | |
/** | |
* Returns the notes that the command has at the current stage. | |
* | |
* @return a list of notes. | |
*/ | |
public List<AdHocCommandNote> getNotes() { | |
return data.getNotes(); | |
} | |
/** | |
* Adds a note to the current stage. This should be used when setting a | |
* response to the execution of an action. All the notes added here are | |
* returned by the {@link #getNotes} method during the current stage. | |
* Once the stage changes all the notes are discarded. | |
* | |
* @param note the note. | |
*/ | |
protected void addNote(AdHocCommandNote note) { | |
data.addNote(note); | |
} | |
public String getRaw() { | |
return data.getChildElementXML(); | |
} | |
/** | |
* Returns the form of the current stage. Usually it is the form that must | |
* be answered to execute the next action. If that is the case it should be | |
* used by the requester to fill all the information that the executor needs | |
* to continue to the next stage. It can also be the result of the | |
* execution. | |
* | |
* @return the form of the current stage to fill out or the result of the | |
* execution. | |
*/ | |
public Form getForm() { | |
if (data.getForm() == null) { | |
return null; | |
} | |
else { | |
return new Form(data.getForm()); | |
} | |
} | |
/** | |
* Sets the form of the current stage. This should be used when setting a | |
* response. It could be a form to fill out the information needed to go to | |
* the next stage or the result of an execution. | |
* | |
* @param form the form of the current stage to fill out or the result of the | |
* execution. | |
*/ | |
protected void setForm(Form form) { | |
data.setForm(form.getDataFormToSend()); | |
} | |
/** | |
* Executes the command. This is invoked only on the first stage of the | |
* command. It is invoked on every command. If there is a problem executing | |
* the command it throws an XMPPException. | |
* | |
* @throws XMPPException if there is an error executing the command. | |
*/ | |
public abstract void execute() throws XMPPException; | |
/** | |
* Executes the next action of the command with the information provided in | |
* the <code>response</code>. This form must be the answer form of the | |
* previous stage. This method will be only invoked for commands that have one | |
* or more stages. If there is a problem executing the command it throws an | |
* XMPPException. | |
* | |
* @param response the form answer of the previous stage. | |
* @throws XMPPException if there is a problem executing the command. | |
*/ | |
public abstract void next(Form response) throws XMPPException; | |
/** | |
* Completes the command execution with the information provided in the | |
* <code>response</code>. This form must be the answer form of the | |
* previous stage. This method will be only invoked for commands that have one | |
* or more stages. If there is a problem executing the command it throws an | |
* XMPPException. | |
* | |
* @param response the form answer of the previous stage. | |
* @throws XMPPException if there is a problem executing the command. | |
*/ | |
public abstract void complete(Form response) throws XMPPException; | |
/** | |
* Goes to the previous stage. The requester is asking to re-send the | |
* information of the previous stage. The command must change it state to | |
* the previous one. If there is a problem executing the command it throws | |
* an XMPPException. | |
* | |
* @throws XMPPException if there is a problem executing the command. | |
*/ | |
public abstract void prev() throws XMPPException; | |
/** | |
* Cancels the execution of the command. This can be invoked on any stage of | |
* the execution. If there is a problem executing the command it throws an | |
* XMPPException. | |
* | |
* @throws XMPPException if there is a problem executing the command. | |
*/ | |
public abstract void cancel() throws XMPPException; | |
/** | |
* Returns a collection with the allowed actions based on the current stage. | |
* Possible actions are: {@link Action#prev prev}, {@link Action#next next} and | |
* {@link Action#complete complete}. This method will be only invoked for commands that | |
* have one or more stages. | |
* | |
* @return a collection with the allowed actions based on the current stage | |
* as defined in the SessionData. | |
*/ | |
protected List<Action> getActions() { | |
return data.getActions(); | |
} | |
/** | |
* Add an action to the current stage available actions. This should be used | |
* when creating a response. | |
* | |
* @param action the action. | |
*/ | |
protected void addActionAvailable(Action action) { | |
data.addAction(action); | |
} | |
/** | |
* Returns the action available for the current stage which 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. | |
* | |
* @return the action available for the current stage which is considered | |
* the equivalent to "execute". | |
*/ | |
protected Action getExecuteAction() { | |
return data.getExecuteAction(); | |
} | |
/** | |
* Sets which of the actions available for the current stage is | |
* considered the equivalent to "execute". This should be used when setting | |
* a response. 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. | |
* | |
* @param action the action. | |
*/ | |
protected void setExecuteAction(Action action) { | |
data.setExecuteAction(action); | |
} | |
/** | |
* Returns the status of the current stage. | |
* | |
* @return the current status. | |
*/ | |
public Status getStatus() { | |
return data.getStatus(); | |
} | |
/** | |
* Sets the data of the current stage. This should not used. | |
* | |
* @param data the data. | |
*/ | |
void setData(AdHocCommandData data) { | |
this.data = data; | |
} | |
/** | |
* Gets the data of the current stage. This should not used. | |
* | |
* @return the data. | |
*/ | |
AdHocCommandData getData() { | |
return data; | |
} | |
/** | |
* Returns true if the <code>action</code> is available in the current stage. | |
* The {@link Action#cancel cancel} action is always allowed. To define the | |
* available actions use the <code>addActionAvailable</code> method. | |
* | |
* @param action | |
* The action to check if it is available. | |
* @return True if the action is available for the current stage. | |
*/ | |
protected boolean isValidAction(Action action) { | |
return getActions().contains(action) || Action.cancel.equals(action); | |
} | |
/** | |
* The status of the stage in the adhoc command. | |
*/ | |
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. | |
*/ | |
canceled | |
} | |
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). | |
*/ | |
complete, | |
/** | |
* The action is unknow. This is used when a recieved message has an | |
* unknown action. It must not be used to send an execution request. | |
*/ | |
unknown | |
} | |
public enum SpecificErrorCondition { | |
/** | |
* The responding JID cannot accept the specified action. | |
*/ | |
badAction("bad-action"), | |
/** | |
* The responding JID does not understand the specified action. | |
*/ | |
malformedAction("malformed-action"), | |
/** | |
* The responding JID cannot accept the specified language/locale. | |
*/ | |
badLocale("bad-locale"), | |
/** | |
* The responding JID cannot accept the specified payload (e.g. the data | |
* form did not provide one or more required fields). | |
*/ | |
badPayload("bad-payload"), | |
/** | |
* The responding JID cannot accept the specified sessionid. | |
*/ | |
badSessionid("bad-sessionid"), | |
/** | |
* The requesting JID specified a sessionid that is no longer active | |
* (either because it was completed, canceled, or timed out). | |
*/ | |
sessionExpired("session-expired"); | |
private String value; | |
SpecificErrorCondition(String value) { | |
this.value = value; | |
} | |
public String toString() { | |
return value; | |
} | |
} | |
} |