/** * * Copyright 2003-2007 Jive Software. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.smack.util; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.packet.Bind; import org.jivesoftware.smack.packet.DefaultPacketExtension; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Registration; import org.jivesoftware.smack.packet.RosterPacket; import org.jivesoftware.smack.packet.StreamError; import org.jivesoftware.smack.packet.XMPPError; import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.provider.PacketExtensionProvider; import org.jivesoftware.smack.provider.ProviderManager; import org.jivesoftware.smack.sasl.packet.SaslStanzas.SASLFailure; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; /** * Utility class that helps to parse packets. Any parsing packets method that must be shared * between many clients must be placed in this utility class. * * @author Gaston Dombiak */ public class PacketParserUtils { private static final Logger LOGGER = Logger.getLogger(PacketParserUtils.class.getName()); public static XmlPullParser getParserFor(String stanza) throws XmlPullParserException, IOException { return getParserFor(new StringReader(stanza)); } public static XmlPullParser getParserFor(Reader reader) throws XmlPullParserException, IOException { XmlPullParser parser = newXmppParser(); parser.setInput(reader); // Wind the parser forward to the first start tag int event = parser.getEventType(); while (event != XmlPullParser.START_TAG) { if (event == XmlPullParser.END_DOCUMENT) { throw new IllegalArgumentException("Document contains no start tag"); } event = parser.next(); } return parser; } public static XmlPullParser getParserFor(String stanza, String startTag) throws XmlPullParserException, IOException { XmlPullParser parser = getParserFor(stanza); while (true) { int event = parser.getEventType(); String name = parser.getName(); if (event == XmlPullParser.START_TAG && name.equals(startTag)) { break; } else if (event == XmlPullParser.END_DOCUMENT) { throw new IllegalArgumentException("Could not find start tag '" + startTag + "' in stanza: " + stanza); } parser.next(); } return parser; } public static Packet parseStanza(String stanza) throws Exception { return parseStanza(getParserFor(stanza)); } public static Packet parseStanza(XmlPullParser parser) throws Exception { return parseStanza(parser, null); } /** * Tries to parse and return either a Message, IQ or Presence stanza. * * connection is optional and is used to return feature-not-implemented errors for unknown IQ stanzas. * * @param parser * @param connection * @return a packet which is either a Message, IQ or Presence. * @throws Exception */ public static Packet parseStanza(XmlPullParser parser, XMPPConnection connection) throws Exception { final int eventType = parser.getEventType(); if (eventType != XmlPullParser.START_TAG) { throw new IllegalArgumentException("Parser not at start tag"); } final String name = parser.getName(); switch (name) { case "message": return parseMessage(parser); case "iq": return parseIQ(parser, connection); case "presence": return parsePresence(parser); default: return null; } } /** * Creates a new XmlPullParser suitable for parsing XMPP. This means in particular that * FEATURE_PROCESS_NAMESPACES is enabled. *

* Note that not all XmlPullParser implementations will return a String on * getText() if the parser is on START_TAG or END_TAG. So you must not rely on this * behavior when using the parser. *

* * @return A suitable XmlPullParser for XMPP parsing * @throws XmlPullParserException */ public static XmlPullParser newXmppParser() throws XmlPullParserException { XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); return parser; } /** * Parses a message packet. * * @param parser the XML parser, positioned at the start of a message packet. * @return a Message packet. * @throws Exception if an exception occurs while parsing the packet. */ public static Message parseMessage(XmlPullParser parser) throws Exception { Message message = new Message(); message.setPacketID(parser.getAttributeValue("", "id")); message.setTo(parser.getAttributeValue("", "to")); message.setFrom(parser.getAttributeValue("", "from")); String typeString = parser.getAttributeValue("", "type"); if (typeString != null) { message.setType(Message.Type.fromString(typeString)); } String language = getLanguageAttribute(parser); // determine message's default language String defaultLanguage = null; if (language != null && !"".equals(language.trim())) { message.setLanguage(language); defaultLanguage = language; } else { defaultLanguage = Packet.getDefaultLanguage(); } // Parse sub-elements. We include extra logic to make sure the values // are only read once. This is because it's possible for the names to appear // in arbitrary sub-elements. boolean done = false; String thread = null; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { String elementName = parser.getName(); String namespace = parser.getNamespace(); if (elementName.equals("subject")) { String xmlLang = getLanguageAttribute(parser); if (xmlLang == null) { xmlLang = defaultLanguage; } String subject = parseElementText(parser); if (message.getSubject(xmlLang) == null) { message.addSubject(xmlLang, subject); } } else if (elementName.equals(Message.BODY)) { String xmlLang = getLanguageAttribute(parser); if (xmlLang == null) { xmlLang = defaultLanguage; } String body = parseElementText(parser); if (message.getBody(xmlLang) == null) { message.addBody(xmlLang, body); } } else if (elementName.equals("thread")) { if (thread == null) { thread = parser.nextText(); } } else if (elementName.equals("error")) { message.setError(parseError(parser)); } // Otherwise, it must be a packet extension. else { message.addExtension( PacketParserUtils.parsePacketExtension(elementName, namespace, parser)); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("message")) { done = true; } } } message.setThread(thread); return message; } /** * Returns the textual content of an element as String. *

* The parser must be positioned on a START_TAG of an element which MUST NOT contain Mixed * Content (as defined in XML 3.2.2), or else an XmlPullParserException will be thrown. *

* This method is used for the parts where the XMPP specification requires elements that contain * only text or are the empty element. * * @param parser * @return the textual content of the element as String * @throws XmlPullParserException * @throws IOException */ public static String parseElementText(XmlPullParser parser) throws XmlPullParserException, IOException { assert (parser.getEventType() == XmlPullParser.START_TAG); String res; if (parser.isEmptyElementTag()) { res = ""; } else { // Advance to the text of the Element int event = parser.next(); if (event != XmlPullParser.TEXT) { throw new XmlPullParserException( "Non-empty element tag not followed by text, while Mixed Content (XML 3.2.2) is disallowed"); } res = parser.getText(); event = parser.next(); if (event != XmlPullParser.END_TAG) { throw new XmlPullParserException( "Non-empty element tag contains child-elements, while Mixed Content (XML 3.2.2) is disallowed"); } } return res; } /** * Returns the current element as string. *

* The parser must be positioned on START_TAG. *

* Note that only the outermost namespace attributes ("xmlns") will be returned, not nested ones. * * @param parser the XML pull parser * @return the element as string * @throws XmlPullParserException * @throws IOException */ public static CharSequence parseElement(XmlPullParser parser) throws XmlPullParserException, IOException { assert(parser.getEventType() == XmlPullParser.START_TAG); return parseContentDepth(parser, parser.getDepth()); } /** * Returns the content of a element. *

* The parser must be positioned on the START_TAG of the element which content is going to get * returned. If the current element is the empty element, then the empty string is returned. If * it is a element which contains just text, then just the text is returned. If it contains * nested elements (and text), then everything from the current opening tag to the corresponding * closing tag of the same depth is returned as String. *

* Note that only the outermost namespace attributes ("xmlns") will be returned, not nested ones. * * @param parser the XML pull parser * @return the content of a tag * @throws XmlPullParserException if parser encounters invalid XML * @throws IOException if an IO error occurs */ public static CharSequence parseContent(XmlPullParser parser) throws XmlPullParserException, IOException { assert(parser.getEventType() == XmlPullParser.START_TAG); if (parser.isEmptyElementTag()) { return ""; } // Advance the parser, since we want to parse the content of the current element parser.next(); return parseContentDepth(parser, parser.getDepth()); } /** * Returns the content from the current position of the parser up to the closing tag of the * given depth. Note that only the outermost namespace attributes ("xmlns") will be returned, * not nested ones. *

* This method is able to parse the content with MX- and KXmlParser. In order to achieve * this some trade-off has to be make, because KXmlParser does not support xml-roundtrip (ie. * return a String on getText() on START_TAG and END_TAG). We are therefore required to work * around this limitation, which results in only partial support for XML namespaces ("xmlns"): * Only the outermost namespace of elements will be included in the resulting String. *

* * @param parser * @param depth * @return the content of the current depth * @throws XmlPullParserException * @throws IOException */ public static CharSequence parseContentDepth(XmlPullParser parser, int depth) throws XmlPullParserException, IOException { XmlStringBuilder xml = new XmlStringBuilder(); int event = parser.getEventType(); boolean isEmptyElement = false; // XmlPullParser reports namespaces in nested elements even if *only* the outer ones defines // it. This 'flag' ensures that when a namespace is set for an element, it won't be set again // in a nested element. It's an ugly workaround that has the potential to break things. String namespaceElement = null;; while (true) { if (event == XmlPullParser.START_TAG) { xml.halfOpenElement(parser.getName()); if (namespaceElement == null) { String namespace = parser.getNamespace(); if (StringUtils.isNotEmpty(namespace)) { xml.attribute("xmlns", namespace); namespaceElement = parser.getName(); } } for (int i = 0; i < parser.getAttributeCount(); i++) { xml.attribute(parser.getAttributeName(i), parser.getAttributeValue(i)); } if (parser.isEmptyElementTag()) { xml.closeEmptyElement(); isEmptyElement = true; } else { xml.rightAngelBracket(); } } else if (event == XmlPullParser.END_TAG) { if (isEmptyElement) { // Do nothing as the element was already closed, just reset the flag isEmptyElement = false; } else { xml.closeElement(parser.getName()); } if (namespaceElement != null && namespaceElement.equals(parser.getName())) { // We are on the closing tag, which defined the namespace as starting tag, reset the 'flag' namespaceElement = null; } if (parser.getDepth() <= depth) { // Abort parsing, we are done break; } } else if (event == XmlPullParser.TEXT) { xml.append(parser.getText()); } event = parser.next(); } return xml; } /** * Parses a presence packet. * * @param parser the XML parser, positioned at the start of a presence packet. * @return a Presence packet. * @throws Exception if an exception occurs while parsing the packet. */ public static Presence parsePresence(XmlPullParser parser) throws Exception { Presence.Type type = Presence.Type.available; String typeString = parser.getAttributeValue("", "type"); if (typeString != null && !typeString.equals("")) { type = Presence.Type.fromString(typeString); } Presence presence = new Presence(type); presence.setTo(parser.getAttributeValue("", "to")); presence.setFrom(parser.getAttributeValue("", "from")); presence.setPacketID(parser.getAttributeValue("", "id")); String language = getLanguageAttribute(parser); if (language != null && !"".equals(language.trim())) { presence.setLanguage(language); } // Parse sub-elements boolean done = false; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { String elementName = parser.getName(); String namespace = parser.getNamespace(); if (elementName.equals("status")) { presence.setStatus(parser.nextText()); } else if (elementName.equals("priority")) { int priority = Integer.parseInt(parser.nextText()); presence.setPriority(priority); } else if (elementName.equals("show")) { String modeText = parser.nextText(); presence.setMode(Presence.Mode.fromString(modeText)); } else if (elementName.equals("error")) { presence.setError(parseError(parser)); } // Otherwise, it must be a packet extension. else { // Be extra robust: Skip PacketExtensions that cause Exceptions, instead of // failing completely here. See SMACK-390 for more information. try { presence.addExtension(PacketParserUtils.parsePacketExtension(elementName, namespace, parser)); } catch (Exception e) { LOGGER.warning("Failed to parse extension packet in Presence packet."); } } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("presence")) { done = true; } } } return presence; } /** * Parses an IQ packet. * * @param parser the XML parser, positioned at the start of an IQ packet. * @param connection the optional XMPPConnection used to send feature-not-implemented replies. * @return an IQ object. * @throws Exception if an exception occurs while parsing the packet. */ public static IQ parseIQ(XmlPullParser parser, XMPPConnection connection) throws Exception { IQ iqPacket = null; XMPPError error = null; final String id = parser.getAttributeValue("", "id"); final String to = parser.getAttributeValue("", "to"); final String from = parser.getAttributeValue("", "from"); final IQ.Type type = IQ.Type.fromString(parser.getAttributeValue("", "type")); boolean done = false; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { String elementName = parser.getName(); String namespace = parser.getNamespace(); if (elementName.equals("error")) { error = PacketParserUtils.parseError(parser); } else if (elementName.equals("query") && namespace.equals("jabber:iq:roster")) { iqPacket = parseRoster(parser); } else if (elementName.equals("query") && namespace.equals("jabber:iq:register")) { iqPacket = parseRegistration(parser); } else if (elementName.equals("bind") && namespace.equals("urn:ietf:params:xml:ns:xmpp-bind")) { iqPacket = parseResourceBinding(parser); } // Otherwise, see if there is a registered provider for // this element name and namespace. else { Object provider = ProviderManager.getIQProvider(elementName, namespace); if (provider != null) { if (provider instanceof IQProvider) { iqPacket = ((IQProvider)provider).parseIQ(parser); } else if (provider instanceof Class) { iqPacket = (IQ)PacketParserUtils.parseWithIntrospection(elementName, (Class)provider, parser); } } // Only handle unknown IQs of type result. Types of 'get' and 'set' which are not understood // have to be answered with an IQ error response. See the code a few lines below else if (IQ.Type.result == type){ // No Provider found for the IQ stanza, parse it to an UnparsedIQ instance // so that the content of the IQ can be examined later on iqPacket = new UnparsedResultIQ(parseContent(parser)); } } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("iq")) { done = true; } } } // Decide what to do when an IQ packet was not understood if (iqPacket == null) { if (connection != null && (IQ.Type.get == type || IQ.Type.set == type)) { // If the IQ stanza is of type "get" or "set" containing a child element qualified // by a namespace with no registered Smack provider, then answer an IQ of type // "error" with code 501 ("feature-not-implemented") iqPacket = new IQ() { @Override public String getChildElementXML() { return null; } }; iqPacket.setPacketID(id); iqPacket.setTo(from); iqPacket.setFrom(to); iqPacket.setType(IQ.Type.error); iqPacket.setError(new XMPPError(XMPPError.Condition.feature_not_implemented)); connection.sendPacket(iqPacket); return null; } else { // If an IQ packet wasn't created above, create an empty IQ packet. iqPacket = new IQ() { @Override public String getChildElementXML() { return null; } }; } } // Set basic values on the iq packet. iqPacket.setPacketID(id); iqPacket.setTo(to); iqPacket.setFrom(from); iqPacket.setType(type); iqPacket.setError(error); return iqPacket; } private static RosterPacket parseRoster(XmlPullParser parser) throws Exception { RosterPacket roster = new RosterPacket(); boolean done = false; RosterPacket.Item item = null; String version = parser.getAttributeValue("", "ver"); roster.setVersion(version); while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { if (parser.getName().equals("item")) { String jid = parser.getAttributeValue("", "jid"); String name = parser.getAttributeValue("", "name"); // Create packet. item = new RosterPacket.Item(jid, name); // Set status. String ask = parser.getAttributeValue("", "ask"); RosterPacket.ItemStatus status = RosterPacket.ItemStatus.fromString(ask); item.setItemStatus(status); // Set type. String subscription = parser.getAttributeValue("", "subscription"); RosterPacket.ItemType type = RosterPacket.ItemType.valueOf(subscription != null ? subscription : "none"); item.setItemType(type); } else if (parser.getName().equals("group") && item!= null) { final String groupName = parser.nextText(); if (groupName != null && groupName.trim().length() > 0) { item.addGroupName(groupName); } } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("item")) { roster.addRosterItem(item); } if (parser.getName().equals("query")) { done = true; } } } return roster; } private static Registration parseRegistration(XmlPullParser parser) throws Exception { Registration registration = new Registration(); Map fields = null; boolean done = false; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { // Any element that's in the jabber:iq:register namespace, // attempt to parse it if it's in the form value. if (parser.getNamespace().equals("jabber:iq:register")) { String name = parser.getName(); String value = ""; if (fields == null) { fields = new HashMap(); } if (parser.next() == XmlPullParser.TEXT) { value = parser.getText(); } // Ignore instructions, but anything else should be added to the map. if (!name.equals("instructions")) { fields.put(name, value); } else { registration.setInstructions(value); } } // Otherwise, it must be a packet extension. else { registration.addExtension( PacketParserUtils.parsePacketExtension( parser.getName(), parser.getNamespace(), parser)); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("query")) { done = true; } } } registration.setAttributes(fields); return registration; } private static Bind parseResourceBinding(XmlPullParser parser) throws IOException, XmlPullParserException { Bind bind = new Bind(); boolean done = false; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { if (parser.getName().equals("resource")) { bind.setResource(parser.nextText()); } else if (parser.getName().equals("jid")) { bind.setJid(parser.nextText()); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("bind")) { done = true; } } } return bind; } /** * Parse the available SASL mechanisms reported from the server. * * @param parser the XML parser, positioned at the start of the mechanisms stanza. * @return a collection of Stings with the mechanisms included in the mechanisms stanza. * @throws Exception if an exception occurs while parsing the stanza. */ public static Collection parseMechanisms(XmlPullParser parser) throws Exception { List mechanisms = new ArrayList(); boolean done = false; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { String elementName = parser.getName(); if (elementName.equals("mechanism")) { mechanisms.add(parser.nextText()); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("mechanisms")) { done = true; } } } return mechanisms; } /** * Parse the available compression methods reported from the server. * * @param parser the XML parser, positioned at the start of the compression stanza. * @return a collection of Stings with the methods included in the compression stanza. * @throws XmlPullParserException if an exception occurs while parsing the stanza. */ public static Collection parseCompressionMethods(XmlPullParser parser) throws IOException, XmlPullParserException { List methods = new ArrayList(); boolean done = false; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { String elementName = parser.getName(); if (elementName.equals("method")) { methods.add(parser.nextText()); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("compression")) { done = true; } } } return methods; } /** * Parses SASL authentication error packets. * * @param parser the XML parser. * @return a SASL Failure packet. * @throws Exception if an exception occurs while parsing the packet. */ public static SASLFailure parseSASLFailure(XmlPullParser parser) throws Exception { String condition = null; boolean done = false; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { if (!parser.getName().equals("failure")) { condition = parser.getName(); } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals("failure")) { done = true; } } } return new SASLFailure(condition); } /** * Parses stream error packets. * * @param parser the XML parser. * @return an stream error packet. * @throws XmlPullParserException if an exception occurs while parsing the packet. */ public static StreamError parseStreamError(XmlPullParser parser) throws IOException, XmlPullParserException { final int depth = parser.getDepth(); boolean done = false; String code = null; String text = null; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { String namespace = parser.getNamespace(); if (StreamError.NAMESPACE.equals(namespace)) { String name = parser.getName(); if (name.equals(Packet.TEXT) && !parser.isEmptyElementTag()) { parser.next(); text = parser.getText(); } else { // If it's not a text element, that is qualified by the StreamError.NAMESPACE, // then it has to be the stream error code code = name; } } } else if (eventType == XmlPullParser.END_TAG && depth == parser.getDepth()) { done = true; } } return new StreamError(code, text); } /** * Parses error sub-packets. * * @param parser the XML parser. * @return an error sub-packet. * @throws Exception if an exception occurs while parsing the packet. */ public static XMPPError parseError(XmlPullParser parser) throws Exception { final String errorNamespace = "urn:ietf:params:xml:ns:xmpp-stanzas"; String type = null; String message = null; String condition = null; List extensions = new ArrayList(); // Parse the error header for (int i=0; i)provider, parser); } } // No providers registered, so use a default extension. DefaultPacketExtension extension = new DefaultPacketExtension(elementName, namespace); boolean done = false; while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { String name = parser.getName(); // If an empty element, set the value with the empty string. if (parser.isEmptyElementTag()) { extension.setValue(name,""); } // Otherwise, get the the element text. else { eventType = parser.next(); if (eventType == XmlPullParser.TEXT) { String value = parser.getText(); extension.setValue(name, value); } } } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals(elementName)) { done = true; } } } return extension; } private static String getLanguageAttribute(XmlPullParser parser) { for (int i = 0; i < parser.getAttributeCount(); i++) { String attributeName = parser.getAttributeName(i); if ( "xml:lang".equals(attributeName) || ("lang".equals(attributeName) && "xml".equals(parser.getAttributePrefix(i)))) { return parser.getAttributeValue(i); } } return null; } public static Object parseWithIntrospection(String elementName, Class objectClass, XmlPullParser parser) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, XmlPullParserException, IOException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException { boolean done = false; Object object = objectClass.newInstance(); while (!done) { int eventType = parser.next(); if (eventType == XmlPullParser.START_TAG) { String name = parser.getName(); String stringValue = parser.nextText(); Class propertyType = object.getClass().getMethod( "get" + Character.toUpperCase(name.charAt(0)) + name.substring(1)).getReturnType(); // Get the value of the property by converting it from a // String to the correct object type. Object value = decode(propertyType, stringValue); // Set the value of the bean. object.getClass().getMethod( "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1), propertyType).invoke(object, value); } else if (eventType == XmlPullParser.END_TAG) { if (parser.getName().equals(elementName)) { done = true; } } } return object; } /** * Decodes a String into an object of the specified type. If the object * type is not supported, null will be returned. * * @param type the type of the property. * @param value the encode String value to decode. * @return the String value decoded into the specified type. * @throws ClassNotFoundException */ private static Object decode(Class type, String value) throws ClassNotFoundException { if (type.getName().equals("java.lang.String")) { return value; } if (type.getName().equals("boolean")) { return Boolean.valueOf(value); } if (type.getName().equals("int")) { return Integer.valueOf(value); } if (type.getName().equals("long")) { return Long.valueOf(value); } if (type.getName().equals("float")) { return Float.valueOf(value); } if (type.getName().equals("double")) { return Double.valueOf(value); } if (type.getName().equals("java.lang.Class")) { return Class.forName(value); } return null; } /** * This class represents and unparsed IQ of the type 'result'. Usually it's created when no IQProvider * was found for the IQ element. * * The child elements can be examined with the getChildElementXML() method. * */ public static class UnparsedResultIQ extends IQ { public UnparsedResultIQ(CharSequence content) { this.content = content; } private final CharSequence content; @Override public CharSequence getChildElementXML() { return this.content; } } }