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.XMPPException.XMPPErrorException; 022import org.jivesoftware.smack.packet.StanzaError; 023 024import org.jivesoftware.smackx.commands.packet.AdHocCommandData; 025import org.jivesoftware.smackx.commands.packet.AdHocCommandDataBuilder; 026import org.jivesoftware.smackx.xdata.form.SubmitForm; 027 028import org.jxmpp.jid.Jid; 029 030/** 031 * Represents a command that can be executed locally from a remote location. This 032 * class must be extended to implement an specific ad-hoc command. This class 033 * provides some useful tools:<ul> 034 * <li>Node</li> 035 * <li>Name</li> 036 * <li>Session ID</li> 037 * <li>Current Stage</li> 038 * <li>Available actions</li> 039 * <li>Default action</li> 040 * </ul> 041 * To implement a new command extend this class and implement all the abstract 042 * methods. When implementing the actions remember that they could be invoked 043 * several times, and that you must use the current stage number to know what to 044 * do. 045 * 046 * @author Gabriel Guardincerri 047 * @author Florian Schmaus 048 */ 049public abstract class AdHocCommandHandler extends AbstractAdHocCommand { 050 051 /** 052 * The time stamp of first invocation of the command. Used to implement the session timeout. 053 */ 054 private final long creationDate; 055 056 /** 057 * The number of the current stage. 058 */ 059 private int currentStage; 060 061 @SuppressWarnings("this-escape") 062 public AdHocCommandHandler(String node, String name, String sessionId) { 063 super(node, name); 064 setSessionId(sessionId); 065 this.creationDate = System.currentTimeMillis(); 066 } 067 068 protected abstract AdHocCommandData execute(AdHocCommandDataBuilder response) throws NoResponseException, 069 XMPPErrorException, NotConnectedException, InterruptedException, IllegalStateException; 070 071 protected abstract AdHocCommandData next(AdHocCommandDataBuilder response, SubmitForm submittedForm) 072 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, 073 IllegalStateException; 074 075 protected abstract AdHocCommandData complete(AdHocCommandDataBuilder response, SubmitForm submittedForm) 076 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, 077 IllegalStateException; 078 079 protected abstract AdHocCommandData prev(AdHocCommandDataBuilder response) throws NoResponseException, 080 XMPPErrorException, NotConnectedException, InterruptedException, IllegalStateException; 081 082 /** 083 * Returns the date the command was created. 084 * 085 * @return the date the command was created. 086 */ 087 public long getCreationDate() { 088 return creationDate; 089 } 090 091 /** 092 * Returns true if the specified requester has permission to execute all the 093 * stages of this action. This is checked when the first request is received, 094 * if the permission is grant then the requester will be able to execute 095 * all the stages of the command. It is not checked again during the 096 * execution. 097 * 098 * @param jid the JID to check permissions on. 099 * @return true if the user has permission to execute this action. 100 */ 101 public boolean hasPermission(Jid jid) { 102 return true; 103 }; 104 105 /** 106 * Returns the currently executing stage number. The first stage number is 107 * 1. During the execution of the first action this method will answer 1. 108 * 109 * @return the current stage number. 110 */ 111 public final int getCurrentStage() { 112 return currentStage; 113 } 114 115 /** 116 * Increase the current stage number. 117 */ 118 final void incrementStage() { 119 currentStage++; 120 } 121 122 /** 123 * Decrease the current stage number. 124 */ 125 final void decrementStage() { 126 currentStage--; 127 } 128 129 protected static XMPPErrorException newXmppErrorException(StanzaError.Condition condition) { 130 return newXmppErrorException(condition, null); 131 } 132 133 protected static XMPPErrorException newXmppErrorException(StanzaError.Condition condition, String descriptiveText) { 134 StanzaError stanzaError = StanzaError.from(condition, descriptiveText).build(); 135 return new XMPPErrorException(null, stanzaError); 136 } 137 138 protected static XMPPErrorException newBadRequestException(String descriptiveTest) { 139 return newXmppErrorException(StanzaError.Condition.bad_request, descriptiveTest); 140 } 141 142 public abstract static class SingleStage extends AdHocCommandHandler { 143 144 public SingleStage(String node, String name, String sessionId) { 145 super(node, name, sessionId); 146 } 147 148 protected abstract AdHocCommandData executeSingleStage(AdHocCommandDataBuilder response) 149 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException; 150 151 @Override 152 protected final AdHocCommandData execute(AdHocCommandDataBuilder response) 153 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 154 response.setStatusCompleted(); 155 return executeSingleStage(response); 156 } 157 158 @Override 159 public final AdHocCommandData next(AdHocCommandDataBuilder response, SubmitForm submittedForm) 160 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 161 throw newXmppErrorException(StanzaError.Condition.bad_request); 162 } 163 164 @Override 165 public final AdHocCommandData complete(AdHocCommandDataBuilder response, SubmitForm submittedForm) 166 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 167 throw newXmppErrorException(StanzaError.Condition.bad_request); 168 } 169 170 @Override 171 public final AdHocCommandData prev(AdHocCommandDataBuilder response) 172 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 173 throw newXmppErrorException(StanzaError.Condition.bad_request); 174 } 175 176 @Override 177 public final void cancel() 178 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 179 throw newXmppErrorException(StanzaError.Condition.bad_request); 180 } 181 182 } 183}