From c297aba43e0e5484c6ed6000ccb68ea9eae7df5e Mon Sep 17 00:00:00 2001 From: Gideon le Grange Date: Sun, 29 Mar 2015 22:34:42 +0200 Subject: [PATCH] Added command timeouts as requested in #16 --- src/main/java/examples/Config.java | 6 +- src/main/java/examples/Example.java | 2 +- src/main/java/examples/Example2.java | 1 + .../me/legrange/mikrotik/ApiConnection.java | 17 +++- .../mikrotik/impl/ApiConnectionImpl.java | 80 ++++++++----------- 5 files changed, 54 insertions(+), 52 deletions(-) diff --git a/src/main/java/examples/Config.java b/src/main/java/examples/Config.java index 020c596..57c81aa 100644 --- a/src/main/java/examples/Config.java +++ b/src/main/java/examples/Config.java @@ -7,9 +7,9 @@ package examples; public class Config { - public static final String HOST = "192.168.1.1"; - public static final String USERNAME = "admin"; - public static final String PASSWORD = ""; + public static final String HOST = "192.168.1.34"; + public static final String USERNAME = "gideon"; + public static final String PASSWORD = "minapp"; } diff --git a/src/main/java/examples/Example.java b/src/main/java/examples/Example.java index 33dea60..ff25eae 100644 --- a/src/main/java/examples/Example.java +++ b/src/main/java/examples/Example.java @@ -9,7 +9,7 @@ import me.legrange.mikrotik.ApiConnection; abstract class Example { protected void connect() throws Exception { - con = ApiConnection.connect(Config.HOST); + con = ApiConnection.connect(Config.HOST, ApiConnection.DEFAULT_PORT, 2000); con.login(Config.USERNAME, Config.PASSWORD); } diff --git a/src/main/java/examples/Example2.java b/src/main/java/examples/Example2.java index 5391d56..95f63a8 100644 --- a/src/main/java/examples/Example2.java +++ b/src/main/java/examples/Example2.java @@ -19,6 +19,7 @@ public class Example2 extends Example { } private void test() throws MikrotikApiException { + con.setTimeout(50); List> results = con.execute("/interface/print"); for (Map result : results) { System.out.println(result); diff --git a/src/main/java/me/legrange/mikrotik/ApiConnection.java b/src/main/java/me/legrange/mikrotik/ApiConnection.java index 1a11807..b9b6b1e 100644 --- a/src/main/java/me/legrange/mikrotik/ApiConnection.java +++ b/src/main/java/me/legrange/mikrotik/ApiConnection.java @@ -18,7 +18,9 @@ public abstract class ApiConnection { public static final int DEFAULT_TLS_PORT = 8729; /** default connection timeout to use when opening the connection */ public static final int DEFAULT_CONNECTION_TIMEOUT = 60000; - + /** default command timeout used for synchronous commands */ + public static final int DEFAULT_COMMAND_TIMEOUT = 60000; + /** * Create a new API connection to the give device on the supplied port, using anonymous TLS for encryption. * @param host The host to which to connect. @@ -130,5 +132,18 @@ public abstract class ApiConnection { * @param tag The tag of the command to cancel * @throws me.legrange.mikrotik.MikrotikApiException Thrown if there is a problem canceling the command */ public abstract void cancel(String tag) throws MikrotikApiException; + + /** get the command timeout. The command timeout is used to time out API + * commands after a specific time. + * @return The time out in milliseconds. + */ + public abstract int getTimeout(); + + /** set the command timeout. The command timeout is used to time out API + * commands after a specific time. + * @param timeout The time out in milliseconds. + * @throws MikrotikApiException Thrown if the timeout specified is invalid. + */ + public abstract void setTimeout(int timeout) throws MikrotikApiException; } \ No newline at end of file diff --git a/src/main/java/me/legrange/mikrotik/impl/ApiConnectionImpl.java b/src/main/java/me/legrange/mikrotik/impl/ApiConnectionImpl.java index b6dff4f..699a209 100644 --- a/src/main/java/me/legrange/mikrotik/impl/ApiConnectionImpl.java +++ b/src/main/java/me/legrange/mikrotik/impl/ApiConnectionImpl.java @@ -36,6 +36,7 @@ public final class ApiConnectionImpl extends ApiConnection { * @param host The host to which to connect. * @param port The TCP port to use. * @param secure Is TLS required + * @param timeOut The connection timeout * @return The ApiConnection * @throws me.legrange.mikrotik.ApiConnectionException Thrown if there is a * problem connecting @@ -46,22 +47,11 @@ public final class ApiConnectionImpl extends ApiConnection { return con; } - /** - * Check the state of connection. - * - * @return if connection is established to router it returns true. - */ @Override public boolean isConnected() { return connected; } - /** - * Disconnect from the remote API - * - * @throws me.legrange.mikrotik.ApiConnectionException Thrown if there is a - * problem disconnecting - */ @Override public void disconnect() throws ApiConnectionException { if (!connected) { @@ -77,14 +67,6 @@ public final class ApiConnectionImpl extends ApiConnection { } } - /** - * Log in to the remote router. - * - * @param username - username of the user on the router - * @param password - password for the user - * @throws me.legrange.mikrotik.MikrotikApiException - * @throws java.lang.InterruptedException - */ @Override public void login(String username, String password) throws MikrotikApiException, InterruptedException { if (username.trim().isEmpty()) { @@ -98,47 +80,40 @@ public final class ApiConnectionImpl extends ApiConnection { execute("/login name=" + username + " response=00" + chal); } - /** - * execute a command and return a list of results. - * - * @param cmd Command to execute - * @return The list of results - * @throws me.legrange.mikrotik.MikrotikApiException - */ @Override public List> execute(String cmd) throws MikrotikApiException { - return execute(Parser.parse(cmd)); + return execute(Parser.parse(cmd), timeOut); } - /** - * execute a command and attach a result listener to receive it's results. - * - * @param cmd Command to execute - * @param lis ResultListener that will receive the results - * @return A command object that can be used to cancel the command. - * @throws MikrotikApiException - */ @Override public String execute(String cmd, ResultListener lis) throws MikrotikApiException { return execute(Parser.parse(cmd), lis); } - /** - * cancel a command - * - * @param tag - * @throws me.legrange.mikrotik.MikrotikApiException Thrown if an error is - * experienced while canceling the - */ @Override public void cancel(String tag) throws MikrotikApiException { execute(String.format("/cancel tag=%s", tag)); } - private List> execute(Command cmd) throws MikrotikApiException { + @Override + public int getTimeout() { + return timeOut; + } + + @Override + public void setTimeout(int timeout) throws MikrotikApiException { + if (timeout >=0) { + timeOut = timeout; + } + else { + throw new MikrotikApiException(String.format("Invalid timeout value '%d'; must be postive or 0", timeout)); + } + } + + private List> execute(Command cmd, int timeOut) throws MikrotikApiException { SyncListener l = new SyncListener(); execute(cmd, l); - return l.getResults(); + return l.getResults(timeOut); } private String execute(Command cmd, ResultListener lis) throws MikrotikApiException { @@ -226,6 +201,7 @@ public final class ApiConnectionImpl extends ApiConnection { private Processor processor; private final Map listeners; private Integer _tag = 0; + private int timeOut = ApiConnection.DEFAULT_COMMAND_TIMEOUT; /** * thread to read data from the socket and process it into Strings @@ -483,6 +459,7 @@ public final class ApiConnectionImpl extends ApiConnection { @Override public synchronized void completed() { + complete = true; notify(); } @@ -492,6 +469,7 @@ public final class ApiConnectionImpl extends ApiConnection { res.put("ret", done.getHash()); results.add(res); } + complete = true; notify(); } @@ -500,11 +478,17 @@ public final class ApiConnectionImpl extends ApiConnection { results.add(result); } - private List> getResults() throws MikrotikApiException { + private List> getResults(int timeOut) throws MikrotikApiException { try { synchronized (this) { // don't wait if we already have a result. - if ((err == null) && results.isEmpty()) { - wait(); + int waitTime = timeOut; + while (!complete && (waitTime > 0)) { + long start = System.currentTimeMillis(); + wait(waitTime); + waitTime = waitTime - (int)(System.currentTimeMillis() - start); + if ((waitTime < 0) && !complete) { + err = new ApiConnectionException(String.format("Command timed out after %d ms", timeOut)); + } } } } catch (InterruptedException ex) { @@ -515,7 +499,9 @@ public final class ApiConnectionImpl extends ApiConnection { } return results; } + private final List> results = new LinkedList<>(); private MikrotikApiException err; + private boolean complete = false; } }