Home | History | Annotate | Download | only in commands
      1 /**
      2  * $RCSfile$
      3  * $Revision$
      4  * $Date$
      5  *
      6  * Copyright 2005-2007 Jive Software.
      7  *
      8  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *     http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  */
     20 
     21 package org.jivesoftware.smackx.commands;
     22 
     23 import org.jivesoftware.smack.PacketCollector;
     24 import org.jivesoftware.smack.SmackConfiguration;
     25 import org.jivesoftware.smack.Connection;
     26 import org.jivesoftware.smack.XMPPException;
     27 import org.jivesoftware.smack.filter.PacketIDFilter;
     28 import org.jivesoftware.smack.packet.IQ;
     29 import org.jivesoftware.smack.packet.Packet;
     30 import org.jivesoftware.smackx.Form;
     31 import org.jivesoftware.smackx.packet.AdHocCommandData;
     32 
     33 /**
     34  * Represents a command that is in a remote location. Invoking one of the
     35  * {@link AdHocCommand.Action#execute execute}, {@link AdHocCommand.Action#next next},
     36  * {@link AdHocCommand.Action#prev prev}, {@link AdHocCommand.Action#cancel cancel} or
     37  * {@link AdHocCommand.Action#complete complete} actions results in executing that
     38  * action in the remote location. In response to that action the internal state
     39  * of the this command instance will change. For example, if the command is a
     40  * single stage command, then invoking the execute action will execute this
     41  * action in the remote location. After that the local instance will have a
     42  * state of "completed" and a form or notes that applies.
     43  *
     44  * @author Gabriel Guardincerri
     45  *
     46  */
     47 public class RemoteCommand extends AdHocCommand {
     48 
     49     /**
     50      * The connection that is used to execute this command
     51      */
     52     private Connection connection;
     53 
     54     /**
     55      * The full JID of the command host
     56      */
     57     private String jid;
     58 
     59     /**
     60      * The session ID of this execution.
     61      */
     62     private String sessionID;
     63 
     64 
     65     /**
     66      * The number of milliseconds to wait for a response from the server
     67      * The default value is the default packet reply timeout (5000 ms).
     68      */
     69     private long packetReplyTimeout;
     70 
     71     /**
     72      * Creates a new RemoteCommand that uses an specific connection to execute a
     73      * command identified by <code>node</code> in the host identified by
     74      * <code>jid</code>
     75      *
     76      * @param connection the connection to use for the execution.
     77      * @param node the identifier of the command.
     78      * @param jid the JID of the host.
     79      */
     80     protected RemoteCommand(Connection connection, String node, String jid) {
     81         super();
     82         this.connection = connection;
     83         this.jid = jid;
     84         this.setNode(node);
     85         this.packetReplyTimeout = SmackConfiguration.getPacketReplyTimeout();
     86     }
     87 
     88     @Override
     89     public void cancel() throws XMPPException {
     90         executeAction(Action.cancel, packetReplyTimeout);
     91     }
     92 
     93     @Override
     94     public void complete(Form form) throws XMPPException {
     95         executeAction(Action.complete, form, packetReplyTimeout);
     96     }
     97 
     98     @Override
     99     public void execute() throws XMPPException {
    100         executeAction(Action.execute, packetReplyTimeout);
    101     }
    102 
    103     /**
    104      * Executes the default action of the command with the information provided
    105      * in the Form. This form must be the anwser form of the previous stage. If
    106      * there is a problem executing the command it throws an XMPPException.
    107      *
    108      * @param form the form anwser of the previous stage.
    109      * @throws XMPPException if an error occurs.
    110      */
    111     public void execute(Form form) throws XMPPException {
    112         executeAction(Action.execute, form, packetReplyTimeout);
    113     }
    114 
    115     @Override
    116     public void next(Form form) throws XMPPException {
    117         executeAction(Action.next, form, packetReplyTimeout);
    118     }
    119 
    120     @Override
    121     public void prev() throws XMPPException {
    122         executeAction(Action.prev, packetReplyTimeout);
    123     }
    124 
    125     private void executeAction(Action action, long packetReplyTimeout) throws XMPPException {
    126         executeAction(action, null, packetReplyTimeout);
    127     }
    128 
    129     /**
    130      * Executes the <code>action</codo> with the <code>form</code>.
    131      * The action could be any of the available actions. The form must
    132      * be the anwser of the previous stage. It can be <tt>null</tt> if it is the first stage.
    133      *
    134      * @param action the action to execute.
    135      * @param form the form with the information.
    136      * @param timeout the amount of time to wait for a reply.
    137      * @throws XMPPException if there is a problem executing the command.
    138      */
    139     private void executeAction(Action action, Form form, long timeout) throws XMPPException {
    140         // TODO: Check that all the required fields of the form were filled, if
    141         // TODO: not throw the corresponding exeption. This will make a faster response,
    142         // TODO: since the request is stoped before it's sent.
    143         AdHocCommandData data = new AdHocCommandData();
    144         data.setType(IQ.Type.SET);
    145         data.setTo(getOwnerJID());
    146         data.setNode(getNode());
    147         data.setSessionID(sessionID);
    148         data.setAction(action);
    149 
    150         if (form != null) {
    151             data.setForm(form.getDataFormToSend());
    152         }
    153 
    154         PacketCollector collector = connection.createPacketCollector(
    155                 new PacketIDFilter(data.getPacketID()));
    156 
    157         connection.sendPacket(data);
    158 
    159         Packet response = collector.nextResult(timeout);
    160 
    161         // Cancel the collector.
    162         collector.cancel();
    163         if (response == null) {
    164             throw new XMPPException("No response from server on status set.");
    165         }
    166         if (response.getError() != null) {
    167             throw new XMPPException(response.getError());
    168         }
    169 
    170         AdHocCommandData responseData = (AdHocCommandData) response;
    171         this.sessionID = responseData.getSessionID();
    172         super.setData(responseData);
    173     }
    174 
    175     @Override
    176     public String getOwnerJID() {
    177         return jid;
    178     }
    179 
    180     /**
    181      * Returns the number of milliseconds to wait for a respone. The
    182      * {@link SmackConfiguration#getPacketReplyTimeout default} value
    183      * should be adjusted for commands that can take a long time to execute.
    184      *
    185      * @return the number of milliseconds to wait for responses.
    186      */
    187     public long getPacketReplyTimeout() {
    188         return packetReplyTimeout;
    189     }
    190 
    191     /**
    192      * Returns the number of milliseconds to wait for a respone. The
    193      * {@link SmackConfiguration#getPacketReplyTimeout default} value
    194      * should be adjusted for commands that can take a long time to execute.
    195      *
    196      * @param packetReplyTimeout the number of milliseconds to wait for responses.
    197      */
    198     public void setPacketReplyTimeout(long packetReplyTimeout) {
    199         this.packetReplyTimeout = packetReplyTimeout;
    200     }
    201 }