001/**
002 *
003 * Copyright 2005-2008 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 */
017
018package org.jivesoftware.smackx.commands.packet;
019
020import java.util.ArrayList;
021import java.util.EnumSet;
022import java.util.List;
023import java.util.Set;
024
025import org.jivesoftware.smack.XMPPConnection;
026import org.jivesoftware.smack.packet.IQ;
027import org.jivesoftware.smack.packet.IqData;
028import org.jivesoftware.smack.packet.XmlElement;
029
030import org.jivesoftware.smackx.commands.AdHocCommandNote;
031import org.jivesoftware.smackx.commands.SpecificErrorCondition;
032import org.jivesoftware.smackx.xdata.packet.DataForm;
033
034/**
035 * Represents the state and the request of the execution of an adhoc command.
036 *
037 * @author Gabriel Guardincerri
038 * @author Florian Schmaus
039 */
040public class AdHocCommandData extends IQ implements AdHocCommandDataView {
041
042    public static final String ELEMENT = "command";
043    public static final String NAMESPACE = "http://jabber.org/protocol/commands";
044
045    private final String node;
046
047    private final String name;
048
049    private final String sessionId;
050
051    private final List<AdHocCommandNote> notes = new ArrayList<>();
052
053    private final DataForm form;
054
055    private final Action action;
056
057    private final Status status;
058
059    private final Set<AllowedAction> actions = EnumSet.noneOf(AllowedAction.class);
060
061    private final AllowedAction executeAction;
062
063    public AdHocCommandData(AdHocCommandDataBuilder builder) {
064        super(builder, ELEMENT, NAMESPACE);
065        node = builder.getNode();
066        name = builder.getName();
067        sessionId = builder.getSessionId();
068        notes.addAll(builder.getNotes());
069        form = builder.getForm();
070        action = builder.getAction();
071        status = builder.getStatus();
072        actions.addAll(builder.getActions());
073        executeAction = builder.getExecuteAction();
074
075        if (executeAction != null && !actions.contains(executeAction)) {
076            throw new IllegalArgumentException("Execute action " + executeAction + " is not part of allowed actions: " + actions);
077        }
078    }
079
080    @Override
081    public String getNode() {
082        return node;
083    }
084
085   @Override
086    public String getName() {
087        return name;
088    }
089
090    @Override
091    public String getSessionId() {
092        return sessionId;
093    }
094
095    @Override
096    public List<AdHocCommandNote> getNotes() {
097        return notes;
098    }
099
100    @Override
101    public DataForm getForm() {
102        return form;
103    }
104
105    @Override
106    public Action getAction() {
107        return action;
108    }
109
110    @Override
111    public Status getStatus() {
112        return status;
113    }
114
115    @Override
116    public Set<AllowedAction> getActions() {
117        return actions;
118    }
119
120    @Override
121    public AllowedAction getExecuteAction() {
122        return executeAction;
123    }
124
125    @Override
126    protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
127        xml.attribute("node", node);
128        xml.optAttribute("sessionid", sessionId);
129        xml.optAttribute("status", status);
130        xml.optAttribute("action", action);
131        xml.rightAngleBracket();
132
133        if (getType() == Type.result) {
134            xml.halfOpenElement("actions");
135            xml.optAttribute("execute", executeAction);
136            if (actions.size() == 0) {
137                xml.closeEmptyElement();
138            } else {
139                xml.rightAngleBracket();
140
141                for (AdHocCommandData.AllowedAction action : actions) {
142                    xml.emptyElement(action);
143                }
144                xml.closeElement("actions");
145            }
146        }
147
148        xml.optAppend(form);
149
150        for (AdHocCommandNote note : notes) {
151            xml.halfOpenElement("note")
152              .attribute("type", note.getType().toString())
153              .rightAngleBracket();
154            xml.append(note.getValue());
155            xml.closeElement("note");
156        }
157
158        // TODO ERRORS
159//        if (getError() != null) {
160//            buf.append(getError().toXML());
161//        }
162
163        return xml;
164    }
165
166    public static AdHocCommandDataBuilder builder(String node, IqData iqCommon) {
167        return new AdHocCommandDataBuilder(node, iqCommon);
168    }
169
170    public static AdHocCommandDataBuilder builder(String node, String stanzaId) {
171        return new AdHocCommandDataBuilder(node, stanzaId);
172    }
173
174    public static AdHocCommandDataBuilder builder(String node, XMPPConnection connection) {
175        return new AdHocCommandDataBuilder(node, connection);
176    }
177
178    public static class SpecificError implements XmlElement {
179
180        public static final String namespace = "http://jabber.org/protocol/commands";
181
182        public SpecificErrorCondition condition;
183
184        public SpecificError(SpecificErrorCondition condition) {
185            this.condition = condition;
186        }
187
188        @Override
189        public String getElementName() {
190            return condition.toString();
191        }
192        @Override
193        public String getNamespace() {
194            return namespace;
195        }
196
197        public SpecificErrorCondition getCondition() {
198            return condition;
199        }
200
201        @Override
202        public String toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
203            StringBuilder buf = new StringBuilder();
204            buf.append('<').append(getElementName());
205            buf.append(" xmlns=\"").append(getNamespace()).append("\"/>");
206            return buf.toString();
207        }
208    }
209
210    /**
211     * The status of the stage in the adhoc command.
212     */
213    public enum Status {
214
215        /**
216         * The command is being executed.
217         */
218        executing,
219
220        /**
221         * The command has completed. The command session has ended.
222         */
223        completed,
224
225        /**
226         * The command has been canceled. The command session has ended.
227         */
228        canceled
229    }
230
231    public enum AllowedAction {
232
233        /**
234         * The command should be digress to the previous stage of execution.
235         */
236        prev(Action.prev),
237
238        /**
239         * The command should progress to the next stage of execution.
240         */
241        next(Action.next),
242
243        /**
244         * The command should be completed (if possible).
245         */
246        complete(Action.complete),
247        ;
248
249        public final Action action;
250
251        AllowedAction(Action action) {
252            this.action = action;
253        }
254    }
255
256    public enum Action {
257        /**
258         * The command should be executed or continue to be executed. This is
259         * the default value.
260         */
261        execute(null),
262
263        /**
264         * The command should be canceled.
265         */
266        cancel(null),
267
268        /**
269         * The command should be digress to the previous stage of execution.
270         */
271        prev(AllowedAction.prev),
272
273        /**
274         * The command should progress to the next stage of execution.
275         */
276        next(AllowedAction.next),
277
278        /**
279         * The command should be completed (if possible).
280         */
281        complete(AllowedAction.complete),
282        ;
283
284        public final AllowedAction allowedAction;
285
286        Action(AllowedAction allowedAction) {
287            this.allowedAction = allowedAction;
288        }
289
290    }
291}