KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xmpp > packet > IQ


1 package org.xmpp.packet;
2
3 import org.dom4j.Element;
4 import org.dom4j.QName;
5
6 import java.lang.reflect.Constructor JavaDoc;
7 import java.util.Iterator JavaDoc;
8 import java.util.List JavaDoc;
9 import java.util.Random JavaDoc;
10
11 /**
12  * IQ (Info/Query) packet. IQ packets are used to get and set information
13  * on the server, including authentication, roster operations, and creating
14  * accounts. Each IQ packet has a specific type that indicates what type of action
15  * is being taken: "get", "set", "result", or "error".<p>
16  *
17  * IQ packets can contain a single child element that exists in a extended XML
18  * namespace.
19  */

20 public class IQ extends Packet {
21
22     // Sequence and random number generator used for creating unique ID's.
23
private static int sequence = 0;
24     private static Random JavaDoc random = new Random JavaDoc();
25
26     /**
27      * Constructs a new IQ with an automatically generated ID and a type
28      * of {@link Type#get IQ.Type.get}.
29      */

30     public IQ() {
31         this.element = docFactory.createDocument().addElement("iq");
32         String JavaDoc id = String.valueOf(random.nextInt(1000) + "-" + sequence++);
33         setType(Type.get);
34         setID(id);
35     }
36
37     /**
38      * Constructs a new IQ using the specified type. A packet ID will
39      * be automatically generated.
40      *
41      * @param type the IQ type.
42      */

43     public IQ(Type type) {
44         this.element = docFactory.createDocument().addElement("iq");
45         setType(type);
46         String JavaDoc id = String.valueOf(random.nextInt(1000) + "-" + sequence++);
47         setID(id);
48     }
49
50     /**
51      * Constructs a new IQ using the specified type and ID.
52      *
53      * @param ID the packet ID of the IQ.
54      * @param type the IQ type.
55      */

56     public IQ(Type type, String JavaDoc ID) {
57         this.element = docFactory.createDocument().addElement("iq");
58         setType(type);
59         setID(ID);
60     }
61
62     /**
63      * Constructs a new IQ using an existing Element. This is useful
64      * for parsing incoming IQ Elements into IQ objects.
65      *
66      * @param element the IQ Element.
67      */

68     public IQ(Element element) {
69         super(element);
70     }
71
72     /**
73      * Constructs a new IQ that is a copy of an existing IQ.
74      *
75      * @param iq the iq packet.
76      * @see #createCopy()
77      */

78     private IQ(IQ iq) {
79         Element elementCopy = iq.element.createCopy();
80         docFactory.createDocument().add(elementCopy);
81         this.element = elementCopy;
82     }
83
84     /**
85      * Returns the type of this IQ.
86      *
87      * @return the IQ type.
88      * @see Type
89      */

90     public Type getType() {
91         String JavaDoc type = element.attributeValue("type");
92         if (type != null) {
93             return Type.valueOf(type);
94         }
95         else {
96             return null;
97         }
98     }
99
100     /**
101      * Sets the type of this IQ.
102      *
103      * @param type the IQ type.
104      * @see Type
105      */

106     public void setType(Type type) {
107         element.addAttribute("type", type==null?null:type.toString());
108     }
109
110     /**
111      * Returns the child element of this IQ. IQ packets may have a single child
112      * element in an extended namespace. This is a convenience method to
113      * avoid manipulating the underlying packet's Element instance directly.<p>
114      *
115      * An IQ child element in extended namespaces is used to extend the features
116      * of XMPP. Although any valid XML can be included in a child element
117      * in an extended namespace, many common features have been standardized
118      * as <a HREF="http://www.jabber.org/jeps">Jabber Enhancement Proposals</a>
119      * (JEPs).
120      *
121      * @return the child element.
122      */

123     public Element getChildElement() {
124         List JavaDoc elements = element.elements();
125         if (elements.isEmpty()) {
126             return null;
127         }
128         else {
129             // Search for a child element that is in a different namespace.
130
for (int i=0; i<elements.size(); i++) {
131                 Element element = (Element)elements.get(i);
132                 String JavaDoc namespace = element.getNamespaceURI();
133                 if (!namespace.equals("") && !namespace.equals("jabber:client") &&
134                         !namespace.equals("jabber:server"))
135                 {
136                     return element;
137                 }
138             }
139             return null;
140         }
141     }
142
143     /**
144      * Sets the child element of this IQ. IQ packets may have a single child
145      * element in an extended namespace. This is a convenience method to
146      * avoid manipulating this underlying packet's Element instance directly.<p>
147      *
148      * A sample use of this method might look like the following:
149      * <pre>
150      * IQ iq = new IQ("time_1");
151      * iq.setTo("mary@example.com");
152      * iq.setType(IQ.Type.GET);
153      * iq.setChildElement(docFactory.createElement("query", "jabber:iq:time"));</pre><p>
154      *
155      * An IQ child element in extended namespaces is used to extend the features
156      * of XMPP. Although any valid XML can be included in a child element
157      * in an extended namespace, many common features have been standardized
158      * as <a HREF="http://www.jabber.org/jeps">Jabber Enhancement Proposals</a>
159      * (JEPs).
160      *
161      * @param childElement the child element.
162      */

163     public void setChildElement(Element childElement) {
164         for (Iterator JavaDoc i=element.elementIterator(); i.hasNext(); ) {
165             element.remove((Element)i.next());
166         }
167         element.add(childElement);
168     }
169
170     /**
171      * Sets the child element of this IQ by constructing a new Element with the
172      * given name and namespace. The newly created child element is returned.
173      * IQ packets may have a single child element in an extended namespace.
174      * This method is a convenience method to avoid manipulating the underlying
175      * packet's Element instance directly.<p>
176      *
177      * In some cases, additional custom sub-elements must be added to an IQ child
178      * element (called packet extensions). For example, when adding a data form to
179      * an IQ response. See {@link #addExtension(PacketExtension)}.<p>
180      *
181      * A sample use of this method might look like the following:
182      * <pre>
183      * IQ iq = new IQ("time_1");
184      * iq.setTo("mary@example.com");
185      * iq.setType(IQ.Type.GET);
186      * iq.setChildElement("query", "jabber:iq:time");</pre>
187      *
188      * @param name the child element name.
189      * @param namespace the child element namespace.
190      * @return the newly created child element.
191      */

192     public Element setChildElement(String JavaDoc name, String JavaDoc namespace) {
193         for (Iterator JavaDoc i=element.elementIterator(); i.hasNext(); ) {
194             element.remove((Element)i.next());
195         }
196         return element.addElement(name, namespace);
197     }
198
199     /**
200      * Adds the element contained in the PacketExtension to the child element of the IQ
201      * packet. IQ packets, unlike the other packet types, have a unique child element that
202      * holds the packet extensions. If an extension is added to an IQ packet that does
203      * not have a child element then an IllegalStateException will be thrown.<p>
204      *
205      * It is important that this is the first and last time the element contained in
206      * PacketExtension is added to another Packet. Otherwise, a runtime error will be
207      * thrown when trying to add the PacketExtension's element to the Packet's element.
208      * Future modifications to the PacketExtension will be reflected in this Packet.<p>
209      *
210      * Note: packet extensions on IQ packets are only for use in specialized situations.
211      * In most cases, you should only need to set the child element of the IQ.
212      *
213      * @param extension the PacketExtension whose element will be added to this Packet's element.
214      */

215     public void addExtension(PacketExtension extension) {
216         Element childElement = getChildElement();
217         if (childElement == null) {
218             throw new IllegalStateException JavaDoc("Cannot add packet extension when child element is null");
219         }
220         // Add the extension to the child element
221
childElement.add(extension.getElement());
222     }
223
224     /**
225      * Returns a {@link PacketExtension} on the first element found in this packet's
226      * child element for the specified <tt>name</tt> and <tt>namespace</tt> or <tt>null</tt> if
227      * none was found. If the IQ packet does not have a child element then <tt>null</tt>
228      * will be returned.<p>
229      *
230      * Note: packet extensions on IQ packets are only for use in specialized situations.
231      * In most cases, you should only need to set the child element of the IQ.
232      *
233      * @param name the child element name.
234      * @param namespace the child element namespace.
235      * @return a PacketExtension on the first element found in this packet for the specified
236      * name and namespace or <tt>null</tt> if none was found.
237      */

238     public PacketExtension getExtension(String JavaDoc name, String JavaDoc namespace) {
239         Element childElement = getChildElement();
240         if (childElement == null) {
241             return null;
242         }
243         // Search for extensions in the child element
244
List JavaDoc extensions = childElement.elements(QName.get(name, namespace));
245         if (!extensions.isEmpty()) {
246             Class JavaDoc extensionClass = PacketExtension.getExtensionClass(name, namespace);
247             if (extensionClass != null) {
248                 try {
249                     Constructor JavaDoc constructor = extensionClass.getDeclaredConstructor(new Class JavaDoc[]{
250                         Element.class});
251                     return (PacketExtension) constructor.newInstance(new Object JavaDoc[]{
252                         extensions.get(0)});
253                 }
254                 catch (Exception JavaDoc e) {
255                 }
256             }
257         }
258         return null;
259     }
260
261     /**
262      * Deletes the first element whose element name and namespace matches the specified
263      * element name and namespace in this packet's child element. If the
264      * IQ packet does not have a child element then this method does nothing and returns
265      * <tt>false</tt>.<p>
266      *
267      * Notice that this method may remove any child element that matches the specified
268      * element name and namespace even if that element was not added to the Packet using a
269      * {@link PacketExtension}.<p>
270      *
271      * Note: packet extensions on IQ packets are only for use in specialized situations.
272      * In most cases, you should only need to set the child element of the IQ.
273      *
274      * @param name the child element name.
275      * @param namespace the child element namespace.
276      * @return true if a child element was removed.
277      */

278     public boolean deleteExtension(String JavaDoc name, String JavaDoc namespace) {
279         Element childElement = getChildElement();
280         if (childElement == null) {
281             return false;
282         }
283         // Delete extensions in the child element
284
List JavaDoc extensions = childElement.elements(QName.get(name, namespace));
285         if (!extensions.isEmpty()) {
286             childElement.remove((Element) extensions.get(0));
287             return true;
288         }
289         return false;
290     }
291
292     /**
293      * Returns a deep copy of this IQ.
294      *
295      * @return a deep copy of this IQ.
296      */

297     public IQ createCopy() {
298         return new IQ(this);
299     }
300
301     /**
302      * Convenience method to create a new {@link Type#result IQ.Type.result} IQ based
303      * on a {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set} IQ. The new
304      * packet will be initialized with:<ul>
305      *
306      * <li>The sender set to the recipient of the originating IQ.
307      * <li>The recipient set to the sender of the originating IQ.
308      * <li>The type set to {@link Type#result IQ.Type.result}.
309      * <li>The id set to the id of the originating IQ.
310      * <li>An empty child element using the same element name and namespace
311      * as the orginiating IQ.
312      * </ul>
313      *
314      * @param iq the {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set} IQ packet.
315      * @throws IllegalArgumentException if the IQ packet does not have a type of
316      * {@link Type#get IQ.Type.get} or {@link Type#set IQ.Type.set}.
317      * @return a new {@link Type#result IQ.Type.result} IQ based on the originating IQ.
318      */

319     public static IQ createResultIQ(IQ iq) {
320         if (!(iq.getType() == Type.get || iq.getType() == Type.set)) {
321             throw new IllegalArgumentException JavaDoc("IQ must be of type 'set' or 'get'.");
322         }
323         IQ result = new IQ(Type.result, iq.getID());
324         result.setFrom(iq.getTo());
325         result.setTo(iq.getFrom());
326         return result;
327     }
328
329     /**
330      * Type-safe enumeration to represent the type of the IQ packet. The types are:
331      *
332      * <ul>
333      * <li>IQ.Type.get -- the IQ is a request for information or requirements.
334      * <li>IQ.Type.set -- the IQ provides required data, sets new values, or
335      * replaces existing values.
336      * <li>IQ.Type.result -- the IQ is a response to a successful get or set request.
337      * <li>IQ.Type.error -- an error has occurred regarding processing or delivery of a
338      * previously-sent get or set.
339      * </ul>
340      *
341      * If {@link #get IQ.Type.get} or {@link #set IQ.Type.set} is received the response
342      * must be {@link #result IQ.Type.result} or {@link #error IQ.Type.error}. The id of the
343      * originating {@link #get IQ.Type.get} of {@link #set IQ.Type.set} IQ must be preserved
344      * when sending {@link #result IQ.Type.result} or {@link #error IQ.Type.error}.
345      */

346     public enum Type {
347
348         /**
349          * The IQ is a request for information or requirements.
350          */

351         get,
352
353         /**
354          * The IQ provides required data, sets new values, or
355          * replaces existing values.
356          */

357         set,
358
359         /**
360          * The IQ is a response to a successful get or set request.
361          */

362         result,
363
364         /**
365          * An error has occurred regarding processing or delivery of a
366          * previously-sent get or set.
367          */

368         error;
369
370     }
371 }
Popular Tags