001/**
002 *
003 * Copyright 2005-2007 Jive Software.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * 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 */
017package org.jivesoftware.smackx.commands;
018
019import org.jivesoftware.smack.SmackException.NoResponseException;
020import org.jivesoftware.smack.SmackException.NotConnectedException;
021import org.jivesoftware.smack.XMPPConnection;
022import org.jivesoftware.smack.XMPPException.XMPPErrorException;
023import org.jivesoftware.smack.packet.IQ;
024import org.jivesoftware.smackx.commands.packet.AdHocCommandData;
025import org.jivesoftware.smackx.xdata.Form;
026
027/**
028 * Represents a command that is in a remote location. Invoking one of the
029 * {@link AdHocCommand.Action#execute execute}, {@link AdHocCommand.Action#next next},
030 * {@link AdHocCommand.Action#prev prev}, {@link AdHocCommand.Action#cancel cancel} or
031 * {@link AdHocCommand.Action#complete complete} actions results in executing that
032 * action in the remote location. In response to that action the internal state
033 * of the this command instance will change. For example, if the command is a
034 * single stage command, then invoking the execute action will execute this
035 * action in the remote location. After that the local instance will have a
036 * state of "completed" and a form or notes that applies.
037 *
038 * @author Gabriel Guardincerri
039 *
040 */
041public class RemoteCommand extends AdHocCommand {
042
043    /**
044     * The connection that is used to execute this command
045     */
046    private XMPPConnection connection;
047
048    /**
049     * The full JID of the command host
050     */
051    private String jid;
052
053    /**
054     * The session ID of this execution.
055     */
056    private String sessionID;
057
058    /**
059     * Creates a new RemoteCommand that uses an specific connection to execute a
060     * command identified by <code>node</code> in the host identified by
061     * <code>jid</code>
062     *
063     * @param connection the connection to use for the execution.
064     * @param node the identifier of the command.
065     * @param jid the JID of the host.
066     */
067    protected RemoteCommand(XMPPConnection connection, String node, String jid) {
068        super();
069        this.connection = connection;
070        this.jid = jid;
071        this.setNode(node);
072    }
073
074    @Override
075    public void cancel() throws NoResponseException, XMPPErrorException, NotConnectedException {
076        executeAction(Action.cancel);
077    }
078
079    @Override
080    public void complete(Form form) throws NoResponseException, XMPPErrorException, NotConnectedException {
081        executeAction(Action.complete, form);
082    }
083
084    @Override
085    public void execute() throws NoResponseException, XMPPErrorException, NotConnectedException {
086        executeAction(Action.execute);
087    }
088
089    /**
090     * Executes the default action of the command with the information provided
091     * in the Form. This form must be the anwser form of the previous stage. If
092     * there is a problem executing the command it throws an XMPPException.
093     *
094     * @param form the form anwser of the previous stage.
095     * @throws XMPPErrorException if an error occurs.
096     * @throws NoResponseException if there was no response from the server.
097     * @throws NotConnectedException 
098     */
099    public void execute(Form form) throws NoResponseException, XMPPErrorException, NotConnectedException {
100        executeAction(Action.execute, form);
101    }
102
103    @Override
104    public void next(Form form) throws NoResponseException, XMPPErrorException, NotConnectedException {
105        executeAction(Action.next, form);
106    }
107
108    @Override
109    public void prev() throws NoResponseException, XMPPErrorException, NotConnectedException {
110        executeAction(Action.prev);
111    }
112
113    private void executeAction(Action action) throws NoResponseException, XMPPErrorException, NotConnectedException {
114        executeAction(action, null);
115    }
116
117    /**
118     * Executes the <code>action</codo> with the <code>form</code>.
119     * The action could be any of the available actions. The form must
120     * be the anwser of the previous stage. It can be <tt>null</tt> if it is the first stage.
121     *
122     * @param action the action to execute.
123     * @param form the form with the information.
124     * @throws XMPPErrorException if there is a problem executing the command.
125     * @throws NoResponseException if there was no response from the server.
126     * @throws NotConnectedException 
127     */
128    private void executeAction(Action action, Form form) throws NoResponseException, XMPPErrorException, NotConnectedException {
129        // TODO: Check that all the required fields of the form were filled, if
130        // TODO: not throw the corresponding exeption. This will make a faster response,
131        // TODO: since the request is stoped before it's sent.
132        AdHocCommandData data = new AdHocCommandData();
133        data.setType(IQ.Type.SET);
134        data.setTo(getOwnerJID());
135        data.setNode(getNode());
136        data.setSessionID(sessionID);
137        data.setAction(action);
138
139        if (form != null) {
140            data.setForm(form.getDataFormToSend());
141        }
142
143        AdHocCommandData responseData = (AdHocCommandData) connection.createPacketCollectorAndSend(
144                        data).nextResultOrThrow();
145
146        this.sessionID = responseData.getSessionID();
147        super.setData(responseData);
148    }
149
150    @Override
151    public String getOwnerJID() {
152        return jid;
153    }
154}