diff options
author | Kevin Smith <git@kismith.co.uk> | 2011-07-01 09:19:49 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2011-07-01 09:19:49 (GMT) |
commit | 2da71a8a85486a494343f1662d64fb5ae5a2a44e (patch) | |
tree | 23992f9f2a00bac23b345e5c2cc9c1194efc25be /src/com/isode/stroke/streamstack | |
download | stroke-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.java | 43 | ||||
-rw-r--r-- | src/com/isode/stroke/streamstack/ConnectionLayer.java | 58 | ||||
-rw-r--r-- | src/com/isode/stroke/streamstack/HighLayer.java | 31 | ||||
-rw-r--r-- | src/com/isode/stroke/streamstack/LowLayer.java | 30 | ||||
-rw-r--r-- | src/com/isode/stroke/streamstack/StreamLayer.java | 50 | ||||
-rw-r--r-- | src/com/isode/stroke/streamstack/StreamStack.java | 52 | ||||
-rw-r--r-- | src/com/isode/stroke/streamstack/TLSLayer.java | 73 | ||||
-rw-r--r-- | src/com/isode/stroke/streamstack/WhitespacePingLayer.java | 61 | ||||
-rw-r--r-- | src/com/isode/stroke/streamstack/XMPPLayer.java | 152 |
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); + } +} |