if (requestData.getType() != IQ.Type.SET) {
return;
}
// Creates the response with the corresponding data
AdHocCommandData response = new AdHocCommandData();
response.setTo(requestData.getFrom());
response.setPacketID(requestData.getPacketID());
response.setNode(requestData.getNode());
response.setId(requestData.getTo());
String sessionId = requestData.getSessionID();
String commandNode = requestData.getNode();
if (sessionId == null) {
// A new execution request has been received. Check that the
// command exists
if (!commands.containsKey(commandNode)) {
// Requested command does not exist so return
// item_not_found error.
respondError(response, XMPPError.Condition.item_not_found);
return;
}
// Create new session ID
sessionId = StringUtils.randomString(15);
try {
// Create a new instance of the command with the
// corresponding sessioid
LocalCommand command = newInstanceOfCmd(commandNode, sessionId);
response.setType(IQ.Type.RESULT);
command.setData(response);
// Check that the requester has enough permission.
// Answer forbidden error if requester permissions are not
// enough to execute the requested command
if (!command.hasPermission(requestData.getFrom())) {
respondError(response, XMPPError.Condition.forbidden);
return;
}
Action action = requestData.getAction();
// If the action is unknown then respond an error.
if (action != null && action.equals(Action.unknown)) {
respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.malformedAction);
return;
}
// If the action is not execute, then it is an invalid action.
if (action != null && !action.equals(Action.execute)) {
respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.badAction);
return;
}
// Increase the state number, so the command knows in witch
// stage it is
command.incrementStage();
// Executes the command
command.execute();
if (command.isLastStage()) {
// If there is only one stage then the command is completed
response.setStatus(Status.completed);
}
else {
// Else it is still executing, and is registered to be
// available for the next call
response.setStatus(Status.executing);
executingCommands.put(sessionId, command);
// See if the session reaping thread is started. If not, start it.
if (sessionsSweeper == null) {
sessionsSweeper = new Thread(new Runnable() {
public void run() {
while (true) {
for (String sessionId : executingCommands.keySet()) {
LocalCommand command = executingCommands.get(sessionId);
// Since the command could be removed in the meanwhile
// of getting the key and getting the value - by a
// processed packet. We must check if it still in the
// map.
if (command != null) {
long creationStamp = command.getCreationDate();
// Check if the Session data has expired (default is
// 10 minutes)
// To remove it from the session list it waits for
// the double of the of time out time. This is to
// let
// the requester know why his execution request is
// not accepted. If the session is removed just
// after the time out, then whe the user request to
// continue the execution he will recieved an
// invalid session error and not a time out error.
if (System.currentTimeMillis() - creationStamp > SESSION_TIMEOUT * 1000 * 2) {
// Remove the expired session
executingCommands.remove(sessionId);
}
}
}
try {
Thread.sleep(1000);
}
catch (InterruptedException ie) {
// Ignore.
}
}
}
});
sessionsSweeper.setDaemon(true);
sessionsSweeper.start();
}
}
// Sends the response packet
connection.sendPacket(response);
}
catch (XMPPException e) {
// If there is an exception caused by the next, complete,
// prev or cancel method, then that error is returned to the
// requester.
XMPPError error = e.getXMPPError();
// If the error type is cancel, then the execution is
// canceled therefore the status must show that, and the
// command be removed from the executing list.
if (XMPPError.Type.CANCEL.equals(error.getType())) {
response.setStatus(Status.canceled);
executingCommands.remove(sessionId);
}
respondError(response, error);
e.printStackTrace();
}
}
else {
LocalCommand command = executingCommands.get(sessionId);
// Check that a command exists for the specified sessionID
// This also handles if the command was removed in the meanwhile
// of getting the key and the value of the map.
if (command == null) {
respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.badSessionid);
return;
}
// Check if the Session data has expired (default is 10 minutes)
long creationStamp = command.getCreationDate();
if (System.currentTimeMillis() - creationStamp > SESSION_TIMEOUT * 1000) {
// Remove the expired session
executingCommands.remove(sessionId);
// Answer a not_allowed error (session-expired)
respondError(response, XMPPError.Condition.not_allowed,
AdHocCommand.SpecificErrorCondition.sessionExpired);
return;
}
/*
* Since the requester could send two requests for the same
* executing command i.e. the same session id, all the execution of
* the action must be synchronized to avoid inconsistencies.
*/
synchronized (command) {
Action action = requestData.getAction();
// If the action is unknown the respond an error
if (action != null && action.equals(Action.unknown)) {
respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.malformedAction);
return;
}
// If the user didn't specify an action or specify the execute
// action then follow the actual default execute action
if (action == null || Action.execute.equals(action)) {
action = command.getExecuteAction();
}
// Check that the specified action was previously
// offered
if (!command.isValidAction(action)) {
respondError(response, XMPPError.Condition.bad_request,
AdHocCommand.SpecificErrorCondition.badAction);
return;
}
try {
// TODO: Check that all the requierd fields of the form are
// TODO: filled, if not throw an exception. This will simplify the
// TODO: construction of new commands
// Since all errors were passed, the response is now a
// result
response.setType(IQ.Type.RESULT);
// Set the new data to the command.
command.setData(response);
if (Action.next.equals(action)) {
command.incrementStage();
command.next(new Form(requestData.getForm()));
if (command.isLastStage()) {
// If it is the last stage then the command is
// completed
response.setStatus(Status.completed);
}
else {
// Otherwise it is still executing
response.setStatus(Status.executing);
}
}
else if (Action.complete.equals(action)) {
command.incrementStage();
command.complete(new Form(requestData.getForm()));
response.setStatus(Status.completed);
// Remove the completed session
executingCommands.remove(sessionId);
}
else if (Action.prev.equals(action)) {
command.decrementStage();
command.prev();
}
else if (Action.cancel.equals(action)) {
command.cancel();
response.setStatus(Status.canceled);
// Remove the canceled session
executingCommands.remove(sessionId);
}
connection.sendPacket(response);
}
catch (XMPPException e) {
// If there is an exception caused by the next, complete,
// prev or cancel method, then that error is returned to the
// requester.
XMPPError error = e.getXMPPError();
// If the error type is cancel, then the execution is
// canceled therefore the status must show that, and the
// command be removed from the executing list.
if (XMPPError.Type.CANCEL.equals(error.getType())) {
response.setStatus(Status.canceled);
executingCommands.remove(sessionId);
}
respondError(response, error);
e.printStackTrace();