summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Smith <git@kismith.co.uk>2011-07-01 09:19:49 (GMT)
committerKevin Smith <git@kismith.co.uk>2011-07-01 09:19:49 (GMT)
commit2da71a8a85486a494343f1662d64fb5ae5a2a44e (patch)
tree23992f9f2a00bac23b345e5c2cc9c1194efc25be /src/com/isode/stroke/streamstack
downloadstroke-2da71a8a85486a494343f1662d64fb5ae5a2a44e.zip
stroke-2da71a8a85486a494343f1662d64fb5ae5a2a44e.tar.bz2
Initial import
Diffstat (limited to 'src/com/isode/stroke/streamstack')
-rw-r--r--src/com/isode/stroke/streamstack/CompressionLayer.java43
-rw-r--r--src/com/isode/stroke/streamstack/ConnectionLayer.java58
-rw-r--r--src/com/isode/stroke/streamstack/HighLayer.java31
-rw-r--r--src/com/isode/stroke/streamstack/LowLayer.java30
-rw-r--r--src/com/isode/stroke/streamstack/StreamLayer.java50
-rw-r--r--src/com/isode/stroke/streamstack/StreamStack.java52
-rw-r--r--src/com/isode/stroke/streamstack/TLSLayer.java73
-rw-r--r--src/com/isode/stroke/streamstack/WhitespacePingLayer.java61
-rw-r--r--src/com/isode/stroke/streamstack/XMPPLayer.java152
9 files changed, 550 insertions, 0 deletions
diff --git a/src/com/isode/stroke/streamstack/CompressionLayer.java b/src/com/isode/stroke/streamstack/CompressionLayer.java
new file mode 100644
index 0000000..fae8263
--- /dev/null
+++ b/src/com/isode/stroke/streamstack/CompressionLayer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010 Remko Tron¨on
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+/*
+ * Copyright (c) 2011, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.streamstack;
+
+import com.isode.stroke.base.ByteArray;
+import com.isode.stroke.compress.ZLibCompressor;
+import com.isode.stroke.compress.ZLibDecompressor;
+import com.isode.stroke.compress.ZLibException;
+import com.isode.stroke.signals.Signal;
+
+public class CompressionLayer extends StreamLayer {
+
+ public void writeData(ByteArray data) {
+ try {
+ writeDataToChildLayer(compressor_.process(data));
+ }
+ catch (ZLibException e) {
+ onError.emit();
+ }
+ }
+
+ public void handleDataRead(ByteArray data) {
+ try {
+ writeDataToParentLayer(decompressor_.process(data));
+ }
+ catch (ZLibException e) {
+ onError.emit();
+ }
+ }
+
+ public Signal onError = new Signal();
+
+ private ZLibCompressor compressor_ = new ZLibCompressor();
+ private ZLibDecompressor decompressor_ = new ZLibDecompressor();
+
+}
diff --git a/src/com/isode/stroke/streamstack/ConnectionLayer.java b/src/com/isode/stroke/streamstack/ConnectionLayer.java
new file mode 100644
index 0000000..525da50
--- /dev/null
+++ b/src/com/isode/stroke/streamstack/ConnectionLayer.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010 Remko Tron¨on
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+/*
+ * Copyright (c) 2010, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.streamstack;
+
+import com.isode.stroke.base.ByteArray;
+import com.isode.stroke.network.Connection;
+import com.isode.stroke.signals.Signal1;
+import com.isode.stroke.signals.Slot1;
+
+public class ConnectionLayer implements LowLayer {
+
+ public ConnectionLayer(Connection connection) {
+ this.connection = connection;
+ connection.onDataRead.connect(new Slot1<ByteArray>() {
+
+ public void call(ByteArray p1) {
+ writeDataToParentLayer(p1);
+ }
+ });
+ }
+
+ public void writeData(ByteArray data) {
+ connection.write(data);
+ }
+
+ private Connection connection;
+
+ /* Work around multiple inheritance workaround again */
+ StreamLayer fakeStreamLayer_ = new StreamLayer() {
+
+ public void writeData(ByteArray data) {
+ connection.write(data);
+ }
+
+ public void handleDataRead(ByteArray data) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ };
+
+ public HighLayer getParentLayer() {
+ return fakeStreamLayer_.getParentLayer();
+ }
+
+ public void setParentLayer(HighLayer parentLayer) {
+ fakeStreamLayer_.setParentLayer(parentLayer);
+ }
+
+ public void writeDataToParentLayer(ByteArray data) {
+ fakeStreamLayer_.writeDataToParentLayer(data);
+ }
+}
diff --git a/src/com/isode/stroke/streamstack/HighLayer.java b/src/com/isode/stroke/streamstack/HighLayer.java
new file mode 100644
index 0000000..9ef37d1
--- /dev/null
+++ b/src/com/isode/stroke/streamstack/HighLayer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2010 Remko Tron¨on
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+/*
+ * Copyright (c) 2010-2011, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.streamstack;
+
+import com.isode.stroke.base.ByteArray;
+
+/**
+ * Because of the lack of multiple inheritance in Java, this has to be done
+ * slightly differently from Swiften. What happens is that the methods in Swiften
+ * are provided abstract here, and implemented in the StreamLayer instead.
+ */
+public interface HighLayer {
+
+ void handleDataRead(ByteArray data);
+
+
+ /* Should be protected */
+ LowLayer getChildLayer();
+
+ void setChildLayer(LowLayer childLayer);
+
+ void writeDataToChildLayer(ByteArray data);
+
+}
diff --git a/src/com/isode/stroke/streamstack/LowLayer.java b/src/com/isode/stroke/streamstack/LowLayer.java
new file mode 100644
index 0000000..fa31075
--- /dev/null
+++ b/src/com/isode/stroke/streamstack/LowLayer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010 Remko Tron¨on
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+/*
+ * Copyright (c) 2010-2011, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.streamstack;
+
+import com.isode.stroke.base.ByteArray;
+
+/**
+ * Because of the lack of multiple inheritance in Java, this has to be done
+ * slightly differently from Swiften. What happens is that the methods in Swiften
+ * are provided abstract here, and implemented in the StreamLayer instead.
+ */
+public interface LowLayer {
+
+ void writeData(ByteArray data);
+
+ /* Should be protected */
+
+ HighLayer getParentLayer();
+
+ void setParentLayer(HighLayer parentLayer);
+
+ void writeDataToParentLayer(ByteArray data);
+}
diff --git a/src/com/isode/stroke/streamstack/StreamLayer.java b/src/com/isode/stroke/streamstack/StreamLayer.java
new file mode 100644
index 0000000..c6d8f50
--- /dev/null
+++ b/src/com/isode/stroke/streamstack/StreamLayer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010 Remko Tron¨on
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+/*
+ * Copyright (c) 2010-2011, Isode Limited, London, England.
+ * All rights reserved.
+ */
+
+package com.isode.stroke.streamstack;
+
+import com.isode.stroke.base.ByteArray;
+
+/**
+ * Because of the lack of multiple inheritance in Java, this implements
+ * the abstract methods that should have been implemented in
+ * LowLayer and HighLayer.
+ */
+public abstract class StreamLayer implements LowLayer, HighLayer {
+
+ public HighLayer getParentLayer() {
+ return parentLayer;
+ }
+
+ public void setParentLayer(final HighLayer parentLayer) {
+ this.parentLayer = parentLayer;
+ }
+
+ public void writeDataToParentLayer(final ByteArray data) {
+ assert parentLayer != null;
+ parentLayer.handleDataRead(data);
+ }
+
+ public LowLayer getChildLayer() {
+ return childLayer;
+ }
+
+ public void setChildLayer(final LowLayer childLayer) {
+ this.childLayer = childLayer;
+ }
+
+ public void writeDataToChildLayer(final ByteArray data) {
+ assert childLayer != null;
+ childLayer.writeData(data);
+ }
+
+ private HighLayer parentLayer;
+ private LowLayer childLayer;
+}
diff --git a/src/com/isode/stroke/streamstack/StreamStack.java b/src/com/isode/stroke/streamstack/StreamStack.java
new file mode 100644
index 0000000..f539624
--- /dev/null
+++ b/src/com/isode/stroke/streamstack/StreamStack.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010 Remko Tron¨on
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+/*
+ * Copyright (c) 2010, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.streamstack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StreamStack {
+
+ public StreamStack(XMPPLayer xmppLayer, LowLayer physicalLayer) {
+ xmppLayer_ = xmppLayer;
+ physicalLayer_ = physicalLayer;
+ physicalLayer_.setParentLayer(xmppLayer_);
+ xmppLayer.setChildLayer(physicalLayer_);
+ }
+
+ public void addLayer(final StreamLayer newLayer) {
+ final LowLayer lowLayer = (layers_.isEmpty() ? physicalLayer_ : layers_.get(layers_.size() - 1));
+
+ xmppLayer_.setChildLayer(newLayer);
+ newLayer.setParentLayer(xmppLayer_);
+
+ lowLayer.setParentLayer(newLayer);
+ newLayer.setChildLayer(lowLayer);
+
+ layers_.add(newLayer);
+ }
+
+ public XMPPLayer getXMPPLayer() {
+ return xmppLayer_;
+ }
+
+ public Object getLayer(Class layerClass) {
+ for (StreamLayer layer : layers_) {
+ if (layerClass.isAssignableFrom(layer.getClass())) {
+ return layer;
+ }
+ }
+ return null;
+ }
+
+ private XMPPLayer xmppLayer_;
+ private LowLayer physicalLayer_;
+ private List<StreamLayer> layers_ = new ArrayList<StreamLayer>();
+}
diff --git a/src/com/isode/stroke/streamstack/TLSLayer.java b/src/com/isode/stroke/streamstack/TLSLayer.java
new file mode 100644
index 0000000..ecf908d
--- /dev/null
+++ b/src/com/isode/stroke/streamstack/TLSLayer.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2010, Isode Limited, London, England.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 2010, Remko Tron¨on.
+ * All rights reserved.
+ */
+
+package com.isode.stroke.streamstack;
+
+import com.isode.stroke.base.ByteArray;
+import com.isode.stroke.signals.Signal;
+import com.isode.stroke.signals.Slot1;
+import com.isode.stroke.tls.Certificate;
+import com.isode.stroke.tls.CertificateVerificationError;
+import com.isode.stroke.tls.PKCS12Certificate;
+import com.isode.stroke.tls.TLSContext;
+import com.isode.stroke.tls.TLSContextFactory;
+
+public class TLSLayer extends StreamLayer {
+
+ public TLSLayer(TLSContextFactory factory) {
+ context = factory.createTLSContext();
+ context.onDataForNetwork.connect(new Slot1<ByteArray>() {
+
+ public void call(ByteArray p1) {
+ writeDataToChildLayer(p1);
+ }
+ });
+ context.onDataForApplication.connect(new Slot1<ByteArray>() {
+
+ public void call(ByteArray p1) {
+ writeDataToParentLayer(p1);
+ }
+ });
+ context.onConnected.connect(onConnected);
+ context.onError.connect(onError);
+ }
+
+ public void connect() {
+ context.connect();
+ }
+
+ public void writeData(ByteArray data) {
+ context.handleDataFromApplication(data);
+ }
+
+ public void handleDataRead(ByteArray data) {
+ context.handleDataFromNetwork(data);
+ }
+
+ public boolean setClientCertificate(PKCS12Certificate certificate) {
+ return context.setClientCertificate(certificate);
+ }
+
+ public Certificate getPeerCertificate() {
+ return context.getPeerCertificate();
+ }
+
+ public CertificateVerificationError getPeerCertificateVerificationError() {
+ return context.getPeerCertificateVerificationError();
+ }
+
+ public TLSContext getContext() {
+ return context;
+ }
+
+ public final Signal onError = new Signal();
+ public final Signal onConnected = new Signal();
+
+ private final TLSContext context;
+}
diff --git a/src/com/isode/stroke/streamstack/WhitespacePingLayer.java b/src/com/isode/stroke/streamstack/WhitespacePingLayer.java
new file mode 100644
index 0000000..09d3af8
--- /dev/null
+++ b/src/com/isode/stroke/streamstack/WhitespacePingLayer.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2010 Remko Tron¨on
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+/*
+ * Copyright (c) 2011, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.streamstack;
+
+import com.isode.stroke.base.ByteArray;
+import com.isode.stroke.network.Timer;
+import com.isode.stroke.network.TimerFactory;
+import com.isode.stroke.signals.Slot;
+
+public class WhitespacePingLayer extends StreamLayer {
+
+ private static final int TIMEOUT_MILLISECONDS = 60000;
+
+ public WhitespacePingLayer(TimerFactory timerFactory) {
+ isActive = false;
+ timer = timerFactory.createTimer(TIMEOUT_MILLISECONDS);
+ timer.onTick.connect(new Slot() {
+ public void call() {
+ handleTimerTick();
+ }
+ });
+ }
+
+ public void writeData(ByteArray data) {
+ writeDataToChildLayer(data);
+ }
+
+ public void handleDataRead(ByteArray data) {
+ writeDataToParentLayer(data);
+ }
+
+ private void handleTimerTick() {
+ timer.stop();
+ writeDataToChildLayer(new ByteArray(" "));
+ timer.start();
+ }
+
+ public void setActive() {
+ isActive = true;
+ timer.start();
+ }
+
+ public void setInactive() {
+ timer.stop();
+ isActive = false;
+ }
+
+ public boolean getIsActive() {
+ return isActive;
+ }
+
+ private boolean isActive;
+ private Timer timer;
+}
diff --git a/src/com/isode/stroke/streamstack/XMPPLayer.java b/src/com/isode/stroke/streamstack/XMPPLayer.java
new file mode 100644
index 0000000..86c7b0e
--- /dev/null
+++ b/src/com/isode/stroke/streamstack/XMPPLayer.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2010 Remko Tron¨on
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+/*
+ * Copyright (c) 2010-2011, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.streamstack;
+
+import com.isode.stroke.base.ByteArray;
+import com.isode.stroke.elements.Element;
+import com.isode.stroke.elements.ProtocolHeader;
+import com.isode.stroke.elements.StreamType;
+import com.isode.stroke.eventloop.EventLoop;
+import com.isode.stroke.parser.PayloadParserFactoryCollection;
+import com.isode.stroke.parser.XMPPParser;
+import com.isode.stroke.parser.XMPPParserClient;
+import com.isode.stroke.serializer.PayloadSerializerCollection;
+import com.isode.stroke.serializer.XMPPSerializer;
+import com.isode.stroke.signals.Signal;
+import com.isode.stroke.signals.Signal1;
+
+/**
+ * This uses the inner StreamLayer to work around the HighLayer not having
+ * implementations because of the lack of multiple inheritance.
+ * Swiften doesn't require an eventLoop, Stroke does because of
+ * XML parsing being multi-threaded here.
+ */
+public class XMPPLayer implements HighLayer, XMPPParserClient {
+
+ public XMPPLayer(
+ PayloadParserFactoryCollection payloadParserFactories,
+ PayloadSerializerCollection payloadSerializers,
+ StreamType streamType,
+ EventLoop eventLoop) {
+ payloadParserFactories_ = payloadParserFactories;
+ payloadSerializers_ = payloadSerializers;
+ resetParserAfterParse_ = false;
+ eventLoop_ = eventLoop;
+ inParser_ = false;
+ xmppParser_ = new XMPPParser(this, payloadParserFactories_, eventLoop_);
+ xmppSerializer_ = new XMPPSerializer(payloadSerializers_, streamType);
+ }
+
+ public void writeHeader(ProtocolHeader header) {
+ writeDataInternal(new ByteArray(xmppSerializer_.serializeHeader(header)));
+ }
+
+ public void writeFooter() {
+ writeDataInternal(new ByteArray(xmppSerializer_.serializeFooter()));
+ }
+
+ public void writeElement(Element element) {
+ writeDataInternal(new ByteArray(xmppSerializer_.serializeElement(element)));
+ }
+
+ public void writeData(String data) {
+ writeDataInternal(new ByteArray(data));
+ }
+
+ public void resetParser() {
+ if (inParser_) {
+ resetParserAfterParse_ = true;
+ }
+ else {
+ doResetParser();
+ }
+ }
+
+ /**
+ * Should be protected, but can't because of interface implementation.
+ * @param data
+ */
+ public void handleDataRead(ByteArray data) {
+ handleDataReadInternal(data);
+ }
+
+ protected void writeDataInternal(ByteArray data) {
+ onWriteData.emit(data);
+ writeDataToChildLayer(data);
+ }
+
+ public final Signal1<ProtocolHeader> onStreamStart = new Signal1<ProtocolHeader>();
+ public final Signal1<Element> onElement = new Signal1<Element>();
+ public final Signal1<ByteArray> onWriteData = new Signal1<ByteArray>();
+ public final Signal1<ByteArray> onDataRead = new Signal1<ByteArray>();
+ public final Signal onError = new Signal();
+
+ public void handleStreamStart(ProtocolHeader header) {
+ onStreamStart.emit(header);
+ }
+
+ public void handleElement(Element element) {
+ onElement.emit(element);
+ }
+
+ public void handleStreamEnd() {
+ }
+
+ private void doResetParser() {
+ xmppParser_ = new XMPPParser(this, payloadParserFactories_, eventLoop_);
+ resetParserAfterParse_ = false;
+ }
+
+ private PayloadParserFactoryCollection payloadParserFactories_;
+ private XMPPParser xmppParser_;
+ private PayloadSerializerCollection payloadSerializers_;
+ private XMPPSerializer xmppSerializer_;
+ private boolean resetParserAfterParse_;
+ private boolean inParser_;
+ private EventLoop eventLoop_;
+
+ /* Multiple-inheritance workarounds */
+
+ private StreamLayer fakeStreamLayer_ = new StreamLayer() {
+ public void writeData(ByteArray data) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public void handleDataRead(ByteArray data) {
+ handleDataReadInternal(data);
+ }
+ };
+
+ private void handleDataReadInternal(ByteArray data) {
+ onDataRead.emit(data);
+ inParser_ = true;
+ if(!xmppParser_.parse(data.toString())) {
+ inParser_ = false;
+ onError.emit();
+ return;
+ }
+ inParser_ = false;
+ if (resetParserAfterParse_) {
+ doResetParser();
+ }
+ }
+
+ public LowLayer getChildLayer() {
+ return fakeStreamLayer_.getChildLayer();
+ }
+
+ public void setChildLayer(LowLayer childLayer) {
+ fakeStreamLayer_.setChildLayer(childLayer);
+ }
+
+ public void writeDataToChildLayer(ByteArray data) {
+ fakeStreamLayer_.writeDataToChildLayer(data);
+ }
+}