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 */ RemoteCommand(Connection connection, String node, String jid)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 cancel()89 public void cancel() throws XMPPException { 90 executeAction(Action.cancel, packetReplyTimeout); 91 } 92 93 @Override complete(Form form)94 public void complete(Form form) throws XMPPException { 95 executeAction(Action.complete, form, packetReplyTimeout); 96 } 97 98 @Override execute()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 */ execute(Form form)111 public void execute(Form form) throws XMPPException { 112 executeAction(Action.execute, form, packetReplyTimeout); 113 } 114 115 @Override next(Form form)116 public void next(Form form) throws XMPPException { 117 executeAction(Action.next, form, packetReplyTimeout); 118 } 119 120 @Override prev()121 public void prev() throws XMPPException { 122 executeAction(Action.prev, packetReplyTimeout); 123 } 124 executeAction(Action action, long packetReplyTimeout)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 */ executeAction(Action action, Form form, long timeout)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 getOwnerJID()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 */ getPacketReplyTimeout()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 */ setPacketReplyTimeout(long packetReplyTimeout)198 public void setPacketReplyTimeout(long packetReplyTimeout) { 199 this.packetReplyTimeout = packetReplyTimeout; 200 } 201 }