diff --git a/pom.xml b/pom.xml
index 4368961..d778649 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.bwssystems.HABridge
ha-bridge
- 5.2.1a
+ 5.2.2b
jar
HA Bridge
@@ -63,7 +63,7 @@
com.sparkjava
spark-core
- 2.7.1
+ 2.7.2
slf4j-simple
@@ -120,6 +120,7 @@
junit
junit
4.12
+ test
com.github.bwssytems
@@ -156,6 +157,14 @@
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.1
+
+ true
+
+
org.apache.maven.plugins
maven-shade-plugin
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHandler.java
index 7a02339..6cfb3d3 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHandler.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHandler.java
@@ -9,6 +9,7 @@ import net.whistlingfish.harmony.HarmonyClient;
import net.whistlingfish.harmony.config.Activity;
import net.whistlingfish.harmony.config.Device;
import net.whistlingfish.harmony.config.HarmonyConfig;
+import com.bwssystems.HABridge.NamedIP;
public class HarmonyHandler {
private static final Logger log = LoggerFactory.getLogger(HarmonyHandler.class);
@@ -16,8 +17,9 @@ public class HarmonyHandler {
private Boolean noopCalls;
private Boolean devMode;
private DevModeResponse devResponse;
+ private NamedIP myNameAndIP;
- public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting, DevModeResponse devResponseSetting) {
+ public HarmonyHandler(HarmonyClient theClient, Boolean noopCallsSetting, DevModeResponse devResponseSetting, NamedIP aNameAndIP) {
super();
noopCalls = noopCallsSetting;
devMode = Boolean.TRUE;
@@ -27,6 +29,7 @@ public class HarmonyHandler {
else
devResponse = devResponseSetting;
harmonyClient = theClient;
+ myNameAndIP = aNameAndIP;
}
public List getActivities() {
@@ -34,7 +37,15 @@ public class HarmonyHandler {
if(devMode)
return devResponse.getActivities();
- return harmonyClient.getConfig().getActivities();
+ List listOfActivities = null;
+
+ try {
+ listOfActivities = harmonyClient.getConfig().getActivities();
+ } catch (RuntimeException e) {
+ handleExceptionError(e);
+ }
+
+ return listOfActivities;
}
public List getDevices() {
@@ -42,7 +53,14 @@ public class HarmonyHandler {
if(devMode)
return devResponse.getDevices();
- return harmonyClient.getConfig().getDevices();
+ List listOfDevices = null;
+
+ try {
+ listOfDevices = harmonyClient.getConfig().getDevices();
+ } catch (RuntimeException e) {
+ handleExceptionError(e);
+ }
+ return listOfDevices;
}
public HarmonyConfig getConfig() {
@@ -50,15 +68,27 @@ public class HarmonyHandler {
if(devMode)
return devResponse.getConfig();
- return harmonyClient.getConfig();
+ HarmonyConfig aConfig = null;
+ try {
+ aConfig = harmonyClient.getConfig();
+ } catch (RuntimeException e) {
+ handleExceptionError(e);
+ }
+ return aConfig;
}
public Activity getCurrentActivity() {
log.debug("Harmony api current sctivity requested.");
if(devMode)
return devResponse.getCurrentActivity();
-
- return harmonyClient.getCurrentActivity();
+
+ Activity anActivity = null;
+ try {
+ anActivity = harmonyClient.getCurrentActivity();
+ } catch (RuntimeException e) {
+ handleExceptionError(e);
+ }
+ return anActivity;
}
public Boolean startActivity(RunActivity anActivity) {
@@ -83,7 +113,11 @@ public class HarmonyHandler {
} catch (IllegalArgumentException ei) {
log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
return false;
+ } catch (RuntimeException e1) {
+ handleExceptionError(e1);
}
+ } catch (RuntimeException e1) {
+ handleExceptionError(e1);
}
} else {
log.error("Error in finding activity: " + anActivity.getName() + " for a hub: " + anActivity.getHub());
@@ -114,7 +148,11 @@ public class HarmonyHandler {
} catch (IllegalArgumentException ei) {
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub());
return false;
+ } catch (RuntimeException e1) {
+ handleExceptionError(e1);
}
+ } catch (RuntimeException e1) {
+ handleExceptionError(e1);
}
} else {
log.error("Error in finding device: " + aDeviceButton.getDevice() +" and a button: " + aDeviceButton.getButton() + " for a hub: " + aDeviceButton.getHub());
@@ -124,6 +162,18 @@ public class HarmonyHandler {
return true;
}
+ void handleExceptionError(Exception e) {
+ if(e.getMessage().equalsIgnoreCase("Failed communicating with Harmony Hub")) {
+ log.warn("Issue in communcicating with Harmony Hub, retrying connect....");
+ try {
+ harmonyClient.disconnect();
+ } catch(Exception e1) {
+ log.warn("Hub disconnect failed, continuing....");
+ }
+ harmonyClient.connect(myNameAndIP.getIp());
+ }
+ }
+
public void shutdown() {
log.debug("Harmony api shutdown requested.");
if(devMode)
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java
index 342a633..f7b7c9e 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java
@@ -110,7 +110,7 @@ public class HarmonyServer {
});
harmonyClient.connect(myNameAndIP.getIp());
}
- myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
+ myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse, myNameAndIP);
}
public HarmonyHandler getMyHarmony() {
diff --git a/src/main/java/com/bwssystems/HABridge/util/ParseRoute.java b/src/main/java/com/bwssystems/HABridge/util/ParseRoute.java
new file mode 100644
index 0000000..2c9424f
--- /dev/null
+++ b/src/main/java/com/bwssystems/HABridge/util/ParseRoute.java
@@ -0,0 +1,165 @@
+package com.bwssystems.HABridge.util;
+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Find out the local IP address and default gateway
+ * @author Henry Zheng
+ * @url http://www.ireasoning.com
+ */
+public class ParseRoute
+{
+ private String _gateway;
+ private String _ip;
+ private static ParseRoute _instance;
+
+ public static void main(String[] args)
+ {
+ try
+ {
+ ParseRoute pr = ParseRoute.getInstance();
+ System.out.println( "Gateway: " + pr.getGateway() );
+ System.out.println( "IP: " + pr.getLocalIPAddress() );
+ }
+ catch(Exception e)
+ {
+ System.out.println( e);
+ e.printStackTrace();
+ }
+ }
+
+ private ParseRoute ()
+ {
+ parse();
+ }
+
+ private static boolean isWindows ()
+ {
+ String os = System.getProperty ( "os.name" ).toUpperCase ();
+ return os.contains( "WINDOWS" ) ;
+ }
+
+ private static boolean isLinux ()
+ {
+ String os = System.getProperty ( "os.name" ).toUpperCase ();
+ return os.contains( "LINUX" ) ;
+ }
+
+ public String getLocalIPAddress()
+ {
+ return _ip;
+ }
+
+ public String getGateway()
+ {
+ return _gateway;
+ }
+
+ public static ParseRoute getInstance()
+ {
+ if(_instance == null)
+ {
+ _instance = new ParseRoute();
+ }
+ return _instance;
+ }
+
+ private void parse()
+ {
+ if(isWindows())
+ {
+ parseWindows();
+ }
+ else if(isLinux())
+ {
+ parseLinux();
+ }
+ }
+
+ private void parseWindows()
+ {
+ try
+ {
+ Process pro = Runtime.getRuntime().exec("cmd.exe /c route print");
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(pro.getInputStream()));
+
+ String line;
+ while((line = bufferedReader.readLine())!=null)
+ {
+ line = line.trim();
+ String [] tokens = Tokenizer.parse(line, ' ', true , true);// line.split(" ");
+ if(tokens.length == 5 && tokens[0].equals("0.0.0.0"))
+ {
+ _gateway = tokens[2];
+ _ip = tokens[3];
+ return;
+ }
+ }
+ //pro.waitFor();
+ }
+ catch(IOException e)
+ {
+ System.err.println(e);
+ e.printStackTrace();
+ }
+ }
+
+ private void parseLinux()
+ {
+ BufferedReader reader = null;
+ try
+ {
+ reader = new BufferedReader(new FileReader("/proc/net/route"));
+ String line;
+ while((line = reader.readLine())!=null)
+ {
+ line = line.trim();
+ String [] tokens = Tokenizer.parse(line, '\t', true , true);// line.split(" ");
+ if(tokens.length > 1 && tokens[1].equals("00000000"))
+ {
+ String gateway = tokens[2]; //0102A8C0
+ if(gateway.length() == 8)
+ {
+ String[] s4 = new String[4];
+ s4[3] = String.valueOf(Integer.parseInt(gateway.substring(0, 2), 16));
+ s4[2] = String.valueOf(Integer.parseInt(gateway.substring(2, 4), 16));
+ s4[1] = String.valueOf(Integer.parseInt(gateway.substring(4, 6), 16));
+ s4[0] = String.valueOf(Integer.parseInt(gateway.substring(6, 8), 16));
+ _gateway = s4[0] + "." + s4[1] + "." + s4[2] + "." + s4[3];
+ }
+ String iface = tokens[0];
+ NetworkInterface nif = NetworkInterface.getByName(iface);
+ Enumeration addrs = nif.getInetAddresses();
+ while(addrs.hasMoreElements())
+ {
+ Object obj = addrs.nextElement();
+ if(obj instanceof Inet4Address)
+ {
+ _ip = obj.toString();
+ if(_ip.startsWith("/")) _ip = _ip.substring(1);
+ reader.close();
+ return;
+ }
+ }
+ reader.close();
+ return;
+ }
+ }
+ }
+ catch(IOException e)
+ {
+ System.err.println(e);
+ e.printStackTrace();
+ }
+
+ if(reader != null) {
+ try {
+ reader.close();
+ } catch(Exception e) {
+
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/bwssystems/HABridge/util/StringArray.java b/src/main/java/com/bwssystems/HABridge/util/StringArray.java
new file mode 100644
index 0000000..344b384
--- /dev/null
+++ b/src/main/java/com/bwssystems/HABridge/util/StringArray.java
@@ -0,0 +1,195 @@
+package com.bwssystems.HABridge.util;
+
+import java.io.*;
+
+/**
+ * This class is an auto-resizable String array. It has similar methods to ArrayList
+ *
+ * @author Henry Zheng
+ * @url http://www.ireasoning.com
+ */
+
+public class StringArray implements Serializable
+{
+ public static final long serialVersionUID = 42L;
+ public static final int DEFAULT_CAPACITY = 10;
+
+ protected String[] _strings = null;
+ protected int _upperBound = 0;
+ protected int _capacity = DEFAULT_CAPACITY;
+ protected int _initialSize = _capacity;
+ protected float _loadFactory = 1.5F;
+
+ public StringArray ()
+ {
+ this(DEFAULT_CAPACITY);
+ }
+
+ public StringArray( int size)
+ {
+ _capacity = size;
+ _initialSize = size;
+ _strings = new String[size];
+ }
+
+ public synchronized void ensureCapacity(int capacity)
+ {
+ if(_capacity < capacity)
+ {
+ _capacity = (_capacity * 3)/2 + 1;
+ if(_capacity < capacity)
+ {
+ _capacity = capacity;
+ }
+ String [] oldData = _strings;
+ _strings = new String[_capacity];
+ System.arraycopy(oldData, 0, _strings, 0, _upperBound);
+ }
+ }
+
+
+ public synchronized void add(String s)
+ {
+ if(_upperBound == _capacity )
+ {
+ resize((int) (_capacity * _loadFactory));
+ }
+ _strings[_upperBound++] = s;
+ }
+
+ public synchronized void add(StringArray sa)
+ {
+ for (int i = 0; i < sa.size() ; i++)
+ {
+ add(sa.get(i));
+ }
+ }
+
+ public synchronized String get(int index)
+ {
+ return _strings[index];
+ }
+
+ public synchronized void set(int index, String newVal)
+ {
+ _strings[index] = newVal;
+ }
+
+ /** Adds all elements in passed string array */
+ public synchronized void add(String [] strs)
+ {
+ for (int i = 0; i < strs.length ; i++)
+ {
+ add(strs[i]);
+ }
+ }
+
+ /** Resets this object. */
+ public synchronized void clear()
+ {
+ _capacity = _initialSize;
+ _strings = new String[_capacity];
+ _upperBound = 0;
+
+ }
+
+ public synchronized String remove(int index)
+ {
+ if(index >= _upperBound )
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ String s = _strings[index];
+ for (int i = index; i < _upperBound - 1 ; i++)
+ {
+ _strings[i] = _strings[i + 1];
+ }
+ _upperBound --;
+ return s;
+ }
+
+ /**
+ * Removes the first occurance of passed str
+ * @return the string removed, or null if not found
+ */
+ public synchronized String remove(String str)
+ {
+ for (int i = 0; i < _upperBound ; i++)
+ {
+ if(_strings[i].equals(str))
+ {
+ return remove(i);
+ }
+ }
+ return null;
+ }
+
+ public synchronized int size()
+ {
+ return _upperBound;
+ }
+
+ public synchronized boolean isEmpty()
+ {
+ return _upperBound == 0;
+ }
+
+ public synchronized String[] toArray()
+ {
+ String [] ret = new String[_upperBound];
+ for (int i = 0; i < _upperBound ; i++)
+ {
+ ret[i] = _strings[i];
+ }
+ return ret;
+ }
+
+ protected synchronized void resize(int newCapacity)
+ {
+ String [] as = new String[newCapacity];
+ for (int i = 0; i < _strings.length ; i++)
+ {
+ as[i] = _strings[i];
+ }
+ _strings = as;
+ _capacity = newCapacity;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < _upperBound ; i++)
+ {
+ buf.append(_strings[i] + "\n");
+ }
+ return buf.toString();
+ }
+
+ public static void main(String[] args)
+ {
+ StringArray as = new StringArray();
+ String [] ss = null;
+ ss = as.toArray();
+ // System.out.println( "ss len="+ss.length);
+ // System.out.println( "ss = " + ss);
+ for (int i = 0; i < 10 ; i++)
+ {
+ as.add("" + i);
+ }
+ // System.out.println( "size = " + as.size());
+ ss = as.toArray();
+ for (int i = 0; i < ss.length ; i++)
+ {
+ // System.out.println( ss[i]);
+ }
+ // System.out.println( "remove 5th element.");
+ as.remove(5);
+
+ // System.out.println( "size = " + as.size());
+ ss = as.toArray();
+ for (int i = 0; i < ss.length ; i++)
+ {
+ // System.out.println( ss[i]);
+ }
+ }
+}//end of class StringArray
\ No newline at end of file
diff --git a/src/main/java/com/bwssystems/HABridge/util/Tokenizer.java b/src/main/java/com/bwssystems/HABridge/util/Tokenizer.java
new file mode 100644
index 0000000..21b3e14
--- /dev/null
+++ b/src/main/java/com/bwssystems/HABridge/util/Tokenizer.java
@@ -0,0 +1,175 @@
+package com.bwssystems.HABridge.util;
+
+
+/**
+ * This class perform similar functionality to StringTokenizer class but faster.
+ * The difference is StringTokenizer doesn't count empty token, but this class does.
+ *
+ * @author Henry Zheng
+ * @url http://www.ireasoning.com
+ */
+public class Tokenizer
+{
+ private Tokenizer()
+ {
+ }
+
+ /**
+ * It's different from the other parse method in that it checks left and right string first, which take higer
+ * priority than the delimiter. For example, if left and right is ", for string a:b:1"c:d"2:3 ,
+ * it returns { a, b, 1"c:d"2, 3 }
+ * @param left the openning tag of higher priority token
+ * @param right the closing tag of higher priority token
+ * @trimEachToken if true, each token will be trim by calling String.trim()
+ */
+ public static String[] parse(String text, char delimiter, boolean trimEachToken, String left, String right)
+ {
+ if(text == null) return null;
+ StringArray tokens = new StringArray();
+ int pos1 = -1;
+ int pos2 = -1;
+ int firstPos = -1;
+ while(true)
+ {
+ pos2 = text.indexOf(delimiter, firstPos + 1);
+ if(pos2 < 0 )
+ {
+ String str = text.substring(pos1 + 1);
+ if(trimEachToken )
+ {
+ str = str.trim();
+ }
+ tokens.add(str);
+ break;
+ }
+ if(pos2 == pos1 + 1)
+ {
+ tokens.add("");
+ }
+ else
+ {
+ int tagPos1 = text.indexOf(left, firstPos + 1);
+ if(tagPos1 > 0 && tagPos1 < pos2 )
+ {
+ int tagPos2 = text.indexOf(right, tagPos1 + 1);
+ if(tagPos2 > 0)
+ {
+ firstPos = tagPos2;
+ continue;
+ }
+ }
+ String str = text.substring(pos1 + 1, pos2);
+ if(trimEachToken )
+ {
+ str = str.trim();
+ }
+ tokens.add(str);
+ }
+ pos1 = pos2;
+ firstPos = pos1;
+ }
+ String[] ret = tokens.toArray();
+ return ret;
+ }
+
+ /**
+ * @trimEachToken if true, each token will be trim by calling String.trim()
+ */
+ public static String[] parse(String text, char delimiter, boolean trimEachToken)
+ {
+ return parse(text, delimiter, trimEachToken, false);
+ }
+
+ /**
+ * @trimEachToken if true, each token will be trim by calling String.trim()
+ */
+ public static String[] parse(String text, char delimiter, boolean trimEachToken, boolean ignoreEmptyToken)
+ {
+ if(text == null) return null;
+ StringArray tokens = new StringArray();
+ int pos1 = -1;
+ int pos2 = -1;
+ while(true)
+ {
+ pos2 = text.indexOf(delimiter, pos1 + 1);
+ if(pos2 < 0 )
+ {
+ String str = text.substring(pos1 + 1);
+ if(trimEachToken )
+ {
+ str = str.trim();
+ }
+ if(ignoreEmptyToken)
+ {
+ if(str.length() != 0) tokens.add(str);
+ }
+ else
+ {
+ tokens.add(str);
+ }
+ break;
+ }
+ if(pos2 == pos1 + 1)
+ {
+ if(!ignoreEmptyToken) { tokens.add(""); }
+ }
+ else
+ {
+ String str = text.substring(pos1 + 1, pos2);
+ if(trimEachToken )
+ {
+ str = str.trim();
+ }
+ if(ignoreEmptyToken)
+ {
+ if(str.length() != 0) tokens.add(str);
+ }
+ else
+ {
+ tokens.add(str);
+ }
+ }
+ pos1 = pos2;
+ }
+ String[] ret = tokens.toArray();
+ return ret;
+ }
+
+ /**
+ * Does not trim each token.
+ * @see #parse(String, char, boolean)
+ */
+ public static String[] parse(String text, char delimiter)
+ {
+ return parse(text, delimiter, false);
+ }
+
+// public static void main(String[] args)
+// {
+// String str = "1,\"2,\"ab\",ttt1,\"3,,a\"222\",4";
+// if(args.length > 0)
+// {
+// str = args[0];
+// }
+ // String [] tokens = Tokenizer.parse(str, ',');
+ //
+ //// System.out.println( "Text = (" + str + ")");
+ // // System.out.println( "------------------------------------------");
+ // for (int i = 0; i < tokens.length ; i++)
+ // {
+ // // System.out.println( "(" + tokens[i] + ")");
+ // }
+ // // System.out.println( "------------------------------------------");
+
+ // String [] tokens = Tokenizer.parse(str, ',', new String[]{"("}, new String[]{")"});
+ //
+ // // System.out.println( "Text = [" + str + "]");
+ // // System.out.println( "------------------------------------------");
+ // for (int i = 0; i < tokens.length ; i++)
+ // {
+ // // System.out.println( "[" + tokens[i] + "]");
+ // }
+ // // System.out.println( "------------------------------------------");
+
+ // }
+}//end of class Tokenizer
\ No newline at end of file