diff options
| author | Alex Clayton <alex.clayton@isode.com> | 2016-03-16 13:48:37 (GMT) |
|---|---|---|
| committer | Alex Clayton <alex.clayton@isode.com> | 2016-03-16 14:05:38 (GMT) |
| commit | 8b9891afc85d114ff1e9c9a0291a4aaee8baeb09 (patch) | |
| tree | 5027dc69d6ca785e0ed94aebc7232b3790b51464 | |
| parent | 892af8539f2b46e840d7344489529259d1df03b9 (diff) | |
| download | stroke-8b9891afc85d114ff1e9c9a0291a4aaee8baeb09.zip stroke-8b9891afc85d114ff1e9c9a0291a4aaee8baeb09.tar.bz2 | |
Add FileWriteBytestream class and test.
Adds a FileWriteBytestream class plus a test for it. These had been
missed out previously. Also as per patch 'Fix crash when saving a
received file to non-writable location' changed
WriteBytestream.write() method to return a boolean indicating success
or failure.
Test-information: Tests pass ok.
Change-Id: I0c3676db8b67573142e8628f439cecf54f3f8f1a
7 files changed, 185 insertions, 19 deletions
diff --git a/src/com/isode/stroke/filetransfer/ByteArrayWriteBytestream.java b/src/com/isode/stroke/filetransfer/ByteArrayWriteBytestream.java index eb3a30f..d983e89 100644 --- a/src/com/isode/stroke/filetransfer/ByteArrayWriteBytestream.java +++ b/src/com/isode/stroke/filetransfer/ByteArrayWriteBytestream.java | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2010-2015 Isode Limited. | 2 | * Copyright (c) 2010-2016 Isode Limited. |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * See the COPYING file for more information. | 4 | * See the COPYING file for more information. |
| 5 | */ | 5 | */ |
| @@ -20,9 +20,11 @@ public class ByteArrayWriteBytestream extends WriteBytestream { | |||
| 20 | public ByteArrayWriteBytestream() { | 20 | public ByteArrayWriteBytestream() { |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | public void write(final ByteArray bytes) { | 23 | @Override |
| 24 | public boolean write(final ByteArray bytes) { | ||
| 24 | data.append(bytes); | 25 | data.append(bytes); |
| 25 | onWrite.emit(bytes); | 26 | onWrite.emit(bytes); |
| 27 | return true; | ||
| 26 | } | 28 | } |
| 27 | 29 | ||
| 28 | public ByteArray getData() { | 30 | public ByteArray getData() { |
diff --git a/src/com/isode/stroke/filetransfer/FileTransferError.java b/src/com/isode/stroke/filetransfer/FileTransferError.java index ac135d6..fbb5ec6 100644 --- a/src/com/isode/stroke/filetransfer/FileTransferError.java +++ b/src/com/isode/stroke/filetransfer/FileTransferError.java | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2010-2015 Isode Limited. | 2 | * Copyright (c) 2010-2016 Isode Limited. |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * See the COPYING file for more information. | 4 | * See the COPYING file for more information. |
| 5 | */ | 5 | */ |
| @@ -19,6 +19,7 @@ public class FileTransferError { | |||
| 19 | UnknownError, | 19 | UnknownError, |
| 20 | PeerError, | 20 | PeerError, |
| 21 | ReadError, | 21 | ReadError, |
| 22 | WriteError, | ||
| 22 | ClosedError | 23 | ClosedError |
| 23 | }; | 24 | }; |
| 24 | 25 | ||
diff --git a/src/com/isode/stroke/filetransfer/FileWriteBytestream.java b/src/com/isode/stroke/filetransfer/FileWriteBytestream.java new file mode 100644 index 0000000..7fa068d --- /dev/null +++ b/src/com/isode/stroke/filetransfer/FileWriteBytestream.java | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | /* Copyright (c) 2016, Isode Limited, London, England. | ||
| 2 | * All rights reserved. | ||
| 3 | * | ||
| 4 | * Acquisition and use of this software and related materials for any | ||
| 5 | * purpose requires a written license agreement from Isode Limited, | ||
| 6 | * or a written license from an organisation licensed by Isode Limited | ||
| 7 | * to grant such a license. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | package com.isode.stroke.filetransfer; | ||
| 11 | |||
| 12 | import java.io.File; | ||
| 13 | import java.io.FileNotFoundException; | ||
| 14 | import java.io.FileOutputStream; | ||
| 15 | import java.io.IOException; | ||
| 16 | |||
| 17 | import com.isode.stroke.base.ByteArray; | ||
| 18 | |||
| 19 | public class FileWriteBytestream extends WriteBytestream { | ||
| 20 | |||
| 21 | private final String filePath_; | ||
| 22 | |||
| 23 | private FileOutputStream stream_ = null; | ||
| 24 | |||
| 25 | public FileWriteBytestream(String filePath) { | ||
| 26 | filePath_ = filePath; | ||
| 27 | } | ||
| 28 | |||
| 29 | @Override | ||
| 30 | protected void finalize() throws Throwable { | ||
| 31 | try { | ||
| 32 | close(); | ||
| 33 | } | ||
| 34 | finally { | ||
| 35 | super.finalize(); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | @Override | ||
| 40 | public boolean write(ByteArray data) { | ||
| 41 | if (data.isEmpty()) { | ||
| 42 | return true; | ||
| 43 | } | ||
| 44 | if (stream_ == null) { | ||
| 45 | try { | ||
| 46 | stream_ = new FileOutputStream(filePath_); | ||
| 47 | } catch (FileNotFoundException e) { | ||
| 48 | return false; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | try { | ||
| 52 | stream_.write(data.getData()); | ||
| 53 | stream_.flush(); | ||
| 54 | } catch (IOException e) { | ||
| 55 | return false; | ||
| 56 | } | ||
| 57 | onWrite.emit(data); | ||
| 58 | return true; | ||
| 59 | } | ||
| 60 | |||
| 61 | public void close() { | ||
| 62 | if (stream_ != null) { | ||
| 63 | try { | ||
| 64 | stream_.close(); | ||
| 65 | } catch (IOException e) { | ||
| 66 | // Ignore exception | ||
| 67 | } | ||
| 68 | stream_ = null; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | |||
| 73 | } | ||
diff --git a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSession.java b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSession.java index 18e4484..982e3e9 100644 --- a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSession.java +++ b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamClientSession.java | |||
| @@ -116,7 +116,6 @@ public class SOCKS5BytestreamClientSession extends SOCKS5AbstractBytestreamSessi | |||
| 116 | state = State.Reading; | 116 | state = State.Reading; |
| 117 | writeBytestream = writeStream; | 117 | writeBytestream = writeStream; |
| 118 | writeBytestream.write(unprocessedData); | 118 | writeBytestream.write(unprocessedData); |
| 119 | //onBytesReceived(unprocessedData.size()); | ||
| 120 | unprocessedData.clear(); | 119 | unprocessedData.clear(); |
| 121 | } else { | 120 | } else { |
| 122 | logger_.fine("Session isn't ready for transfer yet!\n"); | 121 | logger_.fine("Session isn't ready for transfer yet!\n"); |
diff --git a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerSession.java b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerSession.java index 8facca0..f9c1f95 100644 --- a/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerSession.java +++ b/src/com/isode/stroke/filetransfer/SOCKS5BytestreamServerSession.java | |||
| @@ -82,7 +82,7 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess | |||
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | public void stop() { | 84 | public void stop() { |
| 85 | finish(false); | 85 | finish(); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | public void startSending(ReadBytestream stream) { | 88 | public void startSending(ReadBytestream stream) { |
| @@ -124,8 +124,12 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess | |||
| 124 | return streamID; | 124 | return streamID; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | private void finish(boolean error) { | 127 | private void finish() { |
| 128 | logger_.fine(error + " " + state + "\n"); | 128 | finish(null); |
| 129 | } | ||
| 130 | |||
| 131 | private void finish(FileTransferError error) { | ||
| 132 | logger_.fine("state: " + state + "\n"); | ||
| 129 | if (State.Finished.equals(state)) { | 133 | if (State.Finished.equals(state)) { |
| 130 | return; | 134 | return; |
| 131 | } | 135 | } |
| @@ -140,11 +144,7 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess | |||
| 140 | } | 144 | } |
| 141 | readBytestream = null; | 145 | readBytestream = null; |
| 142 | state = State.Finished; | 146 | state = State.Finished; |
| 143 | if (error) { | 147 | onFinished.emit(error); |
| 144 | onFinished.emit(new FileTransferError(FileTransferError.Type.PeerError)); | ||
| 145 | } else { | ||
| 146 | onFinished.emit(null); | ||
| 147 | } | ||
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | private void process() { | 150 | private void process() { |
| @@ -193,7 +193,7 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess | |||
| 193 | if (!hasBytestream) { | 193 | if (!hasBytestream) { |
| 194 | logger_.fine("Readstream or Wrtiestream with ID " + streamID + " not found!\n"); | 194 | logger_.fine("Readstream or Wrtiestream with ID " + streamID + " not found!\n"); |
| 195 | connection.write(result); | 195 | connection.write(result); |
| 196 | finish(true); | 196 | finish(new FileTransferError(FileTransferError.Type.PeerError)); |
| 197 | } | 197 | } |
| 198 | else { | 198 | else { |
| 199 | logger_.fine("Found stream. Sent OK.\n"); | 199 | logger_.fine("Found stream. Sent OK.\n"); |
| @@ -210,14 +210,15 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess | |||
| 210 | unprocessedData.append(data); | 210 | unprocessedData.append(data); |
| 211 | process(); | 211 | process(); |
| 212 | } else { | 212 | } else { |
| 213 | writeBytestream.write(new ByteArray(data)); | 213 | if (!writeBytestream.write(new ByteArray(data))) { |
| 214 | // onBytesReceived(data.size()); | 214 | finish(new FileTransferError(FileTransferError.Type.WriteError)); |
| 215 | } | ||
| 215 | } | 216 | } |
| 216 | } | 217 | } |
| 217 | 218 | ||
| 218 | private void handleDisconnected(final Connection.Error error) { | 219 | private void handleDisconnected(final Connection.Error error) { |
| 219 | logger_.fine((error != null ? (error.equals(Connection.Error.ReadError) ? "Read Error" : "Write Error") : "No Error") + "\n"); | 220 | logger_.fine((error != null ? (error.equals(Connection.Error.ReadError) ? "Read Error" : "Write Error") : "No Error") + "\n"); |
| 220 | finish(error != null ? true : false); | 221 | finish(error != null ? new FileTransferError(FileTransferError.Type.PeerError) : null); |
| 221 | } | 222 | } |
| 222 | 223 | ||
| 223 | private void handleDataAvailable() { | 224 | private void handleDataAvailable() { |
| @@ -244,7 +245,7 @@ public class SOCKS5BytestreamServerSession extends SOCKS5AbstractBytestreamSess | |||
| 244 | //} | 245 | //} |
| 245 | } | 246 | } |
| 246 | else { | 247 | else { |
| 247 | finish(false); | 248 | finish(); |
| 248 | } | 249 | } |
| 249 | } | 250 | } |
| 250 | } \ No newline at end of file | 251 | } \ No newline at end of file |
diff --git a/src/com/isode/stroke/filetransfer/WriteBytestream.java b/src/com/isode/stroke/filetransfer/WriteBytestream.java index c243bdc..81d2093 100644 --- a/src/com/isode/stroke/filetransfer/WriteBytestream.java +++ b/src/com/isode/stroke/filetransfer/WriteBytestream.java | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2010 Isode Limited. | 2 | * Copyright (c) 2010-2016 Isode Limited. |
| 3 | * All rights reserved. | 3 | * All rights reserved. |
| 4 | * See the COPYING file for more information. | 4 | * See the COPYING file for more information. |
| 5 | */ | 5 | */ |
| @@ -16,7 +16,14 @@ import com.isode.stroke.signals.Signal1; | |||
| 16 | 16 | ||
| 17 | public abstract class WriteBytestream { | 17 | public abstract class WriteBytestream { |
| 18 | 18 | ||
| 19 | public abstract void write(final ByteArray b); | 19 | /** |
| 20 | * Write data from a {@link ByteArray} to the bytestream. On | ||
| 21 | * success {@code true} is returned and {@link #onWrite} is called. | ||
| 22 | * On failure {@code false} is returned. | ||
| 23 | * @param b The {@link ByteArray} to write. | ||
| 24 | * @return {@code true} on success, {@code false} on failure. | ||
| 25 | */ | ||
| 26 | public abstract boolean write(final ByteArray b); | ||
| 20 | 27 | ||
| 21 | public final Signal1<ByteArray> onWrite = new Signal1<ByteArray>(); | 28 | public final Signal1<ByteArray> onWrite = new Signal1<ByteArray>(); |
| 22 | } \ No newline at end of file | 29 | } \ No newline at end of file |
diff --git a/test/com/isode/stroke/filetransfer/FileWriteBytestreamTest.java b/test/com/isode/stroke/filetransfer/FileWriteBytestreamTest.java new file mode 100644 index 0000000..3e06646 --- /dev/null +++ b/test/com/isode/stroke/filetransfer/FileWriteBytestreamTest.java | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | /* Copyright (c) 2016, Isode Limited, London, England. | ||
| 2 | * All rights reserved. | ||
| 3 | * | ||
| 4 | * Acquisition and use of this software and related materials for any | ||
| 5 | * purpose requires a written license agreement from Isode Limited, | ||
| 6 | * or a written license from an organisation licensed by Isode Limited | ||
| 7 | * to grant such a license. | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | package com.isode.stroke.filetransfer; | ||
| 11 | |||
| 12 | import static org.junit.Assert.assertFalse; | ||
| 13 | import static org.junit.Assert.assertTrue; | ||
| 14 | |||
| 15 | import java.io.File; | ||
| 16 | import java.io.IOException; | ||
| 17 | |||
| 18 | import org.junit.Test; | ||
| 19 | |||
| 20 | import com.isode.stroke.base.ByteArray; | ||
| 21 | import com.isode.stroke.signals.Slot1; | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Tests for {@link FileWriteBytestream} | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | public class FileWriteBytestreamTest { | ||
| 28 | |||
| 29 | private boolean onWriteWasCalled = false; | ||
| 30 | |||
| 31 | @Test | ||
| 32 | public void testSuccessfulWrite() { | ||
| 33 | File tempfile = null; | ||
| 34 | String filename = null; | ||
| 35 | try { | ||
| 36 | try { | ||
| 37 | tempfile = File.createTempFile("write_file_bytestream_test_", ".tmp"); | ||
| 38 | filename = tempfile.getAbsolutePath(); | ||
| 39 | } catch (IOException e) { | ||
| 40 | // Unable to create file exit test | ||
| 41 | return; | ||
| 42 | } | ||
| 43 | WriteBytestream writeBytestream = new FileWriteBytestream(filename); | ||
| 44 | writeBytestream.onWrite.connect(new Slot1<ByteArray>() { | ||
| 45 | |||
| 46 | @Override | ||
| 47 | public void call(ByteArray data) { | ||
| 48 | handleOnWrite(data); | ||
| 49 | } | ||
| 50 | |||
| 51 | }); | ||
| 52 | |||
| 53 | assertTrue(writeBytestream.write(new ByteArray("Some data."))); | ||
| 54 | assertTrue(onWriteWasCalled); | ||
| 55 | } | ||
| 56 | finally { | ||
| 57 | if (tempfile != null && tempfile.exists()) { | ||
| 58 | tempfile.delete(); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | @Test | ||
| 64 | public void testFailingWrite() { | ||
| 65 | WriteBytestream writeBytestream = new FileWriteBytestream(""); | ||
| 66 | writeBytestream.onWrite.connect(new Slot1<ByteArray>() { | ||
| 67 | |||
| 68 | @Override | ||
| 69 | public void call(ByteArray data) { | ||
| 70 | handleOnWrite(data); | ||
| 71 | } | ||
| 72 | |||
| 73 | }); | ||
| 74 | |||
| 75 | assertFalse(writeBytestream.write(new ByteArray("Some data."))); | ||
| 76 | assertFalse(onWriteWasCalled); | ||
| 77 | } | ||
| 78 | |||
| 79 | private void handleOnWrite(ByteArray data) { | ||
| 80 | onWriteWasCalled = true; | ||
| 81 | } | ||
| 82 | |||
| 83 | } | ||
Swift