Home | History | Annotate | Download | only in packet
      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 
     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 }
    245