M src/main/java/eu/siacs/conversations/xml/Element.java => src/main/java/eu/siacs/conversations/xml/Element.java +41 -19
@@ 3,19 3,21 @@ package eu.siacs.conversations.xml;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Hashtable;
import java.util.List;
+import java.util.stream.Collectors;
import eu.siacs.conversations.utils.XmlHelper;
import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
-public class Element {
+public class Element implements Node {
private final String name;
private Hashtable<String, String> attributes = new Hashtable<>();
- private String content;
- protected List<Element> children = new ArrayList<>();
+ private List<Element> children = new ArrayList<>();
+ private List<Node> childNodes = new ArrayList<>();
public Element(String name) {
this.name = name;
@@ 26,30 28,52 @@ public class Element {
this.setAttribute("xmlns", xmlns);
}
- public Element addChild(Element child) {
- this.content = null;
- children.add(child);
+ public Node prependChild(Node child) {
+ childNodes.add(0, child);
+ if (child instanceof Element) children.add(0, (Element) child);
+ return child;
+ }
+
+ public Node addChild(Node child) {
+ childNodes.add(child);
+ if (child instanceof Element) children.add((Element) child);
return child;
}
public Element addChild(String name) {
- this.content = null;
Element child = new Element(name);
+ childNodes.add(child);
children.add(child);
return child;
}
public Element addChild(String name, String xmlns) {
- this.content = null;
Element child = new Element(name);
child.setAttribute("xmlns", xmlns);
+ childNodes.add(child);
children.add(child);
return child;
}
+ public void addChildren(final Collection<? extends Node> children) {
+ if (children == null) return;
+
+ this.childNodes.addAll(children);
+ for (Node node : children) {
+ if (node instanceof Element) {
+ this.children.add((Element) node);
+ }
+ }
+ }
+
+ public void removeChild(Node child) {
+ this.childNodes.remove(child);
+ if (child instanceof Element) this.children.remove(child);
+ }
+
public Element setContent(String content) {
- this.content = content;
- this.children.clear();
+ clearChildren();
+ if (content != null) this.childNodes.add(new TextNode(content));
return this;
}
@@ 106,17 130,18 @@ public class Element {
return findChild(name, xmlns) != null;
}
- public List<Element> getChildren() {
+ public final List<Element> getChildren() {
return this.children;
}
public Element setChildren(List<Element> children) {
+ this.childNodes = new ArrayList(children);
this.children = children;
return this;
}
public final String getContent() {
- return content;
+ return this.childNodes.stream().map(Node::getContent).filter(c -> c != null).collect(Collectors.joining());
}
public Element setAttribute(String name, String value) {
@@ 170,7 195,7 @@ public class Element {
@NotNull
public String toString() {
final StringBuilder elementOutput = new StringBuilder();
- if ((content == null) && (children.size() == 0)) {
+ if (childNodes.size() == 0) {
Tag emptyTag = Tag.empty(name);
emptyTag.setAtttributes(this.attributes);
elementOutput.append(emptyTag.toString());
@@ 178,12 203,8 @@ public class Element {
Tag startTag = Tag.start(name);
startTag.setAtttributes(this.attributes);
elementOutput.append(startTag);
- if (content != null) {
- elementOutput.append(XmlHelper.encodeEntities(content));
- } else {
- for (Element child : children) {
- elementOutput.append(child.toString());
- }
+ for (Node child : childNodes) {
+ elementOutput.append(child.toString());
}
Tag endTag = Tag.end(name);
elementOutput.append(endTag);
@@ 197,6 218,7 @@ public class Element {
public void clearChildren() {
this.children.clear();
+ this.childNodes.clear();
}
public void setAttribute(String name, long value) {
M src/main/java/eu/siacs/conversations/xml/LocalizedContent.java => src/main/java/eu/siacs/conversations/xml/LocalizedContent.java +1 -1
@@ 23,7 23,7 @@ public class LocalizedContent {
public static LocalizedContent get(final Element element, String name) {
final HashMap<String, String> contents = new HashMap<>();
final String parentLanguage = element.getAttribute("xml:lang");
- for(Element child : element.children) {
+ for(Element child : element.getChildren()) {
if (name.equals(child.getName())) {
final String namespace = child.getNamespace();
final String childLanguage = child.getAttribute("xml:lang");
A src/main/java/eu/siacs/conversations/xml/Node.java => src/main/java/eu/siacs/conversations/xml/Node.java +5 -0
@@ 0,0 1,5 @@
+package eu.siacs.conversations.xml;
+
+public interface Node {
+ public String getContent();
+}
A src/main/java/eu/siacs/conversations/xml/TextNode.java => src/main/java/eu/siacs/conversations/xml/TextNode.java +20 -0
@@ 0,0 1,20 @@
+package eu.siacs.conversations.xml;
+
+import eu.siacs.conversations.utils.XmlHelper;
+
+public class TextNode implements Node {
+ protected String content;
+
+ public TextNode(final String content) {
+ if (content == null) throw new IllegalArgumentException("null TextNode is not allowed");
+ this.content = content;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public String toString() {
+ return XmlHelper.encodeEntities(content);
+ }
+}
M src/main/java/eu/siacs/conversations/xml/XmlReader.java => src/main/java/eu/siacs/conversations/xml/XmlReader.java +3 -8
@@ 94,15 94,10 @@ public class XmlReader implements Closeable {
if (nextTag == null) {
throw new IOException("interrupted mid tag");
}
- if (nextTag.isNo()) {
- element.setContent(nextTag.getName());
- nextTag = this.readTag();
- if (nextTag == null) {
- throw new IOException("interrupted mid tag");
- }
- }
while (!nextTag.isEnd(element.getName())) {
- if (!nextTag.isNo()) {
+ if (nextTag.isNo()) {
+ element.addChild(new TextNode(nextTag.getName()));
+ } else {
Element child = this.readElement(nextTag);
element.addChild(child);
}
M src/main/java/eu/siacs/conversations/xmpp/forms/Data.java => src/main/java/eu/siacs/conversations/xmpp/forms/Data.java +2 -7
@@ 4,8 4,8 @@ import android.os.Bundle;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
+import java.util.stream.Collectors;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
@@ 77,12 77,7 @@ public class Data extends Element {
}
private void removeUnnecessaryChildren() {
- for(Iterator<Element> iterator = this.children.iterator(); iterator.hasNext();) {
- Element element = iterator.next();
- if (!element.getName().equals("field") && !element.getName().equals("title")) {
- iterator.remove();
- }
- }
+ setChildren(getChildren().stream().filter(element -> element.getName().equals("field") || element.getName().equals("title")).collect(Collectors.toList()));
}
public static Data parse(Element element) {
M src/main/java/eu/siacs/conversations/xmpp/forms/Field.java => src/main/java/eu/siacs/conversations/xmpp/forms/Field.java +4 -13
@@ 2,8 2,8 @@ package eu.siacs.conversations.xmpp.forms;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
+import java.util.stream.Collectors;
import eu.siacs.conversations.xml.Element;
@@ 23,24 23,15 @@ public class Field extends Element {
}
public void setValue(String value) {
- this.children.clear();
- this.addChild("value").setContent(value);
+ setChildren(List.of(new Element("value").setContent(value)));
}
public void setValues(Collection<String> values) {
- this.children.clear();
- for(String value : values) {
- this.addChild("value").setContent(value);
- }
+ setChildren(values.stream().map(val -> new Element("value").setContent(val)).collect(Collectors.toList()));
}
public void removeNonValueChildren() {
- for(Iterator<Element> iterator = this.children.iterator(); iterator.hasNext();) {
- Element element = iterator.next();
- if (!element.getName().equals("value")) {
- iterator.remove();
- }
- }
+ setChildren(getChildren().stream().filter(element -> element.getName().equals("value")).collect(Collectors.toList()));
}
public static Field parse(Element element) {
M src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Group.java => src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Group.java +1 -1
@@ 29,7 29,7 @@ public class Group extends Element {
public List<String> getIdentificationTags() {
final ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
- for (final Element child : this.children) {
+ for (final Element child : getChildren()) {
if ("content".equals(child.getName())) {
final String name = child.getAttribute("name");
if (name != null) {
M src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Propose.java => src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Propose.java +1 -1
@@ 15,7 15,7 @@ public class Propose extends Element {
public List<GenericDescription> getDescriptions() {
final ImmutableList.Builder<GenericDescription> builder = new ImmutableList.Builder<>();
- for (final Element child : this.children) {
+ for (final Element child : getChildren()) {
if ("description".equals(child.getName())) {
final String namespace = child.getNamespace();
if (FileTransferDescription.NAMESPACES.contains(namespace)) {
M src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/RtpDescription.java => src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/RtpDescription.java +5 -19
@@ 66,7 66,7 @@ public class RtpDescription extends GenericDescription {
public List<Source> getSources() {
final ImmutableList.Builder<Source> builder = new ImmutableList.Builder<>();
- for (final Element child : this.children) {
+ for (final Element child : getChildren()) {
if ("source".equals(child.getName()) && Namespace.JINGLE_RTP_SOURCE_SPECIFIC_MEDIA_ATTRIBUTES.equals(child.getNamespace())) {
builder.add(Source.upgrade(child));
}
@@ 76,7 76,7 @@ public class RtpDescription extends GenericDescription {
public List<SourceGroup> getSourceGroups() {
final ImmutableList.Builder<SourceGroup> builder = new ImmutableList.Builder<>();
- for (final Element child : this.children) {
+ for (final Element child : getChildren()) {
if ("ssrc-group".equals(child.getName()) && Namespace.JINGLE_RTP_SOURCE_SPECIFIC_MEDIA_ATTRIBUTES.equals(child.getNamespace())) {
builder.add(SourceGroup.upgrade(child));
}
@@ 326,16 326,8 @@ public class RtpDescription extends GenericDescription {
return null;
}
- public void addChildren(final List<Element> children) {
- if (children != null) {
- this.children.addAll(children);
- }
- }
-
public void addParameters(List<Parameter> parameters) {
- if (parameters != null) {
- this.children.addAll(parameters);
- }
+ addChildren(parameters);
}
}
@@ 442,7 434,7 @@ public class RtpDescription extends GenericDescription {
public List<Parameter> getParameters() {
ImmutableList.Builder<Parameter> builder = new ImmutableList.Builder<>();
- for (Element child : this.children) {
+ for (Element child : getChildren()) {
if ("parameter".equals(child.getName())) {
builder.add(Parameter.upgrade(child));
}
@@ 512,7 504,7 @@ public class RtpDescription extends GenericDescription {
public List<String> getSsrcs() {
ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
- for (Element child : this.children) {
+ for (Element child : getChildren()) {
if ("source".equals(child.getName())) {
final String ssrc = child.getAttribute("ssrc");
if (ssrc != null) {
@@ 610,10 602,4 @@ public class RtpDescription extends GenericDescription {
}
return rtpDescription;
}
-
- private void addChildren(List<Element> elements) {
- if (elements != null) {
- this.children.addAll(elements);
- }
- }
}
M src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java => src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java +4 -6
@@ 22,15 22,13 @@ public class MessagePacket extends AbstractAcknowledgeableStanza {
}
public void setBody(String text) {
- this.children.remove(findChild("body"));
- Element body = new Element("body");
- body.setContent(text);
- this.children.add(0, body);
+ removeChild(findChild("body"));
+ prependChild(new Element("body").setContent(text));
}
public void setAxolotlMessage(Element axolotlMessage) {
- this.children.remove(findChild("body"));
- this.children.add(0, axolotlMessage);
+ removeChild(findChild("body"));
+ prependChild(axolotlMessage);
}
public void setType(int type) {