diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/LazyStringBuilder.java b/smack-core/src/main/java/org/jivesoftware/smack/util/LazyStringBuilder.java index 8aa834bbb..d7df08411 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/LazyStringBuilder.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/LazyStringBuilder.java @@ -22,13 +22,20 @@ import java.util.List; public class LazyStringBuilder implements Appendable, CharSequence { private final List list; - + + private String cache; + + private void invalidateCache() { + cache = null; + } + public LazyStringBuilder() { list = new ArrayList(20); } public LazyStringBuilder append(LazyStringBuilder lsb) { list.addAll(lsb.list); + invalidateCache(); return this; } @@ -36,6 +43,7 @@ public class LazyStringBuilder implements Appendable, CharSequence { public LazyStringBuilder append(CharSequence csq) { assert csq != null; list.add(csq); + invalidateCache(); return this; } @@ -43,17 +51,22 @@ public class LazyStringBuilder implements Appendable, CharSequence { public LazyStringBuilder append(CharSequence csq, int start, int end) { CharSequence subsequence = csq.subSequence(start, end); list.add(subsequence); + invalidateCache(); return this; } @Override public LazyStringBuilder append(char c) { list.add(Character.toString(c)); + invalidateCache(); return this; } @Override public int length() { + if (cache != null) { + return cache.length(); + } int length = 0; for (CharSequence csq : list) { length += csq.length(); @@ -63,6 +76,9 @@ public class LazyStringBuilder implements Appendable, CharSequence { @Override public char charAt(int index) { + if (cache != null) { + return cache.charAt(index); + } for (CharSequence csq : list) { if (index < csq.length()) { return csq.charAt(index); @@ -80,10 +96,13 @@ public class LazyStringBuilder implements Appendable, CharSequence { @Override public String toString() { - StringBuilder sb = new StringBuilder(length()); - for (CharSequence csq : list) { - sb.append(csq); + if (cache == null) { + StringBuilder sb = new StringBuilder(length()); + for (CharSequence csq : list) { + sb.append(csq); + } + cache = sb.toString(); } - return sb.toString(); + return cache; } } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java index 109187ced..9a39338a4 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java @@ -168,6 +168,25 @@ public class XmlStringBuilder implements Appendable, CharSequence { return this; } + public XmlStringBuilder emptyElement(String element) { + halfOpenElement(element); + return closeEmptyElement(); + } + + public XmlStringBuilder condEmptyElement(boolean condition, String element) { + if (condition) { + emptyElement(element); + } + return this; + } + + public XmlStringBuilder condAttribute(boolean condition, String name, String value) { + if (condition) { + attribute(name, value); + } + return this; + } + @Override public XmlStringBuilder append(CharSequence csq) { assert csq != null; @@ -207,4 +226,18 @@ public class XmlStringBuilder implements Appendable, CharSequence { public String toString() { return sb.toString(); } + + @Override + public boolean equals(Object other) { + if (!(other instanceof XmlStringBuilder)) { + return false; + } + XmlStringBuilder otherXmlStringBuilder = (XmlStringBuilder) other; + return toString().equals(otherXmlStringBuilder.toString()); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bookmarks/Bookmarks.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bookmarks/Bookmarks.java index 8d9d866fc..10fdb2c2d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bookmarks/Bookmarks.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bookmarks/Bookmarks.java @@ -16,6 +16,7 @@ */ package org.jivesoftware.smackx.bookmarks; +import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smackx.iqprivate.packet.PrivateData; import org.jivesoftware.smackx.iqprivate.provider.PrivateDataProvider; import org.xmlpull.v1.XmlPullParser; @@ -59,6 +60,9 @@ import java.util.List; */ public class Bookmarks implements PrivateData { + public static final String NAMESPACE = "storage:bookmarks"; + public static final String ELEMENT = "storage"; + private List bookmarkedURLS; private List bookmarkedConferences; @@ -145,7 +149,7 @@ public class Bookmarks implements PrivateData { * @return the element name. */ public String getElementName() { - return "storage"; + return ELEMENT; } /** @@ -154,28 +158,26 @@ public class Bookmarks implements PrivateData { * @return the namespace. */ public String getNamespace() { - return "storage:bookmarks"; + return NAMESPACE; } /** - * Returns the XML reppresentation of the PrivateData. + * Returns the XML representation of the PrivateData. * * @return the private data as XML. */ - public String toXML() { - StringBuilder buf = new StringBuilder(); - buf.append(""); + @Override + public XmlStringBuilder toXML() { + XmlStringBuilder buf = new XmlStringBuilder(); + buf.openElement(ELEMENT).xmlnsAttribute(NAMESPACE); for (BookmarkedURL urlStorage : getBookmarkedURLS()) { if(urlStorage.isShared()) { continue; } - buf.append(""); + buf.openElement("url").attribute("name", urlStorage.getName()).attribute("url", urlStorage.getURL()); + buf.condAttribute(urlStorage.isRss(), "rss", "true"); + buf.closeEmptyElement(); } // Add Conference additions @@ -183,26 +185,20 @@ public class Bookmarks implements PrivateData { if(conference.isShared()) { continue; } - buf.append(""); + buf.openElement("conference"); + buf.attribute("name", conference.getName()); + buf.attribute("autojoin", Boolean.toString(conference.isAutoJoin())); + buf.attribute("jid", conference.getJid()); + buf.rightAngelBracket(); - if (conference.getNickname() != null) { - buf.append("").append(conference.getNickname()).append(""); - } + buf.optElement("nick", conference.getNickname()); + buf.optElement("password", conference.getPassword()); - - if (conference.getPassword() != null) { - buf.append("").append(conference.getPassword()).append(""); - } - buf.append(""); + buf.closeElement("conference"); } - - buf.append(""); - return buf.toString(); + buf.closeElement(ELEMENT); + return buf; } /** diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java index 7ef889874..6bba70e3f 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java @@ -44,7 +44,6 @@ import org.jivesoftware.smackx.disco.packet.DiscoverInfo; import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Feature; import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Identity; import org.jivesoftware.smackx.disco.packet.DiscoverItems.Item; -import org.jivesoftware.smackx.xdata.Form; import org.jivesoftware.smackx.xdata.FormField; import org.jivesoftware.smackx.xdata.packet.DataForm; @@ -528,7 +527,7 @@ public class EntityCapsManager extends Manager { protected static boolean verifyPacketExtensions(DiscoverInfo info) { List foundFormTypes = new LinkedList(); for (PacketExtension pe : info.getExtensions()) { - if (pe.getNamespace().equals(Form.NAMESPACE)) { + if (pe.getNamespace().equals(DataForm.NAMESPACE)) { DataForm df = (DataForm) pe; for (FormField f : df.getFields()) { if (f.getVariable().equals("FORM_TYPE")) { @@ -561,7 +560,7 @@ public class EntityCapsManager extends Manager { if (md == null) return null; - DataForm extendedInfo = (DataForm) discoverInfo.getExtension(Form.ELEMENT, Form.NAMESPACE); + DataForm extendedInfo = (DataForm) discoverInfo.getExtension(DataForm.ELEMENT, DataForm.NAMESPACE); // 1. Initialize an empty string S ('sb' in this method). StringBuilder sb = new StringBuilder(); // Use StringBuilder as we don't diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqprivate/packet/PrivateData.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqprivate/packet/PrivateData.java index 0d0dee919..41d50b11b 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqprivate/packet/PrivateData.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqprivate/packet/PrivateData.java @@ -45,5 +45,5 @@ public interface PrivateData { * * @return the private data as XML. */ - public String toXML(); + public CharSequence toXML(); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/Form.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/Form.java index 2cfc311ac..06ec091b6 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/Form.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/Form.java @@ -49,9 +49,6 @@ public class Form { public static final String TYPE_CANCEL = "cancel"; public static final String TYPE_RESULT = "result"; - public static final String NAMESPACE = "jabber:x:data"; - public static final String ELEMENT = "x"; - private DataForm dataForm; /** diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java index 1d40525cc..1e7ba1bd8 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/FormField.java @@ -17,7 +17,6 @@ package org.jivesoftware.smackx.xdata; -import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.XmlStringBuilder; import java.util.ArrayList; @@ -33,6 +32,8 @@ import java.util.List; */ public class FormField { + public static final String ELEMENT = "field"; + public static final String TYPE_BOOLEAN = "boolean"; public static final String TYPE_FIXED = "fixed"; public static final String TYPE_HIDDEN = "hidden"; @@ -263,25 +264,17 @@ public class FormField { } } - public String toXML() { + public XmlStringBuilder toXML() { XmlStringBuilder buf = new XmlStringBuilder(); - buf.append(""); + buf.optAttribute("label", getLabel()); + buf.optAttribute("var", getVariable()); + buf.optAttribute("type", getType()); + buf.rightAngelBracket(); // Add elements - if (getDescription() != null) { - buf.append("").append(getDescription()).append(""); - } - if (isRequired()) { - buf.append(""); - } + buf.optElement("desc", getDescription()); + buf.condEmptyElement(isRequired(), "required"); // Loop through all the values and append them to the string buffer for (String value : getValues()) { buf.element("value", value); @@ -290,8 +283,8 @@ public class FormField { for (Option option : getOptions()) { buf.append(option.toXML()); } - buf.append(""); - return buf.toString(); + buf.closeElement(ELEMENT); + return buf; } @Override @@ -320,8 +313,10 @@ public class FormField { */ public static class Option { + public static final String ELEMNT = "option"; + + private final String value; private String label; - private String value; public Option(String value) { this.value = value; @@ -355,19 +350,18 @@ public class FormField { return getLabel(); } - public String toXML() { - StringBuilder buf = new StringBuilder(); - buf.append(""); - // Add element - buf.append("").append(StringUtils.escapeForXML(getValue())).append(""); + xml.optAttribute("label", getLabel()); + xml.rightAngelBracket(); - buf.append(""); - return buf.toString(); + // Add element + xml.element("value", getValue()); + + xml.closeElement(ELEMENT); + return xml; } @Override diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/packet/DataForm.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/packet/DataForm.java index 6ee3d80b6..9090a370a 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/packet/DataForm.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdata/packet/DataForm.java @@ -18,7 +18,7 @@ package org.jivesoftware.smackx.xdata.packet; import org.jivesoftware.smack.packet.PacketExtension; -import org.jivesoftware.smackx.xdata.Form; +import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smackx.xdata.FormField; import java.util.ArrayList; @@ -33,6 +33,9 @@ import java.util.List; */ public class DataForm implements PacketExtension { + public static final String NAMESPACE = "jabber:x:data"; + public static final String ELEMENT = "x"; + private String type; private String title; private List instructions = new ArrayList(); @@ -120,11 +123,11 @@ public class DataForm implements PacketExtension { } public String getElementName() { - return Form.ELEMENT; + return ELEMENT; } public String getNamespace() { - return Form.NAMESPACE; + return NAMESPACE; } /** @@ -207,15 +210,15 @@ public class DataForm implements PacketExtension { return found; } - public String toXML() { - StringBuilder buf = new StringBuilder(); - buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append( - "\" type=\"" + getType() +"\">"); - if (getTitle() != null) { - buf.append("").append(getTitle()).append(""); - } + @Override + public XmlStringBuilder toXML() { + XmlStringBuilder buf = new XmlStringBuilder(this); + buf.attribute("type", getType()); + buf.rightAngelBracket(); + + buf.optElement("title", getTitle()); for (String instruction : getInstructions()) { - buf.append("").append(instruction).append(""); + buf.element("instructions", instruction); } // Append the list of fields returned from a search if (getReportedData() != null) { @@ -229,8 +232,8 @@ public class DataForm implements PacketExtension { for (FormField field : getFields()) { buf.append(field.toXML()); } - buf.append(""); - return buf.toString(); + buf.closeElement(this); + return buf; } /** @@ -241,6 +244,8 @@ public class DataForm implements PacketExtension { * @author Gaston Dombiak */ public static class ReportedData { + public static final String ELEMENT = "reported"; + private List fields = new ArrayList(); public ReportedData(List fields) { @@ -256,15 +261,15 @@ public class DataForm implements PacketExtension { return Collections.unmodifiableList(new ArrayList(fields)); } - public String toXML() { - StringBuilder buf = new StringBuilder(); - buf.append(""); + public CharSequence toXML() { + XmlStringBuilder buf = new XmlStringBuilder(); + buf.openElement(ELEMENT); // Loop through all the form items and append them to the string buffer for (FormField field : getFields()) { buf.append(field.toXML()); } - buf.append(""); - return buf.toString(); + buf.closeElement(ELEMENT); + return buf; } } @@ -275,6 +280,8 @@ public class DataForm implements PacketExtension { * @author Gaston Dombiak */ public static class Item { + public static final String ELEMENT = "item"; + private List fields = new ArrayList(); public Item(List fields) { @@ -290,15 +297,15 @@ public class DataForm implements PacketExtension { return Collections.unmodifiableList(new ArrayList(fields)); } - public String toXML() { - StringBuilder buf = new StringBuilder(); - buf.append(""); + public CharSequence toXML() { + XmlStringBuilder buf = new XmlStringBuilder(); + buf.openElement(ELEMENT); // Loop through all the form items and append them to the string buffer for (FormField field : getFields()) { buf.append(field.toXML()); } - buf.append(""); - return buf.toString(); + buf.closeElement(ELEMENT); + return buf; } } } diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/filetransfer/FileTransferNegotiatorTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/filetransfer/FileTransferNegotiatorTest.java index f98b99887..ac4bad49f 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/filetransfer/FileTransferNegotiatorTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/filetransfer/FileTransferNegotiatorTest.java @@ -51,6 +51,6 @@ public class FileTransferNegotiatorTest { fileNeg.negotiateOutgoingTransfer("me", "streamid", "file", 1024, null, 10); Packet packet = connection.getSentPacket(); String xml = packet.toXML().toString(); - assertTrue(xml.indexOf("var='stream-method' type=\"list-single\"") != -1); + assertTrue(xml.indexOf("var='stream-method' type='list-single'") != -1); } }