/** * * Copyright 2005-2007 Jive Software. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.smackx.commands; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smackx.commands.packet.AdHocCommandData; import org.jivesoftware.smackx.xdata.form.FillableForm; import org.jivesoftware.smackx.xdata.form.SubmitForm; import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jxmpp.jid.Jid; /** * Represents a ad-hoc command invoked on a remote entity. Invoking one of the * {@link #execute()}, {@link #next(SubmitForm)}, * {@link #prev()}, {@link #cancel()} or * {@link #complete(SubmitForm)} actions results in executing that * action on the remote entity. In response to that action the internal state * of the this command instance will change. For example, if the command is a * single stage command, then invoking the execute action will execute this * action in the remote location. After that the local instance will have a * state of "completed" and a form or notes that applies. * * @author Gabriel Guardincerri * @author Florian Schmaus * */ public class AdHocCommand extends AbstractAdHocCommand { /** * The connection that is used to execute this command */ private final XMPPConnection connection; /** * The full JID of the command host */ private final Jid jid; /** * Creates a new RemoteCommand that uses an specific connection to execute a * command identified by node in the host identified by * jid * * @param connection the connection to use for the execution. * @param node the identifier of the command. * @param jid the JID of the host. */ protected AdHocCommand(XMPPConnection connection, String node, Jid jid) { super(node); this.connection = Objects.requireNonNull(connection); this.jid = Objects.requireNonNull(jid); } public Jid getOwnerJID() { return jid; } @Override public final void cancel() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { executeAction(AdHocCommandData.Action.cancel); } /** * Executes the command. This is invoked only on the first stage of the * command. It is invoked on every command. If there is a problem executing * the command it throws an XMPPException. * * @return an ad-hoc command result. * @throws NoResponseException if there was no response from the remote entity. * @throws XMPPErrorException if there is an error executing the command. * @throws NotConnectedException if the XMPP connection is not connected. * @throws InterruptedException if the calling thread was interrupted. */ public final AdHocCommandResult execute() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { return executeAction(AdHocCommandData.Action.execute); } /** * Executes the next action of the command with the information provided in * the response. This form must be the answer form of the * previous stage. This method will be only invoked for commands that have one * or more stages. If there is a problem executing the command it throws an * XMPPException. * * @param filledForm the form answer of the previous stage. * @return an ad-hoc command result. * @throws NoResponseException if there was no response from the remote entity. * @throws XMPPErrorException if there is a problem executing the command. * @throws NotConnectedException if the XMPP connection is not connected. * @throws InterruptedException if the calling thread was interrupted. */ public final AdHocCommandResult next(SubmitForm filledForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { return executeAction(AdHocCommandData.Action.next, filledForm.getDataForm()); } /** * Completes the command execution with the information provided in the * response. This form must be the answer form of the * previous stage. This method will be only invoked for commands that have one * or more stages. If there is a problem executing the command it throws an * XMPPException. * * @param filledForm the form answer of the previous stage. * @return an ad-hoc command result. * @throws NoResponseException if there was no response from the remote entity. * @throws XMPPErrorException if there is a problem executing the command. * @throws NotConnectedException if the XMPP connection is not connected. * @throws InterruptedException if the calling thread was interrupted. */ public AdHocCommandResult complete(SubmitForm filledForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { return executeAction(AdHocCommandData.Action.complete, filledForm.getDataForm()); } /** * Goes to the previous stage. The requester is asking to re-send the * information of the previous stage. The command must change it state to * the previous one. If there is a problem executing the command it throws * an XMPPException. * * @return an ad-hoc command result. * @throws NoResponseException if there was no response from the remote entity. * @throws XMPPErrorException if there is a problem executing the command. * @throws NotConnectedException if the XMPP connection is not connected. * @throws InterruptedException if the calling thread was interrupted. */ public final AdHocCommandResult prev() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { return executeAction(AdHocCommandData.Action.prev); } /** * Executes the default action of the command with the information provided * in the Form. This form must be the answer form of the previous stage. If * there is a problem executing the command it throws an XMPPException. * * @param form the form answer of the previous stage. * @return an ad-hoc command result. * @throws XMPPErrorException if an error occurs. * @throws NoResponseException if there was no response from the server. * @throws NotConnectedException if the XMPP connection is not connected. * @throws InterruptedException if the calling thread was interrupted. */ public final AdHocCommandResult execute(FillableForm form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { return executeAction(AdHocCommandData.Action.execute, form.getDataFormToSubmit()); } private AdHocCommandResult executeAction(AdHocCommandData.Action action) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { return executeAction(action, null); } /** * Executes the action with the form. * The action could be any of the available actions. The form must * be the answer of the previous stage. It can be null if it is the first stage. * * @param action the action to execute. * @param form the form with the information. * @throws XMPPErrorException if there is a problem executing the command. * @throws NoResponseException if there was no response from the server. * @throws NotConnectedException if the XMPP connection is not connected. * @throws InterruptedException if the calling thread was interrupted. */ private synchronized AdHocCommandResult executeAction(AdHocCommandData.Action action, DataForm form) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { AdHocCommandData request = AdHocCommandData.builder(getNode(), connection) .ofType(IQ.Type.set) .to(getOwnerJID()) .setSessionId(getSessionId()) .setAction(action) .setForm(form) .build(); addRequest(request); AdHocCommandData response = connection.sendIqRequestAndWaitForResponse(request); // The Ad-Hoc service ("server") may have generated a session id for us. String sessionId = response.getSessionId(); if (sessionId != null) { setSessionId(sessionId); } AdHocCommandResult result = AdHocCommandResult.from(response); addResult(result); return result; } }