|
39 | 39 | import java.util.HashMap; |
40 | 40 | import java.util.List; |
41 | 41 | import java.util.Map; |
| 42 | +import java.util.concurrent.ExecutionException; |
| 43 | +import java.util.concurrent.ExecutorService; |
| 44 | +import java.util.concurrent.Executors; |
42 | 45 | import java.util.concurrent.TimeUnit; |
| 46 | +import java.util.concurrent.TimeoutException; |
| 47 | +import java.util.concurrent.atomic.AtomicReference; |
| 48 | + |
| 49 | +import static java.util.Optional.ofNullable; |
43 | 50 |
|
44 | 51 | /** |
45 | 52 | * A {@code NetconfSession} is obtained by first building a |
|
59 | 66 | public class NetconfSession { |
60 | 67 |
|
61 | 68 | private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NetconfSession.class); |
| 69 | + private final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); |
62 | 70 |
|
63 | 71 | private final Channel netconfChannel; |
64 | 72 | private String serverCapability; |
@@ -127,30 +135,49 @@ private void sendHello(String hello) throws IOException { |
127 | 135 | } |
128 | 136 |
|
129 | 137 | @VisibleForTesting |
130 | | - String getRpcReply(String rpc) throws IOException { |
| 138 | + String getRpcReply(final String rpc) throws IOException { |
131 | 139 | // write the rpc to the device |
132 | 140 | sendRpcRequest(rpc); |
133 | 141 |
|
134 | | - final char[] buffer = new char[BUFFER_SIZE]; |
135 | | - final StringBuilder rpcReply = new StringBuilder(); |
136 | | - final long startTime = System.nanoTime(); |
137 | | - final Reader in = new InputStreamReader(stdInStreamFromDevice, Charsets.UTF_8); |
138 | | - boolean timeoutNotExceeded = true; |
139 | | - int promptPosition; |
140 | | - while ((promptPosition = rpcReply.indexOf(NetconfConstants.DEVICE_PROMPT)) < 0 && |
141 | | - (timeoutNotExceeded = (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) < commandTimeout))) { |
142 | | - int charsRead = in.read(buffer, 0, buffer.length); |
143 | | - if (charsRead < 0) throw new NetconfException("Input Stream has been closed during reading."); |
144 | | - rpcReply.append(buffer, 0, charsRead); |
145 | | - } |
146 | | - |
147 | | - if (!timeoutNotExceeded) |
| 142 | + final AtomicReference<Thread> threadReference = new AtomicReference<>(); |
| 143 | + try { |
| 144 | + return singleThreadExecutor.submit(() -> { |
| 145 | + try { |
| 146 | + |
| 147 | + threadReference.set(Thread.currentThread()); |
| 148 | + final char[] buffer = new char[BUFFER_SIZE]; |
| 149 | + final StringBuilder rpcReply = new StringBuilder(); |
| 150 | + final Reader in = new InputStreamReader(stdInStreamFromDevice, Charsets.UTF_8); |
| 151 | + int promptPosition; |
| 152 | + while ((promptPosition = rpcReply.indexOf(NetconfConstants.DEVICE_PROMPT)) < 0) { |
| 153 | + int charsRead = in.read(buffer, 0, buffer.length); |
| 154 | + if (charsRead < 0) throw new NetconfException("Input Stream has been closed during reading."); |
| 155 | + rpcReply.append(buffer, 0, charsRead); |
| 156 | + } |
| 157 | + |
| 158 | + log.debug("Received Netconf RPC-Reply\n{}", rpcReply); |
| 159 | + rpcReply.setLength(promptPosition); |
| 160 | + return rpcReply.toString(); |
| 161 | + |
| 162 | + } catch (final Exception e) { |
| 163 | + log.warn("Error reading from input stream", e); |
| 164 | + throw e; |
| 165 | + } |
| 166 | + }) |
| 167 | + .get(commandTimeout, TimeUnit.MILLISECONDS); |
| 168 | + } catch (final InterruptedException e) { |
| 169 | + Thread.currentThread().interrupt(); |
| 170 | + throw new NetconfException("Thread interrupted whilst waiting for RPC reply", e); |
| 171 | + } catch (final ExecutionException e) { |
| 172 | + if(e.getCause() instanceof NetconfException) { |
| 173 | + throw (NetconfException) e.getCause(); |
| 174 | + } |
| 175 | + throw new NetconfException("Unexpected exception whilst waiting for RPC reply", e); |
| 176 | + } catch (final TimeoutException e) { |
| 177 | + // Make sure the thread isn't still running |
| 178 | + ofNullable(threadReference.get()).ifPresent(Thread::interrupt); |
148 | 179 | throw new SocketTimeoutException("Command timeout limit was exceeded: " + commandTimeout); |
149 | | - // fixing the rpc reply by removing device prompt |
150 | | - log.debug("Received Netconf RPC-Reply\n{}", rpcReply); |
151 | | - rpcReply.setLength(promptPosition); |
152 | | - |
153 | | - return rpcReply.toString(); |
| 180 | + } |
154 | 181 | } |
155 | 182 |
|
156 | 183 | private BufferedReader getRpcReplyRunning(String rpc) throws IOException { |
|
0 commit comments