From c9e6cd079fc49d9fd7dc10ff8955780849a16c5d Mon Sep 17 00:00:00 2001 From: BWS Systems Date: Tue, 6 Nov 2018 15:46:45 -0600 Subject: [PATCH] Update Harmonhy connection handling on disconnect. Add Route Parse --- pom.xml | 13 +- .../plugins/harmony/HarmonyHandler.java | 62 +++++- .../plugins/harmony/HarmonyServer.java | 2 +- .../bwssystems/HABridge/util/ParseRoute.java | 165 +++++++++++++++ .../bwssystems/HABridge/util/StringArray.java | 195 ++++++++++++++++++ .../bwssystems/HABridge/util/Tokenizer.java | 175 ++++++++++++++++ 6 files changed, 603 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/bwssystems/HABridge/util/ParseRoute.java create mode 100644 src/main/java/com/bwssystems/HABridge/util/StringArray.java create mode 100644 src/main/java/com/bwssystems/HABridge/util/Tokenizer.java 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