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 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><query xmlns="jabber:iq:auth"> -- an authentication IQ. 36 * <li><query xmlns="jabber:iq:private"> -- a private storage IQ. 37 * <li><pubsub xmlns="http://jabber.org/protocol/pubsub"> -- 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} 245