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