mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 06:12:05 +01:00
Improve writing XML elements to socket
Instead of allocating one big continuous memory block before "writing" the XMPP stream element to the socket, write the single CharSequences of LazyStringBuilder/XmlStringBuilder. Also change Obserable writer to only notify the listeners after a flush *or* if a certain limit has been reached since the last notification. Otherwise the debugger would "print" every single XML part as result of this change.
This commit is contained in:
parent
3c2ba0ec43
commit
8db0403138
4 changed files with 62 additions and 6 deletions
|
@ -17,6 +17,7 @@
|
||||||
package org.jivesoftware.smack.util;
|
package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class LazyStringBuilder implements Appendable, CharSequence {
|
public class LazyStringBuilder implements Appendable, CharSequence {
|
||||||
|
@ -105,4 +106,17 @@ public class LazyStringBuilder implements Appendable, CharSequence {
|
||||||
}
|
}
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the List of CharSequences representation of this instance. The list is unmodifiable. If
|
||||||
|
* the resulting String was already cached, a list with a single String entry will be returned.
|
||||||
|
*
|
||||||
|
* @return a List of CharSequences representing this instance.
|
||||||
|
*/
|
||||||
|
public List<CharSequence> getAsList() {
|
||||||
|
if (cache != null) {
|
||||||
|
return Collections.singletonList((CharSequence) cache);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,11 @@ import java.util.List;
|
||||||
* @author Gaston Dombiak
|
* @author Gaston Dombiak
|
||||||
*/
|
*/
|
||||||
public class ObservableWriter extends Writer {
|
public class ObservableWriter extends Writer {
|
||||||
|
private static final int MAX_STRING_BUILDER_SIZE = 4096;
|
||||||
|
|
||||||
Writer wrappedWriter = null;
|
Writer wrappedWriter = null;
|
||||||
List<WriterListener> listeners = new ArrayList<WriterListener>();
|
List<WriterListener> listeners = new ArrayList<WriterListener>();
|
||||||
|
private final StringBuilder stringBuilder = new StringBuilder(MAX_STRING_BUILDER_SIZE);
|
||||||
|
|
||||||
public ObservableWriter(Writer wrappedWriter) {
|
public ObservableWriter(Writer wrappedWriter) {
|
||||||
this.wrappedWriter = wrappedWriter;
|
this.wrappedWriter = wrappedWriter;
|
||||||
|
@ -39,10 +41,11 @@ public class ObservableWriter extends Writer {
|
||||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||||
wrappedWriter.write(cbuf, off, len);
|
wrappedWriter.write(cbuf, off, len);
|
||||||
String str = new String(cbuf, off, len);
|
String str = new String(cbuf, off, len);
|
||||||
notifyListeners(str);
|
maybeNotifyListeners(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
|
notifyListeners();
|
||||||
wrappedWriter.flush();
|
wrappedWriter.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,18 +60,25 @@ public class ObservableWriter extends Writer {
|
||||||
public void write(char[] cbuf) throws IOException {
|
public void write(char[] cbuf) throws IOException {
|
||||||
wrappedWriter.write(cbuf);
|
wrappedWriter.write(cbuf);
|
||||||
String str = new String(cbuf);
|
String str = new String(cbuf);
|
||||||
notifyListeners(str);
|
maybeNotifyListeners(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(String str) throws IOException {
|
public void write(String str) throws IOException {
|
||||||
wrappedWriter.write(str);
|
wrappedWriter.write(str);
|
||||||
notifyListeners(str);
|
maybeNotifyListeners(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(String str, int off, int len) throws IOException {
|
public void write(String str, int off, int len) throws IOException {
|
||||||
wrappedWriter.write(str, off, len);
|
wrappedWriter.write(str, off, len);
|
||||||
str = str.substring(off, off + len);
|
str = str.substring(off, off + len);
|
||||||
notifyListeners(str);
|
maybeNotifyListeners(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeNotifyListeners(String s) {
|
||||||
|
stringBuilder.append(s);
|
||||||
|
if (stringBuilder.length() > MAX_STRING_BUILDER_SIZE) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,12 +86,14 @@ public class ObservableWriter extends Writer {
|
||||||
*
|
*
|
||||||
* @param str the written String to notify
|
* @param str the written String to notify
|
||||||
*/
|
*/
|
||||||
private void notifyListeners(String str) {
|
private void notifyListeners() {
|
||||||
WriterListener[] writerListeners = null;
|
WriterListener[] writerListeners = null;
|
||||||
synchronized (listeners) {
|
synchronized (listeners) {
|
||||||
writerListeners = new WriterListener[listeners.size()];
|
writerListeners = new WriterListener[listeners.size()];
|
||||||
listeners.toArray(writerListeners);
|
listeners.toArray(writerListeners);
|
||||||
}
|
}
|
||||||
|
String str = stringBuilder.toString();
|
||||||
|
stringBuilder.setLength(0);
|
||||||
for (int i = 0; i < writerListeners.length; i++) {
|
for (int i = 0; i < writerListeners.length; i++) {
|
||||||
writerListeners[i].write(str);
|
writerListeners[i].write(str);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.util;
|
package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
@ -459,4 +461,23 @@ public class XmlStringBuilder implements Appendable, CharSequence {
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return toString().hashCode();
|
return toString().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the contents of this <code>XmlStringBuilder</code> to a {@link Writer}. This will write
|
||||||
|
* the single parts one-by-one, avoiding allocation of a big continuous memory block holding the
|
||||||
|
* XmlStringBuilder contents.
|
||||||
|
*
|
||||||
|
* @param writer
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void write(Writer writer) throws IOException {
|
||||||
|
for (CharSequence csq : sb.getAsList()) {
|
||||||
|
if (csq instanceof XmlStringBuilder) {
|
||||||
|
((XmlStringBuilder) csq).write(writer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
writer.write(csq.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ import org.jivesoftware.smack.util.Async;
|
||||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smack.util.TLSUtils;
|
import org.jivesoftware.smack.util.TLSUtils;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
import org.jivesoftware.smack.util.dns.HostAddress;
|
import org.jivesoftware.smack.util.dns.HostAddress;
|
||||||
import org.jxmpp.jid.impl.JidCreate;
|
import org.jxmpp.jid.impl.JidCreate;
|
||||||
import org.jxmpp.jid.parts.Resourcepart;
|
import org.jxmpp.jid.parts.Resourcepart;
|
||||||
|
@ -1316,7 +1317,15 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.write(element.toXML().toString());
|
|
||||||
|
CharSequence elementXml = element.toXML();
|
||||||
|
if (elementXml instanceof XmlStringBuilder) {
|
||||||
|
((XmlStringBuilder) elementXml).write(writer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
writer.write(elementXml.toString());
|
||||||
|
}
|
||||||
|
|
||||||
if (queue.isEmpty()) {
|
if (queue.isEmpty()) {
|
||||||
writer.flush();
|
writer.flush();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue