embulk-input-ftp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,267 @@
1
+ package org.embulk.input.ftp;
2
+
3
+ import java.util.concurrent.Future;
4
+ import java.util.concurrent.Callable;
5
+ import java.util.concurrent.CancellationException;
6
+ import java.util.concurrent.ExecutionException;
7
+ import java.util.concurrent.ExecutorService;
8
+ import java.io.IOException;
9
+ import java.io.EOFException;
10
+ import java.io.InterruptedIOException;
11
+ import java.nio.ByteBuffer;
12
+ import java.nio.channels.ReadableByteChannel;
13
+ import java.nio.channels.WritableByteChannel;
14
+ import com.google.common.base.Function;
15
+
16
+ public class BlockingTransfer
17
+ {
18
+ private final WriterChannel writerChannel;
19
+ private final ReaderChannel readerChannel;
20
+ private Future<?> transferCompletionFuture;
21
+
22
+ public static BlockingTransfer submit(ExecutorService executor,
23
+ Function<BlockingTransfer, Runnable> starterFactory)
24
+ {
25
+ BlockingTransfer transfer = new BlockingTransfer();
26
+ final Runnable starter = starterFactory.apply(transfer);
27
+ transfer.setTransferCompletionFuture(
28
+ executor.submit(new Callable<Void>() {
29
+ public Void call() throws Exception
30
+ {
31
+ starter.run();
32
+ return null;
33
+ }
34
+ })
35
+ );
36
+ return transfer;
37
+ }
38
+
39
+ private BlockingTransfer()
40
+ {
41
+ this.writerChannel = new WriterChannel();
42
+ this.readerChannel = new ReaderChannel();
43
+ }
44
+
45
+ private void setTransferCompletionFuture(Future<?> future)
46
+ {
47
+ this.transferCompletionFuture = future;
48
+ }
49
+
50
+ public ReadableByteChannel getReaderChannel()
51
+ {
52
+ return readerChannel;
53
+ }
54
+
55
+ public WritableByteChannel getWriterChannel()
56
+ {
57
+ return writerChannel;
58
+ }
59
+
60
+ public void transferFailed(Throwable exception)
61
+ {
62
+ readerChannel.overwriteException(exception);
63
+ }
64
+
65
+ void waitForTransferCompletion() throws IOException
66
+ {
67
+ Future<?> f = transferCompletionFuture;
68
+ if (f != null) {
69
+ try {
70
+ f.get();
71
+ } catch (CancellationException ex) {
72
+ throw new InterruptedIOException();
73
+ } catch (InterruptedException ex) {
74
+ throw new InterruptedIOException();
75
+ } catch (ExecutionException ex) {
76
+ // transfer failed
77
+ Throwable e = ex.getCause();
78
+ if (e instanceof IOException) {
79
+ throw (IOException) e;
80
+ } else if (e instanceof RuntimeException) {
81
+ throw (RuntimeException) e;
82
+ } else if (e instanceof Error) {
83
+ throw (Error) e;
84
+ } else {
85
+ throw new IOException(e);
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ public class WriterChannel implements WritableByteChannel
92
+ {
93
+ public int write(ByteBuffer src) throws IOException
94
+ {
95
+ int sz = src.remaining();
96
+ if (sz <= 0) {
97
+ return sz;
98
+ }
99
+
100
+ synchronized(readerChannel) {
101
+ if (!readerChannel.waitForWritable()) {
102
+ return -1;
103
+ }
104
+
105
+ readerChannel.setBuffer(src);
106
+
107
+ if (!readerChannel.waitForWritable()) { // wait for complete processing src
108
+ return -1;
109
+ }
110
+ }
111
+
112
+ return sz - src.remaining();
113
+ }
114
+
115
+ public boolean isOpen()
116
+ {
117
+ return readerChannel.isOpen();
118
+ }
119
+
120
+ public void close() throws IOException
121
+ {
122
+ readerChannel.closePeer();
123
+ waitForTransferCompletion();
124
+ }
125
+ }
126
+
127
+ private static int transferByteBuffer(ByteBuffer src, ByteBuffer dst)
128
+ {
129
+ int pos = dst.position();
130
+
131
+ int srcrem = src.remaining();
132
+ int dstrem = dst.remaining();
133
+ if (dstrem < srcrem) {
134
+ int lim = src.limit();
135
+ try {
136
+ src.limit(src.position() + dstrem);
137
+ dst.put(src);
138
+ } finally {
139
+ src.limit(lim);
140
+ }
141
+ } else {
142
+ dst.put(src);
143
+ }
144
+
145
+ return dst.position() - pos;
146
+ }
147
+
148
+ public class ReaderChannel implements ReadableByteChannel
149
+ {
150
+ private ByteBuffer buffer;
151
+ private Throwable exception;
152
+
153
+ public synchronized int read(ByteBuffer dst) throws IOException
154
+ {
155
+ if (!waitForReadable()) {
156
+ return -1;
157
+ }
158
+
159
+ int len = transferByteBuffer(buffer, dst);
160
+ if (!buffer.hasRemaining()) {
161
+ setBuffer(null);
162
+ notifyAll();
163
+ }
164
+
165
+ return len;
166
+ }
167
+
168
+ public synchronized boolean isOpen()
169
+ {
170
+ return exception == null;
171
+ }
172
+
173
+ public void close() throws IOException
174
+ {
175
+ setException(new EOFException("reader closed channel"));
176
+ }
177
+
178
+ private void setBuffer(ByteBuffer buffer)
179
+ {
180
+ this.buffer = buffer;
181
+ notifyAll();
182
+ }
183
+
184
+ private synchronized boolean waitForWritable() throws IOException
185
+ {
186
+ while (buffer != null) {
187
+ if (exception != null) {
188
+ if (exception instanceof EOFException) {
189
+ return false;
190
+ }
191
+ throwException();
192
+ }
193
+
194
+ try {
195
+ wait();
196
+ } catch (InterruptedException ex) {
197
+ // TODO throws ClosedByInterruptException or InterruptedIOException?
198
+ }
199
+ }
200
+
201
+ return true;
202
+ }
203
+
204
+ private boolean waitForReadable() throws IOException
205
+ {
206
+ while(buffer == null) {
207
+ if (exception != null) {
208
+ if (exception instanceof EOFException) {
209
+ return false;
210
+ }
211
+ throwException();
212
+ }
213
+
214
+ try {
215
+ wait();
216
+ } catch (InterruptedException ex) {
217
+ // TODO throws ClosedByInterruptException or InterruptedIOException?
218
+ }
219
+ }
220
+
221
+ return true;
222
+ }
223
+
224
+ public synchronized void closePeer() throws IOException
225
+ {
226
+ waitForWritable();
227
+ if( exception != null && !(exception instanceof EOFException)) {
228
+ throwException();
229
+ }
230
+ setException(new EOFException("writer closed channel"));
231
+ }
232
+
233
+ public synchronized void setException(Throwable exception)
234
+ {
235
+ if (this.exception == null) {
236
+ this.exception = exception;
237
+ }
238
+ notifyAll();
239
+ }
240
+
241
+ public synchronized void overwriteException(Throwable exception)
242
+ {
243
+ this.exception = exception;
244
+ notifyAll();
245
+ }
246
+
247
+ public boolean hasException()
248
+ {
249
+ return exception != null;
250
+ }
251
+
252
+ public void throwException() throws IOException
253
+ {
254
+ Throwable ex = exception;
255
+ if (ex instanceof IOException) {
256
+ throw (IOException) ex;
257
+ } else if (ex instanceof RuntimeException) {
258
+ throw (RuntimeException) ex;
259
+ } else if (ex instanceof Error) {
260
+ throw (Error) ex;
261
+ } else {
262
+ throw new IOException(ex);
263
+ }
264
+ }
265
+ }
266
+ }
267
+
@@ -0,0 +1,131 @@
1
+ // TODO copied from S3FileInputPlugin. This should be moved to org.embulk.
2
+ package org.embulk.input.ftp;
3
+
4
+ import java.util.concurrent.Callable;
5
+ import java.util.concurrent.ExecutionException;
6
+
7
+ public class RetryExecutor
8
+ {
9
+ public static RetryExecutor retryExecutor()
10
+ {
11
+ // TODO default configuration
12
+ return new RetryExecutor(3, 500, 30*60*1000);
13
+ }
14
+
15
+ public static class RetryGiveupException
16
+ extends ExecutionException
17
+ {
18
+ public RetryGiveupException(String message, Exception cause)
19
+ {
20
+ super(cause);
21
+ }
22
+
23
+ public RetryGiveupException(Exception cause)
24
+ {
25
+ super(cause);
26
+ }
27
+
28
+ public Exception getCause()
29
+ {
30
+ return (Exception) super.getCause();
31
+ }
32
+ }
33
+
34
+ public static interface Retryable<T>
35
+ extends Callable<T>
36
+ {
37
+ public T call()
38
+ throws Exception;
39
+
40
+ public boolean isRetryableException(Exception exception);
41
+
42
+ public void onRetry(Exception exception, int retryCount, int retryLimit, int retryWait)
43
+ throws RetryGiveupException;
44
+
45
+ public void onGiveup(Exception firstException, Exception lastException)
46
+ throws RetryGiveupException;
47
+ }
48
+
49
+ private final int retryLimit;
50
+ private final int initialRetryWait;
51
+ private final int maxRetryWait;
52
+
53
+ private RetryExecutor(int retryLimit, int initialRetryWait, int maxRetryWait)
54
+ {
55
+ this.retryLimit = retryLimit;
56
+ this.initialRetryWait = initialRetryWait;
57
+ this.maxRetryWait = maxRetryWait;
58
+ }
59
+
60
+ public RetryExecutor withRetryLimit(int count)
61
+ {
62
+ return new RetryExecutor(count, initialRetryWait, maxRetryWait);
63
+ }
64
+
65
+ public RetryExecutor withInitialRetryWait(int msec)
66
+ {
67
+ return new RetryExecutor(retryLimit, msec, maxRetryWait);
68
+ }
69
+
70
+ public RetryExecutor withMaxRetryWait(int msec)
71
+ {
72
+ return new RetryExecutor(retryLimit, initialRetryWait, msec);
73
+ }
74
+
75
+ public <T> T runInterruptible(Retryable<T> op)
76
+ throws InterruptedException, RetryGiveupException
77
+ {
78
+ return run(op, true);
79
+ }
80
+
81
+ public <T> T run(Retryable<T> op)
82
+ throws RetryGiveupException
83
+ {
84
+ try {
85
+ return run(op, false);
86
+ } catch (InterruptedException ex) {
87
+ throw new RetryGiveupException("Unexpected interruption", ex);
88
+ }
89
+ }
90
+
91
+ private <T> T run(Retryable<T> op, boolean interruptible)
92
+ throws InterruptedException, RetryGiveupException
93
+ {
94
+ int retryWait = initialRetryWait;
95
+ int retryCount = 0;
96
+
97
+ Exception firstException = null;
98
+
99
+ while(true) {
100
+ try {
101
+ return op.call();
102
+ } catch (Exception exception) {
103
+ if (firstException == null) {
104
+ firstException = exception;
105
+ }
106
+ if (!op.isRetryableException(exception) || retryCount >= retryLimit) {
107
+ op.onGiveup(firstException, exception);
108
+ throw new RetryGiveupException(firstException);
109
+ }
110
+
111
+ retryCount++;
112
+ op.onRetry(exception, retryCount, retryLimit, retryWait);
113
+
114
+ try {
115
+ Thread.sleep(retryWait);
116
+ } catch (InterruptedException ex) {
117
+ if (interruptible) {
118
+ throw ex;
119
+ }
120
+ }
121
+
122
+ // exponential back-off with hard limit
123
+ retryWait *= 2;
124
+ if (retryWait > maxRetryWait) {
125
+ retryWait = maxRetryWait;
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+
@@ -0,0 +1,129 @@
1
+ // TODO copied from S3FileInputPlugin. This should be moved to org.embulk.
2
+ package org.embulk.input.ftp;
3
+
4
+ import java.io.InputStream;
5
+ import java.io.IOException;
6
+
7
+ public class RetryableInputStream
8
+ extends InputStream
9
+ {
10
+ public interface Opener
11
+ {
12
+ public InputStream open(long offset, Exception exception) throws IOException;
13
+ }
14
+
15
+ private final Opener opener;
16
+ protected InputStream in;
17
+ private long offset;
18
+ private long markedOffset;
19
+
20
+ public RetryableInputStream(InputStream initialInputStream, Opener reopener)
21
+ {
22
+ this.opener = reopener;
23
+ this.in = initialInputStream;
24
+ this.offset = 0L;
25
+ this.markedOffset = 0L;
26
+ }
27
+
28
+ public RetryableInputStream(Opener opener) throws IOException
29
+ {
30
+ this(opener.open(0, null), opener);
31
+ }
32
+
33
+ private void reopen(Exception exception) throws IOException
34
+ {
35
+ if (in != null) {
36
+ in.close();
37
+ in = null;
38
+ }
39
+ in = opener.open(offset, exception);
40
+ }
41
+
42
+ @Override
43
+ public int read() throws IOException
44
+ {
45
+ while (true) {
46
+ try {
47
+ int v = in.read();
48
+ offset += 1;
49
+ return v;
50
+ } catch (IOException | RuntimeException ex) {
51
+ reopen(ex);
52
+ }
53
+ }
54
+ }
55
+
56
+ @Override
57
+ public int read(byte[] b) throws IOException
58
+ {
59
+ while (true) {
60
+ try {
61
+ int r = in.read(b);
62
+ offset += r;
63
+ return r;
64
+ } catch (IOException | RuntimeException ex) {
65
+ reopen(ex);
66
+ }
67
+ }
68
+ }
69
+
70
+ @Override
71
+ public int read(byte[] b, int off, int len) throws IOException
72
+ {
73
+ while (true) {
74
+ try {
75
+ int r = in.read(b, off, len);
76
+ offset += r;
77
+ return r;
78
+ } catch (IOException | RuntimeException ex) {
79
+ reopen(ex);
80
+ }
81
+ }
82
+ }
83
+
84
+ @Override
85
+ public long skip(long n) throws IOException
86
+ {
87
+ while (true) {
88
+ try {
89
+ long r = in.skip(n);
90
+ offset += r;
91
+ return r;
92
+ } catch (IOException | RuntimeException ex) {
93
+ reopen(ex);
94
+ }
95
+ }
96
+ }
97
+
98
+ @Override
99
+ public int available() throws IOException
100
+ {
101
+ return in.available();
102
+ }
103
+
104
+ @Override
105
+ public void close() throws IOException
106
+ {
107
+ in.close();
108
+ }
109
+
110
+ @Override
111
+ public void mark(int readlimit)
112
+ {
113
+ in.mark(readlimit);
114
+ markedOffset = offset;
115
+ }
116
+
117
+ @Override
118
+ public void reset() throws IOException
119
+ {
120
+ in.reset();
121
+ offset = markedOffset;
122
+ }
123
+
124
+ @Override
125
+ public boolean markSupported()
126
+ {
127
+ return in.markSupported();
128
+ }
129
+ }