summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMili Verma <mili.verma@isode.com>2012-01-06 15:00:55 (GMT)
committerKevin Smith <git@kismith.co.uk>2012-01-09 15:54:52 (GMT)
commitcc760bfd15caadb56bfef477cb54dc94c25f7fa7 (patch)
tree05f5918b97488b05ca1266c0644a3874adb98129 /src/com/isode/stroke/adhoc
parent12b1d667965556002ea0fd300a71bcdf57634e90 (diff)
downloadstroke-cc760bfd15caadb56bfef477cb54dc94c25f7fa7.zip
stroke-cc760bfd15caadb56bfef477cb54dc94c25f7fa7.tar.bz2
Port Adhoc commands to Stroke
This patch ports the Adhoc commands from Swiften to Stroke. It also ports their unit tests. Test-information: Unit tests pass. MLC able to use the ad-hoc command fine.
Diffstat (limited to 'src/com/isode/stroke/adhoc')
-rw-r--r--src/com/isode/stroke/adhoc/OutgoingAdHocCommandSession.java250
1 files changed, 250 insertions, 0 deletions
diff --git a/src/com/isode/stroke/adhoc/OutgoingAdHocCommandSession.java b/src/com/isode/stroke/adhoc/OutgoingAdHocCommandSession.java
new file mode 100644
index 0000000..a9db0b6
--- /dev/null
+++ b/src/com/isode/stroke/adhoc/OutgoingAdHocCommandSession.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2012 Isode Limited, London, England.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 2010-2011 Kevin Smith
+ * All rights reserved.
+ */
+
+package com.isode.stroke.adhoc;
+
+import java.util.HashMap;
+import java.util.List;
+
+import com.isode.stroke.elements.Command;
+import com.isode.stroke.elements.ErrorPayload;
+import com.isode.stroke.elements.Form;
+import com.isode.stroke.elements.IQ;
+import com.isode.stroke.elements.Command.Action;
+import com.isode.stroke.elements.Command.Status;
+import com.isode.stroke.jid.JID;
+import com.isode.stroke.queries.GenericRequest;
+import com.isode.stroke.queries.IQRouter;
+import com.isode.stroke.signals.Signal1;
+import com.isode.stroke.signals.Slot2;
+
+/**
+ * This class maintains the session between the client and the server for an
+ * Ad-Hoc command.
+ */
+public class OutgoingAdHocCommandSession {
+ /**
+ * Availability of action.
+ */
+ public enum ActionState {
+ /**
+ * Action isn't applicable to this command
+ */
+ ABSENT,
+ /**
+ * Action is applicable to this command but not currently available
+ */
+ PRESENT,
+ /**
+ * Action is currently available (not used in
+ * {@link OutgoingAdHocCommandSession})
+ */
+ ENABLED,
+ /**
+ * Action is applicable and currently available
+ */
+ ENABLED_AND_PRESENT
+ };
+
+ /**
+ * Emitted when the form for the next stage is available. The client should
+ * add a listener to this signal which will be called when the server sends
+ * a form.
+ */
+ public final Signal1<Command> onNextStageReceived = new Signal1<Command>();
+
+ /**
+ * Emitted on error. The client should add a listener to this signal which
+ * will be called when the server sends an error.
+ */
+ public final Signal1<ErrorPayload> onError = new Signal1<ErrorPayload>();
+
+ private JID to_;
+ private String commandNode_;
+ private IQRouter iqRouter_;
+ private boolean isMultiStage_;
+ private String sessionID_;
+ private HashMap<Action, ActionState> actionStates_ = new HashMap<Action, ActionState>();
+
+ /**
+ * Create an Ad-Hoc command session. The initial command will be sent to the
+ * server on calling {@link #start()}.
+ *
+ * @param to JID of the user for which the Ad-Hoc command is executed, must
+ * not be null
+ * @param commandNode Node part of the Ad-Hoc command as published by the
+ * server (e.g. "http://isode.com/xmpp/commands#test"), must not
+ * be null
+ * @param iqRouter TODO: not sure how to explain this, must not be null
+ */
+ public OutgoingAdHocCommandSession(JID to, String commandNode,
+ IQRouter iqRouter) {
+ if (to == null) {
+ throw new NullPointerException("'to' must not be null");
+ }
+ if (commandNode == null) {
+ throw new NullPointerException("'commandNode' must not be null");
+ }
+ if (iqRouter == null) {
+ throw new NullPointerException("'iqRouter' must not be null");
+ }
+
+ to_ = to;
+ commandNode_ = commandNode;
+ iqRouter_ = iqRouter;
+ isMultiStage_ = false;
+ }
+
+ private void handleResponse(Command payload, ErrorPayload error) {
+ if (error != null) {
+ onError.emit(error);
+ } else {
+ List<Action> actions = payload.getAvailableActions();
+ actionStates_.clear();
+ if (payload.getStatus() == Status.EXECUTING) {
+ actionStates_.put(Action.CANCEL,
+ ActionState.ENABLED_AND_PRESENT);
+ actionStates_.put(Action.COMPLETE, ActionState.PRESENT);
+ if (actions.contains(Action.COMPLETE)) {
+ actionStates_.put(Action.COMPLETE,
+ ActionState.ENABLED_AND_PRESENT);
+ }
+
+ if (getIsMultiStage()) {
+ actionStates_.put(Action.NEXT, ActionState.PRESENT);
+ actionStates_.put(Action.PREV, ActionState.PRESENT);
+ }
+
+ if (actions.contains(Action.NEXT)) {
+ actionStates_.put(Action.NEXT,
+ ActionState.ENABLED_AND_PRESENT);
+ }
+
+ if (actions.contains(Action.PREV)) {
+ actionStates_.put(Action.PREV,
+ ActionState.ENABLED_AND_PRESENT);
+ }
+ }
+
+ sessionID_ = payload.getSessionID();
+ if (actions.contains(Action.NEXT) || actions.contains(Action.PREV)) {
+ isMultiStage_ = true;
+ }
+ onNextStageReceived.emit(payload);
+ }
+ }
+
+ /**
+ * @return true if the form is multi-stage. Will return a valid result only
+ * after the first response is received from the server so should be
+ * called only after the listener for {@link #onNextStageReceived}
+ * has been called at least once.
+ */
+ public boolean getIsMultiStage() {
+ return isMultiStage_;
+ }
+
+ /**
+ * Send initial request to the target.
+ */
+ public void start() {
+ Action action = null;
+ GenericRequest<Command> commandRequest = new GenericRequest<Command>(
+ IQ.Type.Set, to_, new Command(commandNode_, null, action),
+ iqRouter_);
+ commandRequest.onResponse.connect(new Slot2<Command, ErrorPayload>() {
+ public void call(Command payload, ErrorPayload error) {
+ handleResponse(payload, error);
+ }
+ });
+ commandRequest.send();
+ }
+
+ /**
+ * Cancel command session with the target.
+ */
+ public void cancel() {
+ if (sessionID_.length() != 0) {
+ submitForm(null, Action.CANCEL);
+ }
+ }
+
+ /**
+ * Return to the previous stage.
+ */
+ public void goBack() {
+ submitForm(null, Action.PREV);
+ }
+
+ /**
+ * Send the form to complete the command.
+ *
+ * @param form Form for submission - if null, the command will be submitted
+ * with no form.
+ */
+ public void complete(Form form) {
+ submitForm(form, Action.COMPLETE);
+ }
+
+ /**
+ * Send the form to advance to the next stage of the command.
+ *
+ * @param form Form for submission - if null, the command will be submitted
+ * with no form.
+ */
+ public void goNext(Form form) {
+ submitForm(form, Action.NEXT);
+ }
+
+ private void submitForm(Form form, Action action) {
+ Command command = new Command(commandNode_, sessionID_, action);
+ command.setForm(form);
+
+ GenericRequest<Command> commandRequest = new GenericRequest<Command>(
+ IQ.Type.Set, to_, command, iqRouter_);
+ commandRequest.onResponse.connect(new Slot2<Command, ErrorPayload>() {
+ public void call(Command payload, ErrorPayload error) {
+ handleResponse(payload, error);
+ }
+ });
+ commandRequest.send();
+ }
+
+ /**
+ * Get the state of a given action. This is useful for a UI to determine
+ * which buttons should be visible, and which enabled. If no actions are
+ * {@link ActionState#ENABLED_AND_PRESENT}, the command has completed.
+ *
+ * <p>
+ * Will return a valid result for the current stage only after the response
+ * is received from the server so should be called only after the listener
+ * for {@link #onNextStageReceived} has been called for that stage.
+ *
+ * @param action Action for which the state needs to be determined for the
+ * current form. Useful for Next, Prev, Cancel and Complete only,
+ * for other values and null, {@link ActionState#ABSENT} will be
+ * returned.
+ * @return state of the requested action, will never be null
+ */
+ public ActionState getActionState(Action action) {
+ ActionState actionState = actionStates_.get(action);
+ if (actionState == null) {
+ actionState = ActionState.ABSENT;
+ }
+
+ return actionState;
+ }
+
+ @Override
+ public String toString() {
+ return OutgoingAdHocCommandSession.class.getSimpleName() + "\nto: "
+ + to_ + "\ncommand node: " + commandNode_ + "\nsession ID: "
+ + sessionID_ + "\nis multi-stage: " + isMultiStage_;
+ }
+}