]> git.basschouten.com Git - openhab-addons.git/blob
967277e0f21fd90f2d567a5ae03709549f3b73cd
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.velux.internal.bridge.slip.io;
14
15 import java.io.DataInputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.Future;
23 import java.util.concurrent.RejectedExecutionException;
24 import java.util.concurrent.TimeUnit;
25 import java.util.concurrent.TimeoutException;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28
29 /**
30  * This is an extension of {@link java.io.DataInputStream}, which adds timeouts to receive operation.
31  * <P>
32  * A data input stream lets an application read primitive Java data
33  * types from an underlying input stream in a machine-independent
34  * way. An application uses a data output stream to write data that
35  * can later be read by a data input stream.
36  * <p>
37  * For an in-depth discussion, see:
38  * https://stackoverflow.com/questions/804951/is-it-possible-to-read-from-a-inputstream-with-a-timeout
39  *
40  * @author Guenther Schreiner - Initial contribution.
41  */
42 @NonNullByDefault
43 class DataInputStreamWithTimeout extends DataInputStream {
44
45     /*
46      * ***************************
47      * ***** Private Objects *****
48      */
49
50     /**
51      * Executor for asynchronous read command
52      */
53     ExecutorService executor = Executors.newFixedThreadPool(2);
54
55     /**
56      * Creates a DataInputStreamWithTimeout that uses the specified
57      * underlying DataInputStream.
58      *
59      * @param in the specified input stream
60      */
61     public DataInputStreamWithTimeout(InputStream in) {
62         super(in);
63     }
64
65     /**
66      * Reads up to <code>len</code> bytes of data from the contained
67      * input stream into an array of bytes. An attempt is made to read
68      * as many as <code>len</code> bytes, but a smaller number may be read,
69      * possibly zero. The number of bytes actually read is returned as an
70      * integer.
71      *
72      * <p>
73      * This method blocks until input data is available, end of file is
74      * detected, or an exception is thrown <B>until</B> the given timeout.
75      *
76      * <p>
77      * If <code>len</code> is zero, then no bytes are read and
78      * <code>0</code> is returned; otherwise, there is an attempt to read at
79      * least one byte. If no byte is available because the stream is at end of
80      * file, the value <code>-1</code> is returned; otherwise, at least one
81      * byte is read and stored into <code>b</code>.
82      *
83      * <p>
84      * The first byte read is stored into element <code>b[off]</code>, the
85      * next one into <code>b[off+1]</code>, and so on. The number of bytes read
86      * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
87      * bytes actually read; these bytes will be stored in elements
88      * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
89      * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
90      * <code>b[off+len-1]</code> unaffected.
91      *
92      * <p>
93      * In every case, elements <code>b[0]</code> through
94      * <code>b[off]</code> and elements <code>b[off+len]</code> through
95      * <code>b[b.length-1]</code> are unaffected.
96      *
97      * @param b the buffer into which the data is read.
98      * @param off the start offset in the destination array <code>b</code>
99      * @param len the maximum number of bytes read.
100      * @param timeoutMSecs the maximum duration of this read before throwing a TimeoutException.
101      * @return the total number of bytes read into the buffer, or
102      *         <code>-1</code> if there is no more data because the end
103      *         of the stream has been reached.
104      * @exception NullPointerException If <code>b</code> is <code>null</code>.
105      * @exception IndexOutOfBoundsException If <code>off</code> is negative,
106      *                <code>len</code> is negative, or <code>len</code> is greater than
107      *                <code>b.length - off</code>
108      * @exception IOException if the first byte cannot be read for any reason
109      *                other than end of file, the stream has been closed and the underlying
110      *                input stream does not support reading after close, or another I/O
111      *                error occurs. Additionally it will occur when the timeout happens.
112      * @see java.io.DataInputStream#read
113      */
114     public synchronized int read(byte b[], int off, int len, int timeoutMSecs) throws IOException {
115         // Definition of Method which encapsulates the Read of data
116         Callable<Integer> readTask = new Callable<Integer>() {
117             @Override
118             public Integer call() throws IOException {
119                 return in.read(b, off, len);
120             }
121         };
122         try {
123             Future<Integer> future = executor.submit(readTask);
124             return future.get(timeoutMSecs, TimeUnit.MILLISECONDS);
125         } catch (RejectedExecutionException e) {
126             throw new IOException("executor failed", e);
127         } catch (ExecutionException e) {
128             throw new IOException("execution failed", e);
129         } catch (InterruptedException e) {
130             throw new IOException("read interrupted", e);
131         } catch (TimeoutException e) {
132             throw new IOException("read timeout", e);
133         }
134     }
135 }