Some small cleanups and refactoring. Fixed minor potential concurrency issue

This commit is contained in:
GideonLeGrange 2014-09-08 13:10:18 +02:00
parent a111646c1f
commit 2e431894bf
6 changed files with 55 additions and 31 deletions

View File

@ -17,6 +17,7 @@ public abstract class ApiConnection {
* @param host The host to which to connect. * @param host The host to which to connect.
* @param port The TCP port to use. * @param port The TCP port to use.
* @return The ApiConnection * @return The ApiConnection
* @throws me.legrange.mikrotik.MikrotikApiException Thrown if there is a problem connecting
*/ */
public static ApiConnection connectTLS(String host, int port) throws MikrotikApiException { public static ApiConnection connectTLS(String host, int port) throws MikrotikApiException {
return ApiConnectionImpl.connect(host, port, true); return ApiConnectionImpl.connect(host, port, true);
@ -27,6 +28,7 @@ public abstract class ApiConnection {
* Create a new API connection to the give device on the default API port, using anonymous TLS for encryption. * Create a new API connection to the give device on the default API port, using anonymous TLS for encryption.
* @param host The host to which to connect. * @param host The host to which to connect.
* @return The ApiConnection * @return The ApiConnection
* @throws me.legrange.mikrotik.MikrotikApiException Thrown if there is a problem connecting
*/ */
public static ApiConnection connectTLS(String host) throws MikrotikApiException { public static ApiConnection connectTLS(String host) throws MikrotikApiException {
return ApiConnectionImpl.connect(host, DEFAULT_TLS_PORT, true); return ApiConnectionImpl.connect(host, DEFAULT_TLS_PORT, true);
@ -38,6 +40,7 @@ public abstract class ApiConnection {
* @param host The host to which to connect. * @param host The host to which to connect.
* @param port The TCP port to use. * @param port The TCP port to use.
* @return The ApiConnection * @return The ApiConnection
* @throws me.legrange.mikrotik.MikrotikApiException Thrown if there is a problem connecting
*/ */
public static ApiConnection connect(String host, int port) throws MikrotikApiException { public static ApiConnection connect(String host, int port) throws MikrotikApiException {
return ApiConnectionImpl.connect(host, port, false); return ApiConnectionImpl.connect(host, port, false);
@ -47,6 +50,7 @@ public abstract class ApiConnection {
* Create a new API connection to the give device on the default API port. * Create a new API connection to the give device on the default API port.
* @param host The host to which to connect. * @param host The host to which to connect.
* @return The ApiConnection * @return The ApiConnection
* @throws me.legrange.mikrotik.MikrotikApiException Thrown if there is a problem connecting
*/ */
public static ApiConnection connect(String host) throws MikrotikApiException { public static ApiConnection connect(String host) throws MikrotikApiException {
return connect(host, DEFAULT_PORT); return connect(host, DEFAULT_PORT);
@ -61,6 +65,7 @@ public abstract class ApiConnection {
/** /**
* Disconnect from the remote API * Disconnect from the remote API
* @throws me.legrange.mikrotik.MikrotikApiException Thrown if there is a problem disconnecting
*/ */
public abstract void disconnect() throws MikrotikApiException; public abstract void disconnect() throws MikrotikApiException;
@ -69,12 +74,15 @@ public abstract class ApiConnection {
* *
* @param username - username of the user on the router * @param username - username of the user on the router
* @param password - password for the user * @param password - password for the user
* @throws me.legrange.mikrotik.MikrotikApiException
* @throws java.lang.InterruptedException
*/ */
public abstract void login(String username, String password) throws MikrotikApiException, InterruptedException; public abstract void login(String username, String password) throws MikrotikApiException, InterruptedException;
/** execute a command and return a list of results. /** execute a command and return a list of results.
* @param cmd Command to execute * @param cmd Command to execute
* @return The list of results * @return The list of results
* @throws me.legrange.mikrotik.MikrotikApiException
*/ */
public abstract List<Map<String, String>> execute(String cmd) throws MikrotikApiException; public abstract List<Map<String, String>> execute(String cmd) throws MikrotikApiException;
@ -87,7 +95,9 @@ public abstract class ApiConnection {
*/ */
public abstract String execute(String cmd, ResultListener lis) throws MikrotikApiException; public abstract String execute(String cmd, ResultListener lis) throws MikrotikApiException;
/** cancel a command */ /** cancel a command
* @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; public abstract void cancel(String tag) throws MikrotikApiException;
/** default TCP port used by Mikrotik API */ /** default TCP port used by Mikrotik API */

View File

@ -9,7 +9,8 @@ import me.legrange.mikrotik.MikrotikApiException;
public class ApiCommandException extends MikrotikApiException { public class ApiCommandException extends MikrotikApiException {
/** return the tag associated with this exception, if there is one */ /** return the tag associated with this exception, if there is one
* @return the tag associated with this exception. Null if there is no tag*/
public String getTag() { public String getTag() {
return tag; return tag;
} }

View File

@ -1,6 +1,5 @@
package me.legrange.mikrotik.impl; package me.legrange.mikrotik.impl;
import me.legrange.mikrotik.*;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
@ -9,14 +8,17 @@ import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
//import org.bouncycastle.jce.provider.BouncyCastleProvider; import me.legrange.mikrotik.ApiConnection;
import me.legrange.mikrotik.ApiConnectionException;
import me.legrange.mikrotik.MikrotikApiException;
import me.legrange.mikrotik.ResultListener;
/** /**
* The Mikrotik API connection implementation. This is the class used to connect * The Mikrotik API connection implementation. This is the class used to connect
@ -77,12 +79,15 @@ public final class ApiConnectionImpl extends ApiConnection {
* *
* @param username - username of the user on the router * @param username - username of the user on the router
* @param password - password for the user * @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 { public void login(String username, String password) throws MikrotikApiException, InterruptedException {
List<Map<String, String>> list = execute("/login"); List<Map<String, String>> list = execute("/login");
Map<String, String> res = list.get(0); Map<String, String> res = list.get(0);
String hash = res.get("ret"); String hash = res.get("ret");
String chal = Util.hexStrToStr("00") + new String(makePass(password)) + Util.hexStrToStr(hash); String chal = Util.hexStrToStr("00") + new String(password.toCharArray()) + Util.hexStrToStr(hash);
chal = Util.hashMD5(chal); chal = Util.hashMD5(chal);
execute("/login name=" + username + " response=00" + chal); execute("/login name=" + username + " response=00" + chal);
} }
@ -92,7 +97,9 @@ public final class ApiConnectionImpl extends ApiConnection {
* *
* @param cmd Command to execute * @param cmd Command to execute
* @return The list of results * @return The list of results
* @throws me.legrange.mikrotik.MikrotikApiException
*/ */
@Override
public List<Map<String, String>> execute(String cmd) throws MikrotikApiException { public List<Map<String, String>> execute(String cmd) throws MikrotikApiException {
return execute(Parser.parse(cmd)); return execute(Parser.parse(cmd));
} }
@ -105,13 +112,17 @@ public final class ApiConnectionImpl extends ApiConnection {
* @return A command object that can be used to cancel the command. * @return A command object that can be used to cancel the command.
* @throws MikrotikApiException * @throws MikrotikApiException
*/ */
@Override
public String execute(String cmd, ResultListener lis) throws MikrotikApiException { public String execute(String cmd, ResultListener lis) throws MikrotikApiException {
return execute(Parser.parse(cmd), lis); return execute(Parser.parse(cmd), lis);
} }
/** /**
* cancel a command * 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 { public void cancel(String tag) throws MikrotikApiException {
execute(String.format("/cancel tag=%s", tag)); execute(String.format("/cancel tag=%s", tag));
} }
@ -137,6 +148,7 @@ public final class ApiConnectionImpl extends ApiConnection {
} }
private ApiConnectionImpl() { private ApiConnectionImpl() {
this.listeners = new ConcurrentHashMap<>();
} }
/** /**
@ -180,7 +192,7 @@ public final class ApiConnectionImpl extends ApiConnection {
*/ */
private Socket openSSLSocket(InetAddress ia, int port) throws IOException { private Socket openSSLSocket(InetAddress ia, int port) throws IOException {
SSLSocket ssl = (SSLSocket) SSLSocketFactory.getDefault().createSocket(ia, port); SSLSocket ssl = (SSLSocket) SSLSocketFactory.getDefault().createSocket(ia, port);
List<String> cs = new LinkedList<String>(); List<String> cs = new LinkedList<>();
// not happy with this code. Without it, SSL throws a "Remote host closed connection during handshake" error // not happy with this code. Without it, SSL throws a "Remote host closed connection during handshake" error
// caused by a "SSL peer shut down incorrectly" error // caused by a "SSL peer shut down incorrectly" error
for (String s : ssl.getSupportedCipherSuites()) { for (String s : ssl.getSupportedCipherSuites()) {
@ -192,16 +204,6 @@ public final class ApiConnectionImpl extends ApiConnection {
return ssl; return ssl;
} }
private char[] makePass(String pass) {
if (true) {
return pass.toCharArray();
}
char[] res = new char[pass.length() + 1];
System.arraycopy(pass.toCharArray(), 0, res, 0, pass.length());
res[pass.length()] = 0x0;
return res;
}
private synchronized String nextTag() { private synchronized String nextTag() {
_tag++; _tag++;
return Integer.toHexString(_tag); return Integer.toHexString(_tag);
@ -213,7 +215,7 @@ public final class ApiConnectionImpl extends ApiConnection {
private boolean connected = false; private boolean connected = false;
private Reader reader; private Reader reader;
private Processor processor; private Processor processor;
private final Map<String, ResultListener> listeners = new HashMap<String, ResultListener>(); private final Map<String, ResultListener> listeners;
private Integer _tag = 0; private Integer _tag = 0;
/** /**
@ -253,12 +255,11 @@ public final class ApiConnectionImpl extends ApiConnection {
queue.put(ex); queue.put(ex);
} catch (InterruptedException ex2) { } catch (InterruptedException ex2) {
} }
} catch (ApiConnectionException ex) { } catch (ApiConnectionException | InterruptedException ex) {
} catch (InterruptedException ex1) {
} }
} }
} }
private LinkedBlockingQueue queue = new LinkedBlockingQueue(40); private final LinkedBlockingQueue queue = new LinkedBlockingQueue(40);
} }
/** /**
@ -280,7 +281,6 @@ public final class ApiConnectionImpl extends ApiConnection {
continue; continue;
} }
} catch (MikrotikApiException ex) { } catch (MikrotikApiException ex) {
ex.printStackTrace();
continue; continue;
} }
ResultListener l = listeners.get(res.getTag()); ResultListener l = listeners.get(res.getTag());
@ -443,17 +443,19 @@ public final class ApiConnectionImpl extends ApiConnection {
} }
} }
} }
private List<String> lines = new LinkedList<String>(); private final List<String> lines = new LinkedList<>();
private String line; private String line;
} }
private class SyncListener implements ResultListener { private class SyncListener implements ResultListener {
@Override
public synchronized void error(MikrotikApiException ex) { public synchronized void error(MikrotikApiException ex) {
this.err = ex; this.err = ex;
notify(); notify();
} }
@Override
public synchronized void completed() { public synchronized void completed() {
notify(); notify();
} }
@ -467,6 +469,7 @@ public final class ApiConnectionImpl extends ApiConnection {
notify(); notify();
} }
@Override
public void receive(Map<String, String> result) { public void receive(Map<String, String> result) {
results.add(result); results.add(result);
} }
@ -486,7 +489,7 @@ public final class ApiConnectionImpl extends ApiConnection {
} }
return results; return results;
} }
private List<Map<String, String>> results = new LinkedList<Map<String, String>>(); private final List<Map<String, String>> results = new LinkedList<>();
private MikrotikApiException err; private MikrotikApiException err;
} }
} }

View File

@ -73,9 +73,9 @@ class Command {
List<Parameter> getParameters() { List<Parameter> getParameters() {
return params; return params;
} }
private String cmd; private final String cmd;
private List<Parameter> params = new LinkedList<Parameter>(); private final List<Parameter> params = new LinkedList<>();
private List<String> queries = new LinkedList<String>(); private final List<String> queries = new LinkedList<>();
private List<String> properties = new LinkedList<String>(); private final List<String> properties = new LinkedList<>();
private String tag; private String tag;
} }

View File

@ -15,6 +15,7 @@ class Result extends Response implements Map<String, String> {
return map.get(key); return map.get(key);
} }
@Override
public boolean isEmpty() { public boolean isEmpty() {
return map.isEmpty(); return map.isEmpty();
} }
@ -24,53 +25,64 @@ class Result extends Response implements Map<String, String> {
return String.format("tag=%s, data=%s", getTag(), map); return String.format("tag=%s, data=%s", getTag(), map);
} }
@Override
public int size() { public int size() {
return map.size(); return map.size();
} }
@Override
public boolean containsKey(Object o) { public boolean containsKey(Object o) {
return map.containsKey(o); return map.containsKey(o);
} }
@Override
public boolean containsValue(Object o) { public boolean containsValue(Object o) {
return map.containsValue(o); return map.containsValue(o);
} }
@Override
public String get(Object o) { public String get(Object o) {
return map.get(o); return map.get(o);
} }
@Override
public String put(String k, String v) { public String put(String k, String v) {
return map.put(k, v); return map.put(k, v);
} }
@Override
public String remove(Object o) { public String remove(Object o) {
return map.remove(o); return map.remove(o);
} }
@Override
public void putAll(Map<? extends String, ? extends String> map) { public void putAll(Map<? extends String, ? extends String> map) {
this.map.putAll(map); this.map.putAll(map);
} }
@Override
public void clear() { public void clear() {
map.clear(); map.clear();
} }
@Override
public Set<String> keySet() { public Set<String> keySet() {
return map.keySet(); return map.keySet();
} }
@Override
public Collection<String> values() { public Collection<String> values() {
return map.values(); return map.values();
} }
@Override
public Set<Entry<String, String>> entrySet() { public Set<Entry<String, String>> entrySet() {
return map.entrySet(); return map.entrySet();
} }
Result() { Result() {
super(null); super(null);
this.map = new HashMap<String, String>(); this.map = new HashMap<>();
} }
private final Map<String, String> map; private final Map<String, String> map;

View File

@ -1,7 +1,5 @@
package me.legrange.mikrotik.impl; package me.legrange.mikrotik.impl;
import me.legrange.mikrotik.MikrotikApiException;
/** /**
* Exception thrown if the scanner encounters an error while scanning a command line. * Exception thrown if the scanner encounters an error while scanning a command line.
* @author GideonLeGrange * @author GideonLeGrange