• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
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 
21 package org.jivesoftware.smack.packet;
22 
23 import 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  */
42 public abstract class IQ extends Packet {
43 
44     private Type type = Type.GET;
45 
IQ()46     public IQ() {
47         super();
48     }
49 
IQ(IQ iq)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      */
getType()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      */
setType(Type type)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 
toXML()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      */
getChildElementXML()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      */
createResultIQ(final IQ request)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      */
createErrorResponse(final IQ request, final XMPPError error)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          */
fromString(String type)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 
Type(String value)236         private Type(String value) {
237             this.value = value;
238         }
239 
toString()240         public String toString() {
241             return value;
242         }
243     }
244 }
245