blob: 8e1f7d4ab259abe0485cafb47285d12085dcd8cc [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001/**
2 * $RCSfile$
3 * $Revision$
4 * $Date$
5 *
6 * Copyright 2003-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
21package org.jivesoftware.smack.packet;
22
23import org.jivesoftware.smack.util.StringUtils;
24
25/**
26 * The base IQ (Info/Query) packet. IQ packets are used to get and set information
27 * on the server, including authentication, roster operations, and creating
28 * accounts. Each IQ packet has a specific type that indicates what type of action
29 * is being taken: "get", "set", "result", or "error".<p>
30 *
31 * IQ packets can contain a single child element that exists in a specific XML
32 * namespace. The combination of the element name and namespace determines what
33 * type of IQ packet it is. Some example IQ subpacket snippets:<ul>
34 *
35 * <li>&lt;query xmlns="jabber:iq:auth"&gt; -- an authentication IQ.
36 * <li>&lt;query xmlns="jabber:iq:private"&gt; -- a private storage IQ.
37 * <li>&lt;pubsub xmlns="http://jabber.org/protocol/pubsub"&gt; -- a pubsub IQ.
38 * </ul>
39 *
40 * @author Matt Tucker
41 */
42public abstract class IQ extends Packet {
43
44 private Type type = Type.GET;
45
46 public IQ() {
47 super();
48 }
49
50 public IQ(IQ iq) {
51 super(iq);
52 type = iq.getType();
53 }
54 /**
55 * Returns the type of the IQ packet.
56 *
57 * @return the type of the IQ packet.
58 */
59 public Type getType() {
60 return type;
61 }
62
63 /**
64 * Sets the type of the IQ packet.
65 *
66 * @param type the type of the IQ packet.
67 */
68 public void setType(Type type) {
69 if (type == null) {
70 this.type = Type.GET;
71 }
72 else {
73 this.type = type;
74 }
75 }
76
77 public String toXML() {
78 StringBuilder buf = new StringBuilder();
79 buf.append("<iq ");
80 if (getPacketID() != null) {
81 buf.append("id=\"" + getPacketID() + "\" ");
82 }
83 if (getTo() != null) {
84 buf.append("to=\"").append(StringUtils.escapeForXML(getTo())).append("\" ");
85 }
86 if (getFrom() != null) {
87 buf.append("from=\"").append(StringUtils.escapeForXML(getFrom())).append("\" ");
88 }
89 if (type == null) {
90 buf.append("type=\"get\">");
91 }
92 else {
93 buf.append("type=\"").append(getType()).append("\">");
94 }
95 // Add the query section if there is one.
96 String queryXML = getChildElementXML();
97 if (queryXML != null) {
98 buf.append(queryXML);
99 }
100 // Add the error sub-packet, if there is one.
101 XMPPError error = getError();
102 if (error != null) {
103 buf.append(error.toXML());
104 }
105 buf.append("</iq>");
106 return buf.toString();
107 }
108
109 /**
110 * Returns the sub-element XML section of the IQ packet, or <tt>null</tt> if there
111 * isn't one. Packet extensions <b>must</b> be included, if any are defined.<p>
112 *
113 * Extensions of this class must override this method.
114 *
115 * @return the child element section of the IQ XML.
116 */
117 public abstract String getChildElementXML();
118
119 /**
120 * Convenience method to create a new empty {@link Type#RESULT IQ.Type.RESULT}
121 * IQ based on a {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET}
122 * IQ. The new packet will be initialized with:<ul>
123 * <li>The sender set to the recipient of the originating IQ.
124 * <li>The recipient set to the sender of the originating IQ.
125 * <li>The type set to {@link Type#RESULT IQ.Type.RESULT}.
126 * <li>The id set to the id of the originating IQ.
127 * <li>No child element of the IQ element.
128 * </ul>
129 *
130 * @param iq the {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET} IQ packet.
131 * @throws IllegalArgumentException if the IQ packet does not have a type of
132 * {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET}.
133 * @return a new {@link Type#RESULT IQ.Type.RESULT} IQ based on the originating IQ.
134 */
135 public static IQ createResultIQ(final IQ request) {
136 if (!(request.getType() == Type.GET || request.getType() == Type.SET)) {
137 throw new IllegalArgumentException(
138 "IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
139 }
140 final IQ result = new IQ() {
141 public String getChildElementXML() {
142 return null;
143 }
144 };
145 result.setType(Type.RESULT);
146 result.setPacketID(request.getPacketID());
147 result.setFrom(request.getTo());
148 result.setTo(request.getFrom());
149 return result;
150 }
151
152 /**
153 * Convenience method to create a new {@link Type#ERROR IQ.Type.ERROR} IQ
154 * based on a {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET}
155 * IQ. The new packet will be initialized with:<ul>
156 * <li>The sender set to the recipient of the originating IQ.
157 * <li>The recipient set to the sender of the originating IQ.
158 * <li>The type set to {@link Type#ERROR IQ.Type.ERROR}.
159 * <li>The id set to the id of the originating IQ.
160 * <li>The child element contained in the associated originating IQ.
161 * <li>The provided {@link XMPPError XMPPError}.
162 * </ul>
163 *
164 * @param iq the {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET} IQ packet.
165 * @param error the error to associate with the created IQ packet.
166 * @throws IllegalArgumentException if the IQ packet does not have a type of
167 * {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET}.
168 * @return a new {@link Type#ERROR IQ.Type.ERROR} IQ based on the originating IQ.
169 */
170 public static IQ createErrorResponse(final IQ request, final XMPPError error) {
171 if (!(request.getType() == Type.GET || request.getType() == Type.SET)) {
172 throw new IllegalArgumentException(
173 "IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
174 }
175 final IQ result = new IQ() {
176 public String getChildElementXML() {
177 return request.getChildElementXML();
178 }
179 };
180 result.setType(Type.ERROR);
181 result.setPacketID(request.getPacketID());
182 result.setFrom(request.getTo());
183 result.setTo(request.getFrom());
184 result.setError(error);
185 return result;
186 }
187
188 /**
189 * A class to represent the type of the IQ packet. The types are:
190 *
191 * <ul>
192 * <li>IQ.Type.GET
193 * <li>IQ.Type.SET
194 * <li>IQ.Type.RESULT
195 * <li>IQ.Type.ERROR
196 * </ul>
197 */
198 public static class Type {
199
200 public static final Type GET = new Type("get");
201 public static final Type SET = new Type("set");
202 public static final Type RESULT = new Type("result");
203 public static final Type ERROR = new Type("error");
204
205 /**
206 * Converts a String into the corresponding types. Valid String values
207 * that can be converted to types are: "get", "set", "result", and "error".
208 *
209 * @param type the String value to covert.
210 * @return the corresponding Type.
211 */
212 public static Type fromString(String type) {
213 if (type == null) {
214 return null;
215 }
216 type = type.toLowerCase();
217 if (GET.toString().equals(type)) {
218 return GET;
219 }
220 else if (SET.toString().equals(type)) {
221 return SET;
222 }
223 else if (ERROR.toString().equals(type)) {
224 return ERROR;
225 }
226 else if (RESULT.toString().equals(type)) {
227 return RESULT;
228 }
229 else {
230 return null;
231 }
232 }
233
234 private String value;
235
236 private Type(String value) {
237 this.value = value;
238 }
239
240 public String toString() {
241 return value;
242 }
243 }
244}