commit
a1ee3cf1b5
15 changed files with 2421 additions and 0 deletions
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<classpath> |
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> |
||||
<classpathentry kind="src" path="src"/> |
||||
<classpathentry kind="lib" path="lib/commons-lang3-3.9.jar"/> |
||||
<classpathentry kind="lib" path="lib/mariadb-java-client-2.4.4.jar"/> |
||||
<classpathentry kind="lib" path="C:/Users/Jens/Documents/Entwicklung/Eclipse workspace/libs/mailapi-1.5.0.jar"/> |
||||
<classpathentry kind="lib" path="C:/Users/Jens/Documents/Entwicklung/Eclipse workspace/libs/smtp-1.5.0.jar"/> |
||||
<classpathentry kind="lib" path="C:/Users/Jens/Documents/Entwicklung/Eclipse workspace/libs/activation-1.1.1.wso2v2.jar"/> |
||||
<classpathentry kind="output" path="bin"/> |
||||
</classpath> |
@ -0,0 +1,74 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/eclipse |
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=eclipse |
||||
|
||||
### Eclipse ### |
||||
.metadata |
||||
bin/ |
||||
tmp/ |
||||
*.tmp |
||||
*.bak |
||||
*.swp |
||||
*~.nib |
||||
local.properties |
||||
.settings/ |
||||
.loadpath |
||||
.recommenders |
||||
|
||||
# External tool builders |
||||
.externalToolBuilders/ |
||||
|
||||
# Locally stored "Eclipse launch configurations" |
||||
*.launch |
||||
|
||||
# PyDev specific (Python IDE for Eclipse) |
||||
*.pydevproject |
||||
|
||||
# CDT-specific (C/C++ Development Tooling) |
||||
.cproject |
||||
|
||||
# CDT- autotools |
||||
.autotools |
||||
|
||||
# Java annotation processor (APT) |
||||
.factorypath |
||||
|
||||
# PDT-specific (PHP Development Tools) |
||||
.buildpath |
||||
|
||||
# sbteclipse plugin |
||||
.target |
||||
|
||||
# Tern plugin |
||||
.tern-project |
||||
|
||||
# TeXlipse plugin |
||||
.texlipse |
||||
|
||||
# STS (Spring Tool Suite) |
||||
.springBeans |
||||
|
||||
# Code Recommenders |
||||
.recommenders/ |
||||
|
||||
# Annotation Processing |
||||
.apt_generated/ |
||||
.apt_generated_test/ |
||||
|
||||
# Scala IDE specific (Scala & Java development for Eclipse) |
||||
.cache-main |
||||
.scala_dependencies |
||||
.worksheet |
||||
|
||||
# Uncomment this line if you wish to ignore the project description file. |
||||
# Typically, this file would be tracked if it contains build/dependency configurations: |
||||
#.project |
||||
|
||||
### Eclipse Patch ### |
||||
# Spring Boot Tooling |
||||
.sts4-cache/ |
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/eclipse |
||||
|
||||
ShoppingListLogFile.txt |
||||
ShoppingList-settings.ini |
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<projectDescription> |
||||
<name>ShoppingList</name> |
||||
<comment></comment> |
||||
<projects> |
||||
</projects> |
||||
<buildSpec> |
||||
<buildCommand> |
||||
<name>org.eclipse.jdt.core.javabuilder</name> |
||||
<arguments> |
||||
</arguments> |
||||
</buildCommand> |
||||
</buildSpec> |
||||
<natures> |
||||
<nature>org.eclipse.jdt.core.javanature</nature> |
||||
</natures> |
||||
</projectDescription> |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,134 @@
|
||||
package com.jens.rhasspy.shoppinglist; |
||||
|
||||
|
||||
import java.sql.Connection; |
||||
import java.sql.DriverManager; |
||||
import java.sql.SQLException; |
||||
|
||||
public class DatabaseHandler implements Runnable |
||||
{ |
||||
private static DatabaseHandler instance = null; |
||||
static final String databaseConnectionEncoding = "utf8"; |
||||
|
||||
Connection conn = null; |
||||
|
||||
private DatabaseHandler() |
||||
{ |
||||
} |
||||
|
||||
public static DatabaseHandler getInstance() |
||||
{ |
||||
if(instance == null) |
||||
instance = new DatabaseHandler(); |
||||
|
||||
return instance; |
||||
} |
||||
|
||||
public Connection getConnection() |
||||
{ |
||||
// if(isConnectedToDatabase())
|
||||
// {
|
||||
// // It has occured that the connection was there, but dead due to timeout or whatever
|
||||
// try
|
||||
// {
|
||||
// conn.getSchema();
|
||||
// }
|
||||
// catch (SQLException e)
|
||||
//// if(conn.isValid(5000))
|
||||
// {
|
||||
// Miscellaneous.logEvent("DB connection probably dropped. Reestablishing...");
|
||||
// conn = null;
|
||||
// establishConnection();
|
||||
// }
|
||||
// }
|
||||
|
||||
if(!isConnectedToDatabase()) |
||||
establishConnection(true); |
||||
|
||||
return this.conn; |
||||
} |
||||
|
||||
/** force means that connection is definitely reestablished, even if there seems to be an existing one **/ |
||||
private synchronized void establishConnection(boolean force) |
||||
{ |
||||
if(conn == null | force) |
||||
{ |
||||
for(String dbServer : Settings.databaseServerNames) |
||||
{ |
||||
Miscellaneous.logEvent("Trying to connect to database " + Settings.databaseName + "@" + dbServer + " as " + Settings.databaseUsername + "...", 3); |
||||
|
||||
// String url = "jdbc:mysql://" + dbServer + ":" + Settings.databasePort + "/";
|
||||
// String driver = "com.mysql.jdbc.Driver";
|
||||
String url = "jdbc:mariadb://" + dbServer + ":" + Settings.databasePort + "/"; |
||||
String driver = "org.mariadb.jdbc.Driver"; |
||||
try |
||||
{ |
||||
Class.forName(driver).newInstance(); |
||||
conn = DriverManager.getConnection(url + Settings.databaseName + "?characterEncoding=" + databaseConnectionEncoding, Settings.databaseUsername, Settings.databasePassword); |
||||
Miscellaneous.logEvent("Connected to database.", 3); |
||||
|
||||
break; |
||||
} |
||||
catch (ClassNotFoundException e) |
||||
{ |
||||
Miscellaneous.logEvent(Settings.languageBlock.get("dbDriverNotFound"), 1); |
||||
} |
||||
catch (Exception e) |
||||
{ |
||||
Miscellaneous.logEvent(Settings.languageBlock.get("dbCouldNotConnect"), 1); |
||||
Miscellaneous.logEvent(Diverse.getStackTraceAsString(e), 2); |
||||
this.conn = null; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void disconnect() |
||||
{ |
||||
// TODO: Timeout after which the DB connection is terminated automatically.
|
||||
|
||||
if(conn != null) |
||||
{ |
||||
Miscellaneous.logEvent("Disconnecting from database.", 3); |
||||
try |
||||
{ |
||||
this.conn.close(); |
||||
} |
||||
catch (SQLException e) |
||||
{ |
||||
Miscellaneous.logEvent(Diverse.getStackTraceAsString(e), 1); |
||||
} |
||||
} |
||||
else |
||||
Miscellaneous.logEvent("Not disconnecting from database because not connected.", 4); |
||||
|
||||
conn=null; |
||||
} |
||||
|
||||
@Override |
||||
protected void finalize() throws Throwable |
||||
{ |
||||
disconnect(); |
||||
} |
||||
|
||||
@Override |
||||
public void run() |
||||
{ |
||||
getConnection(); |
||||
} |
||||
|
||||
public boolean isConnectedToDatabase() |
||||
{ |
||||
try |
||||
{ |
||||
if(conn != null && conn.isValid(5000)) |
||||
return true; |
||||
} |
||||
catch (SQLException e) |
||||
{ |
||||
Miscellaneous.logEvent(Diverse.getStackTraceAsString(e), 1); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,611 @@
|
||||
package com.jens.rhasspy.shoppinglist; |
||||
|
||||
|
||||
import org.w3c.dom.Document; |
||||
import org.w3c.dom.Element; |
||||
import org.w3c.dom.Node; |
||||
import org.w3c.dom.NodeList; |
||||
import org.xml.sax.InputSource; |
||||
import org.xml.sax.SAXException; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.PrintWriter; |
||||
import java.io.StringReader; |
||||
import java.io.StringWriter; |
||||
import java.io.Writer; |
||||
import java.math.BigDecimal; |
||||
import java.math.RoundingMode; |
||||
import java.security.SecureRandom; |
||||
import java.sql.Time; |
||||
import java.util.ArrayList; |
||||
import java.util.Calendar; |
||||
import java.util.HashMap; |
||||
import java.util.TimeZone; |
||||
|
||||
import javax.xml.parsers.DocumentBuilder; |
||||
import javax.xml.parsers.DocumentBuilderFactory; |
||||
import javax.xml.parsers.ParserConfigurationException; |
||||
import javax.xml.transform.OutputKeys; |
||||
import javax.xml.transform.Transformer; |
||||
import javax.xml.transform.TransformerConfigurationException; |
||||
import javax.xml.transform.TransformerException; |
||||
import javax.xml.transform.TransformerFactory; |
||||
import javax.xml.transform.dom.DOMSource; |
||||
import javax.xml.transform.stream.StreamResult; |
||||
import javax.xml.xpath.XPath; |
||||
import javax.xml.xpath.XPathConstants; |
||||
import javax.xml.xpath.XPathExpression; |
||||
import javax.xml.xpath.XPathExpressionException; |
||||
import javax.xml.xpath.XPathFactory; |
||||
|
||||
public class Diverse |
||||
{ |
||||
public final static String networkSeparatorCommunication = ";commSep"; |
||||
public final static String networkSeparatorSettings = ";commSett"; |
||||
|
||||
public static enum cacheObjectsEnum { all, devices, commands, rooms, rules, users, houses, nodes, sensors, userDevices }; |
||||
|
||||
public enum SolarEvent {sunrise, sunset}; |
||||
|
||||
public static final String lineSeparator = System.getProperty("line.separator"); |
||||
|
||||
public static String intToOpenClosed(int value) |
||||
{ |
||||
if(value == 1) |
||||
return "closed"; |
||||
else if(value == 0) |
||||
return "open"; |
||||
else |
||||
return "unknown"; |
||||
} |
||||
|
||||
public static String intToWaterYesNo(int value) |
||||
{ |
||||
if(value == 1) |
||||
return "water"; |
||||
else if(value == 0) |
||||
return "dry"; |
||||
else |
||||
return "unknown"; |
||||
} |
||||
|
||||
public static String intToSmokeYesNo(int value) |
||||
{ |
||||
if(value == 1) |
||||
return "smoke"; |
||||
else if(value == 0) |
||||
return "no smoke"; |
||||
else |
||||
return "unknown"; |
||||
} |
||||
|
||||
public static String getEnabledDisabledString(boolean value) |
||||
{ |
||||
if(value) |
||||
return "enabled"; |
||||
else |
||||
return "disabled"; |
||||
} |
||||
|
||||
public static Calendar calendarFromLong(long source) |
||||
{ |
||||
Calendar cal = Calendar.getInstance(); |
||||
cal.setTimeInMillis(source); |
||||
return cal; |
||||
} |
||||
|
||||
public static String getOnOffString(boolean value) |
||||
{ |
||||
if(value) |
||||
return "on"; |
||||
else |
||||
return "off"; |
||||
} |
||||
|
||||
public static String getIniLikeValue(String fullText, String searchObject, String separator) |
||||
{ |
||||
fullText = fullText.trim(); |
||||
|
||||
if (fullText.toLowerCase().contains(searchObject.toLowerCase())) |
||||
{ |
||||
if (fullText.toLowerCase().contains(separator.toLowerCase())) // multiple values
|
||||
{ |
||||
int start = fullText.toLowerCase().indexOf(searchObject.toLowerCase() + "=") + searchObject.length() + 1; |
||||
int end = fullText.toLowerCase().indexOf(separator.toLowerCase(), start); |
||||
|
||||
if (end == -1) // if the last index in fullText
|
||||
return fullText.substring(start); |
||||
else |
||||
return fullText.substring(start, end); |
||||
} |
||||
else // only one value
|
||||
{ |
||||
return fullText.substring(fullText.indexOf("=") + 1); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
Miscellaneous.logEvent("Index " + searchObject + " cannot be found in full text.", 5); |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public static String addOrReplaceIniLikeValue(String fullText, String key, String value, String separator) |
||||
{ |
||||
fullText = fullText.trim(); |
||||
|
||||
if (fullText.startsWith(key + "=") | fullText.contains(separator + key + "=")) |
||||
{ |
||||
if (fullText.contains(separator)) // multiple values
|
||||
{ |
||||
int start = fullText.indexOf(key + "=") + key.length() + 1; |
||||
int end = fullText.indexOf(separator, start); |
||||
|
||||
String oldValue; |
||||
if (end == -1) // if the last index in fullText
|
||||
oldValue = fullText.substring(start); |
||||
else |
||||
oldValue = fullText.substring(start, end); |
||||
|
||||
return fullText.replace(key + "=" + oldValue, key + "=" + value); |
||||
} |
||||
else // only one value
|
||||
{ |
||||
return key + "=" + value; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if(fullText.length() > 0) |
||||
return fullText + separator + key + "=" + value; |
||||
else |
||||
return key + "=" + value; |
||||
} |
||||
} |
||||
|
||||
public static String removeIniLikeValue(String fullText, String key, String separator) |
||||
{ |
||||
fullText = fullText.trim(); |
||||
String toBeRemoved = getIniLikeValue(fullText, key, separator); |
||||
|
||||
if(toBeRemoved != null && fullText.contains(toBeRemoved)) |
||||
{ |
||||
if(fullText.contains(";")) |
||||
{ |
||||
if(fullText.contains(";" + toBeRemoved)) |
||||
return fullText.replace(";" + toBeRemoved, ""); |
||||
else |
||||
return fullText.replace(toBeRemoved + ";", ""); |
||||
} |
||||
else |
||||
return ""; |
||||
} |
||||
else |
||||
return fullText; |
||||
} |
||||
|
||||
public static String updateIniLikeValue(String fullText, String key, String value, String separator) |
||||
{ |
||||
if (fullText.contains(key)) |
||||
{ |
||||
if (fullText.contains(separator)) // multiple values
|
||||
{ |
||||
String[] lines = fullText.split(separator); |
||||
for(int i=0; i < lines.length; i++) |
||||
{ |
||||
if(lines[i].startsWith(key)) |
||||
{ |
||||
int equalsPosition = lines[i].indexOf(key + "=") + key.length() + 1; |
||||
lines[i] = lines[i].substring(0, equalsPosition) + value; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return Diverse.arrayImplode(separator, lines); |
||||
} |
||||
else // only one value
|
||||
{ |
||||
return fullText + separator + key + "=" + value; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
return fullText + separator + key + "=" + value; |
||||
} |
||||
} |
||||
|
||||
public static int boolToInt(boolean in) |
||||
{ |
||||
if (in) |
||||
return 1; |
||||
else |
||||
return 0; |
||||
} |
||||
|
||||
public static boolean intToBool(int in) |
||||
{ |
||||
if (in > 0) |
||||
return true; |
||||
else |
||||
return false; |
||||
|
||||
// ClientServerSplit.logEvent("Error transforming int to bool.", 3);
|
||||
// return false;
|
||||
} |
||||
|
||||
public static boolean isNumeric(String stringToCheck) |
||||
{ |
||||
String character; |
||||
|
||||
for(int i = 0; i < stringToCheck.length(); i++) |
||||
{ |
||||
character = stringToCheck.substring(i, i + 1); |
||||
|
||||
if(!character.matches("[1234567890]") && !character.equals(".") && !character.equals(",")) |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
public static boolean arraySearch(String[] haystack, String needle, boolean caseSensitive, boolean matchFullLine) |
||||
{ |
||||
if(matchFullLine) |
||||
{ |
||||
if(caseSensitive) |
||||
{ |
||||
for (String s : haystack) |
||||
{ |
||||
if (s.equals(needle)) |
||||
return true; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
for (String s : haystack) |
||||
{ |
||||
if (s.toLowerCase().equals(needle.toLowerCase())) |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if(caseSensitive) |
||||
{ |
||||
for (String s : haystack) |
||||
{ |
||||
if (s.contains(needle)) |
||||
return true; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
for (String s : haystack) |
||||
{ |
||||
if (s.toLowerCase().contains(needle.toLowerCase())) |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public static boolean arraySearch(ArrayList<String> requestList, String needle, boolean caseSensitive, boolean matchFullLine) |
||||
{ |
||||
return arraySearch(requestList.toArray(new String[requestList.size()]), needle, caseSensitive, matchFullLine); |
||||
} |
||||
|
||||
public static boolean arraySearch(cacheObjectsEnum[] haystack, cacheObjectsEnum needle) |
||||
{ |
||||
if (needle != null) |
||||
{ |
||||
for (cacheObjectsEnum c : haystack) |
||||
{ |
||||
if (c.equals(needle)) |
||||
return true; |
||||
} |
||||
} |
||||
else |
||||
Miscellaneous.logEvent("Needle should not be null in function arraySearch()", 5); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public static String arrayImplode(String glue, String... values) |
||||
{ |
||||
String returnString = ""; |
||||
|
||||
for (String s : values) |
||||
returnString += s + glue; |
||||
|
||||
if (returnString.length() > 0) |
||||
returnString = returnString.substring(0, returnString.length() - glue.length()); |
||||
|
||||
return returnString; |
||||
} |
||||
|
||||
public static String arrayImplode(String glue, ArrayList<String> arrayList) |
||||
{ |
||||
String returnString = ""; |
||||
|
||||
for (Object s : arrayList) |
||||
returnString += s + glue; |
||||
|
||||
if (returnString.length() > 0) |
||||
returnString = returnString.substring(0, returnString.length() - glue.length()); |
||||
|
||||
return returnString; |
||||
} |
||||
|
||||
public static String arrayImplode(String glue, Object[] array) |
||||
{ |
||||
String returnString = ""; |
||||
|
||||
for (Object s : array) |
||||
returnString += s.toString() + glue; |
||||
|
||||
if (returnString.length() > 0) |
||||
returnString = returnString.substring(0, returnString.length() - glue.length()); |
||||
|
||||
return returnString; |
||||
} |
||||
|
||||
public static String arrayImplode(String glue, HashMap<String, String> map) |
||||
{ |
||||
String returnString = ""; |
||||
|
||||
for (String key : map.keySet()) |
||||
returnString += map.get(key) + glue; |
||||
|
||||
if (returnString.length() > 0) |
||||
returnString = returnString.substring(0, returnString.length() - glue.length()); |
||||
|
||||
return returnString; |
||||
} |
||||
|
||||
public static String getSystemTimezone() |
||||
{ |
||||
// https://coderanch.com/t/386398/java/System-Timezone
|
||||
TimeZone tz = Calendar.getInstance().getTimeZone(); |
||||
// System.out.println(tz.getDisplayName());// (i.e. Moscow Standard Time)
|
||||
return tz.getID(); |
||||
|
||||
// Should return something like this: Asia/Calcutta
|
||||
} |
||||
|
||||
public static String createPassword(int length) |
||||
{ |
||||
final String allowedChars = "0123456789abcdefghijklmnopqrstuvwABCDEFGHIJKLMNOP!ยง$%&?*+#"; |
||||
SecureRandom random = new SecureRandom(); |
||||
StringBuilder pass = new StringBuilder(length); |
||||
for (int i = 0; i < length; i++) |
||||
{ |
||||
pass.append(allowedChars.charAt(random.nextInt(allowedChars.length()))); |
||||
} |
||||
return pass.toString(); |
||||
} |
||||
|
||||
public static Element getXmlTree(String inputString) throws SAXException, IOException, ParserConfigurationException |
||||
{ |
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
||||
DocumentBuilder builder = factory.newDocumentBuilder(); |
||||
|
||||
// Create a Document from a file or stream
|
||||
/* |
||||
StringBuilder xmlStringBuilder = new StringBuilder(); |
||||
xmlStringBuilder.append("<?xml version="1.0"?> <class> </class>"); |
||||
ByteArrayInputStream input = new ByteArrayInputStream(xmlStringBuilder.toString().getBytes("UTF-8")); |
||||
*/ |
||||
// Document doc = builder.parse(input);
|
||||
Document doc = builder.parse(new InputSource(new StringReader(inputString))); |
||||
|
||||
Element rootElement = doc.getDocumentElement(); |
||||
|
||||
return rootElement; |
||||
/* |
||||
// Examine attributes
|
||||
|
||||
//returns specific attribute
|
||||
root.getAttribute("attributeName"); |
||||
|
||||
//returns a Map (table) of names/values
|
||||
root.getAttributes(); |
||||
|
||||
// Examine sub-elements
|
||||
|
||||
//returns a list of subelements of specified name
|
||||
root.getElementsByTagName("subelementName"); |
||||
|
||||
//returns a list of all child nodes
|
||||
root.getChildNodes(); |
||||
*/ |
||||
} |
||||
|
||||
public static String xmlToString(Node node, boolean omitXmlDeclaration, boolean prettyPrint) |
||||
{ |
||||
if (node == null) |
||||
{ |
||||
throw new IllegalArgumentException("node is null."); |
||||
} |
||||
|
||||
try |
||||
{ |
||||
// Remove unwanted whitespaces
|
||||
node.normalize(); |
||||
XPath xpath = XPathFactory.newInstance().newXPath(); |
||||
XPathExpression expr = xpath.compile("//text()[normalize-space()='']"); |
||||
NodeList nodeList = (NodeList) expr.evaluate(node, XPathConstants.NODESET); |
||||
|
||||
for (int i = 0; i < nodeList.getLength(); ++i) |
||||
{ |
||||
Node nd = nodeList.item(i); |
||||
nd.getParentNode().removeChild(nd); |
||||
} |
||||
|
||||
// Create and setup transformer
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer(); |
||||
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); |
||||
|
||||
if (omitXmlDeclaration == true) |
||||
{ |
||||
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); |
||||
} |
||||
|
||||
if (prettyPrint == true) |
||||
{ |
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); |
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); |
||||
} |
||||
|
||||
// Turn the node into a string
|
||||
StringWriter writer = new StringWriter(); |
||||
transformer.transform(new DOMSource(node), new StreamResult(writer)); |
||||
return writer.toString(); |
||||
} |
||||
catch (TransformerConfigurationException e) |
||||
{ |
||||
e.printStackTrace(); |
||||
} |
||||
catch (TransformerException e) |
||||
{ |
||||
throw new RuntimeException(e); |
||||
} |
||||
catch (XPathExpressionException e) |
||||
{ |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
|
||||
public static String getStackTrace() |
||||
{ |
||||
StringBuilder trace = new StringBuilder(); |
||||
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) |
||||
trace.append(ste + Diverse.lineSeparator); |
||||
|
||||
trace.delete(trace.length(), trace.length()); |
||||
|
||||
return trace.toString(); |
||||
} |
||||
|
||||
public static String getStackTraceAsString(Throwable aThrowable) |
||||
{ |
||||
Writer result = new StringWriter(); |
||||
PrintWriter printWriter = new PrintWriter(result); |
||||
aThrowable.printStackTrace(printWriter); |
||||
return result.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Defines a custom format for the stack trace as String. |
||||
*/ |
||||
public static String getCustomStackTrace(Throwable aThrowable) |
||||
{ |
||||
//add the class name and any message passed to constructor
|
||||
StringBuilder result = new StringBuilder( "Stacktrace: " ); |
||||
result.append(aThrowable.toString()); |
||||
String NEW_LINE = System.getProperty("line.separator"); |
||||
result.append(NEW_LINE); |
||||
|
||||
//add each element of the stack trace
|
||||
for (StackTraceElement element : aThrowable.getStackTrace()) |
||||
{ |
||||
result.append(element); |
||||
result.append(NEW_LINE); |
||||
} |
||||
return result.toString(); |
||||
} |
||||
|
||||
public static ArrayList<Element> getSubElements(Node node, String parentName, String childName) |
||||
{ |
||||
ArrayList<Element> returnList = new ArrayList<Element>(); |
||||
NodeList nodeElements = ((Element)node).getElementsByTagName("houses"); |
||||
for(int i = 0; i < nodeElements.getLength(); i++) |
||||
{ |
||||
if (nodeElements.item(i).getNodeType() == Node.ELEMENT_NODE) |
||||
{ |
||||
NodeList childElements = nodeElements.item(i).getChildNodes(); |
||||
for (int j = 0; j < childElements.getLength(); j++) |
||||
{ |
||||
Element element = (Element) childElements.item(j); |
||||
// HouseTemplate house = HouseTemplate.fromXmlStringStatic(Diverse.getXmlFull(element));
|
||||
returnList.add(element); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*ArrayList<Element> returnList = new ArrayList<>(); |
||||
|
||||
NodeList children = ((Element)node).getElementsByTagName(parentName); |
||||
|
||||
for(int i=0; i < children.getLength(); i++) |
||||
{ |
||||
returnList.add((Element)children.item(i)); |
||||
}*/ |
||||
|
||||
return returnList; |
||||
} |
||||
|
||||
public static double round(double value, int places) |
||||
{ |
||||
if (places < 0) throw new IllegalArgumentException(); |
||||
|
||||
BigDecimal bd = new BigDecimal(Double.toString(value)); |
||||
bd = bd.setScale(places, RoundingMode.HALF_UP); |
||||
return bd.doubleValue(); |
||||
} |
||||
|
||||
public static Class getCallerClass() |
||||
{ |
||||
StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); |
||||
for (int i=1; i<stElements.length; i++) |
||||
{ |
||||
StackTraceElement ste = stElements[i]; |
||||
if (!ste.getClassName().equals(Diverse.class.getName()) && ste.getClassName().indexOf("java.lang.Thread")!=0) |
||||
{ |
||||
return ste.getClass().getDeclaringClass(); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public static Class getCallerCallerClassName() |
||||
{ |
||||
StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); |
||||
String callerClassName = null; |
||||
for (int i=1; i<stElements.length; i++) |
||||
{ |
||||
StackTraceElement ste = stElements[i]; |
||||
if (!ste.getClassName().equals(Diverse.class.getName())&& ste.getClassName().indexOf("java.lang.Thread")!=0) |
||||
{ |
||||
if (callerClassName==null) |
||||
{ |
||||
callerClassName = ste.getClassName(); |
||||
} |
||||
else if (!callerClassName.equals(ste.getClassName())) |
||||
{ |
||||
try |
||||
{ |
||||
Class returnClass = Class.forName(ste.getClassName()); |
||||
return returnClass; |
||||
} |
||||
catch(Exception e) |
||||
{} |
||||
// return ste.getClassName();
|
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public static int countOccurences(String input, String needle) |
||||
{ |
||||
String out = input.replace (needle, ""); |
||||
int lenDiff = input.length () - out.length (); |
||||
return lenDiff / needle.length(); |
||||
} |
||||
} |
@ -0,0 +1,562 @@
|
||||
package com.jens.rhasspy.shoppinglist; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.File; |
||||
import java.io.FileReader; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import java.io.OutputStream; |
||||
import java.lang.management.GarbageCollectorMXBean; |
||||
import java.lang.management.ManagementFactory; |
||||
import java.net.MalformedURLException; |
||||
import java.net.URL; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Paths; |
||||
import java.nio.file.StandardOpenOption; |
||||
import java.text.DateFormat; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Calendar; |
||||
import java.util.Date; |
||||
import java.util.Properties; |
||||
import java.util.concurrent.TimeUnit; |
||||
import java.util.logging.FileHandler; |
||||
import java.util.logging.Logger; |
||||
|
||||
import javax.mail.Authenticator; |
||||
import javax.mail.Message; |
||||
import javax.mail.PasswordAuthentication; |
||||
import javax.mail.Session; |
||||
import javax.mail.Transport; |
||||
import javax.mail.internet.AddressException; |
||||
import javax.mail.internet.InternetAddress; |
||||
import javax.mail.internet.MimeMessage; |
||||
|
||||
public class Miscellaneous |
||||
{ |
||||
protected static Calendar logDate; |
||||
static Logger logger = Logger.getLogger(Miscellaneous.class.getName()); |
||||
static FileHandler fileHandler = null; |
||||
|
||||
|
||||
public static final String genericErrorMessage = "sldaskdm32oierror"; |
||||
|
||||
protected static boolean logCleanerRunning = false; |
||||
|
||||
static File getLogFileFullPath() |
||||
{ |
||||
File logFile; |
||||
File folder = new File(Settings.logFolderPath); |
||||
|
||||
if((folder.exists() && folder.canWrite()) | folder.mkdir()) |
||||
logFile = new File(folder.getAbsolutePath() + "/" + Settings.logFileName); |
||||
else |
||||
logFile = new File(Settings.logFileName); |
||||
|
||||
// System.out.println("Using " + logFile.getAbsolutePath().toString() + " as log file path.");
|
||||
|
||||
return logFile; |
||||
} |
||||
|
||||
public static String formatDate(Date input) |
||||
{ |
||||
DateFormat sdf = null; |
||||
SimpleDateFormat fallBackFormatter = new SimpleDateFormat(Settings.dateFormat); |
||||
|
||||
if(sdf == null && Settings.dateFormat != null) |
||||
sdf = new SimpleDateFormat(Settings.dateFormat); |
||||
|
||||
String formattedDate; |
||||
if(sdf != null) |
||||
formattedDate = sdf.format(input); |
||||
else |
||||
formattedDate = fallBackFormatter.format(input); |
||||
|
||||
return formattedDate; |
||||
} |
||||
|
||||
public static synchronized void logEvent(String eventDescription, int logLevel) |
||||
{ |
||||
if(logLevel <= Settings.logLevel) |
||||
{ |
||||
logDate = Calendar.getInstance(); |
||||
|
||||
String formattedDate = Miscellaneous.formatDate(logDate.getTime()); |
||||
|
||||
String callingClass = Thread.currentThread().getStackTrace()[2].getClassName(); |
||||
|
||||
String textToLog = Diverse.lineSeparator + formattedDate + ": " + callingClass + ": " + eventDescription; |
||||
|
||||
File logFile = getLogFileFullPath(); |
||||
|
||||
if(!logFile.exists()) |
||||
{ |
||||
try |
||||
{ |
||||
logFile.createNewFile(); |
||||
} |
||||
catch (IOException e1) |
||||
{ |
||||
e1.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
try |
||||
{ |
||||
Files.write(Paths.get(logFile.toString()), textToLog.getBytes(), StandardOpenOption.APPEND); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
//exception handling left as an exercise for the reader
|
||||
// System.out.println("Error appending to file " + logFile + ": " + Diverse.getStackTraceAsString(e));
|
||||
} |
||||
|
||||
if(Miscellaneous.isDevelopment()) |
||||
System.out.println(textToLog); |
||||
|
||||
if(!logCleanerRunning && Math.random() < 0.01) // tidy up with 0,1% probability
|
||||
{ |
||||
logCleanerRunning = true; |
||||
|
||||
Miscellaneous.logEvent("Cleaning up log file.", 3); |
||||
|
||||
long maxSizeInBytes = (long)Settings.logMaxSize * 1024 * 1024; |
||||
|
||||
if(logFile.exists() && logFile.length() > (maxSizeInBytes)) |
||||
{ |
||||
File archivedLogFile = new File(logFile.getAbsolutePath() + "-old"); |
||||
logFile.renameTo(archivedLogFile); |
||||
Miscellaneous.logEvent("Log renamed to " + archivedLogFile.getAbsolutePath(), 3); |
||||
} |
||||
|
||||
Miscellaneous.logEvent("Cleaning up log file finished.", 3); |
||||
|
||||
logCleanerRunning = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static String getGCStats() |
||||
{ |
||||
StringBuilder returnString = new StringBuilder(); |
||||
|
||||
long totalGarbageCollections = 0; |
||||
long garbageCollectionTime = 0; |
||||
|
||||
for(GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) |
||||
{ |
||||
|
||||
long count = gc.getCollectionCount(); |
||||
|
||||
if(count >= 0) { |
||||
totalGarbageCollections += count; |
||||
} |
||||
|
||||
long time = gc.getCollectionTime(); |
||||
|
||||
if(time >= 0) |
||||
garbageCollectionTime += time; |
||||
} |
||||
|
||||
returnString.append("Total Garbage Collections: " + totalGarbageCollections + Diverse.lineSeparator); |
||||
returnString.append("Total Garbage Collection Time (ms): " + garbageCollectionTime); |
||||
|
||||
return returnString.toString(); |
||||
} |
||||
|
||||
public static class SmtpSimple |
||||
{ |
||||
/** |
||||
* Send a single email. |
||||
*/ |
||||
public boolean sendEmail(String mailServer, int mailServerPor, String encryptionType, boolean useAuthentication, final String username, final String password, String aFromEmailAddr, String aToEmailAddr, String aSubject, String aBody) |
||||
{ |
||||
// Properties รผber die Systemeigenschaften anlegen
|
||||
Properties properties = System.getProperties(); |
||||
|
||||
properties.setProperty("mail.smtp.host", mailServer); |
||||
properties.setProperty("mail.smtp.port", String.valueOf(mailServerPor)); |
||||
|
||||
properties.setProperty("mail.smtp.auth", String.valueOf(useAuthentication)); |
||||
|
||||
/* |
||||
* final Properties props = new Properties(); |
||||
* props.put("mail.smtp.host", "SMTPHOST"); |
||||
* props.put("mail.smtp.port", "PORTNUMBER"); |
||||
* props.put("mail.transport.protocol","smtp"); |
||||
* props.put("mail.smtp.auth", "true"); |
||||
* props.put("mail.smtp.starttls.enable", "true"); |
||||
* props.put("mail.smtp.tls", "true"); |
||||
* props.put("mail.smtp.ssl.checkserveridentity", "true"); |
||||
*/ |
||||
|
||||
if(encryptionType.equalsIgnoreCase("STARTTLS")) |
||||
properties.setProperty("mail.smtp.starttls.enable", "true"); |
||||
else if(encryptionType.equalsIgnoreCase("TLS")) |
||||
properties.put("mail.smtp.tls", "true"); |
||||
else if(encryptionType.equalsIgnoreCase("SSL")) |
||||
properties.setProperty("mail.smtp.ssl.enable", "true"); |
||||
|
||||
// properties.put("mail.smtp.ssl.checkserveridentity", "false");
|
||||
|
||||
Session session; |
||||
|
||||
Authenticator auth = new Authenticator() |
||||
{ |
||||
protected PasswordAuthentication getPasswordAuthentication() |
||||
{ |
||||
return new PasswordAuthentication(username, password); |
||||
} |
||||
}; |
||||
|
||||
if(useAuthentication) |
||||
session = Session.getDefaultInstance(properties, auth); |
||||
else |
||||
session= Session.getDefaultInstance(properties, null); |
||||
|
||||
// session.setDebug(true);
|
||||
|
||||
MimeMessage message = new MimeMessage(session); |
||||
try |
||||
{ |
||||
//the "from" address may be set in code, or set in the
|
||||
//config file under "mail.from" ; here, the latter style is used
|
||||
message.setFrom(new InternetAddress(aFromEmailAddr)); |
||||
message.addRecipient(Message.RecipientType.TO, new InternetAddress(aToEmailAddr)); |
||||
message.setSubject(aSubject); |
||||
message.setText(aBody); |
||||
Transport.send(message); |
||||
return true; |
||||
} |
||||
catch (AddressException e) |
||||
{ |
||||
System.err.println("Cannot send email. " + Diverse.getStackTraceAsString(e)); |
||||
} |
||||
catch (javax.mail.MessagingException e) |
||||
{ |
||||
System.err.println("Cannot send email. " + Diverse.getStackTraceAsString(e)); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public static String readFile(File file) |
||||
{ |
||||
String content = null; |
||||
try |
||||
{ |
||||
FileReader reader = new FileReader(file); |
||||
char[] chars = new char[(int) file.length()]; |
||||
reader.read(chars); |
||||
content = new String(chars); |
||||
reader.close(); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
e.printStackTrace(); |
||||
} |
||||
return content; |
||||
} |
||||
|
||||
public static double convertCelsiusToFahrenheit(double celsius) |
||||
{ |
||||
return (celsius * 1.8 + 32); |
||||
} |
||||
|
||||
public static double convertFahrenheitToCelsius(double fahrenheit) |
||||
{ |
||||
return ((fahrenheit - 32)/1.8); |
||||
} |
||||
|
||||
public static String downloadWebpage(String urlAddress) |
||||
{ |
||||
URL url; |
||||
InputStream is = null; |
||||
BufferedReader br = null; |
||||
String line; |
||||
|
||||
try |
||||
{ |
||||
url = new URL(urlAddress); |
||||
is = url.openStream(); // throws an IOException
|
||||
br = new BufferedReader(new InputStreamReader(is)); |
||||
|
||||
StringBuilder returnString = new StringBuilder(); |
||||
|
||||
while ((line = br.readLine()) != null) |
||||
{ |
||||
// System.out.println(line);
|
||||
returnString.append(line); |
||||
} |
||||
|
||||
if(br != null) |
||||
br.close(); |
||||
|
||||
if (is != null) |
||||
is.close(); |
||||
|
||||
Miscellaneous.logEvent("Webpage downloaded: " + returnString.toString(), 5); |
||||
|
||||
return returnString.toString(); |
||||
} |
||||
catch (MalformedURLException mue) |
||||
{ |
||||
mue.printStackTrace(); |
||||
} |
||||
catch (IOException ioe) |
||||
{ |
||||
ioe.printStackTrace(); |
||||
} |
||||
finally |
||||
{ |
||||
try |
||||
{ |
||||
if(br != null) |
||||
br.close(); |
||||
|
||||
if (is != null) |
||||
is.close(); |
||||
} |
||||
catch (IOException ioe) |
||||
{ |
||||
// nothing to see here
|
||||
} |
||||
} |
||||
|
||||
return genericErrorMessage; |
||||
} |
||||
|
||||
public static boolean isDevelopment() |
||||
{ |
||||
Boolean desenv = null; |
||||
|
||||
// if (desenv != null)
|
||||
// return desenv;
|
||||
|
||||
try |
||||
{ |
||||
desenv = new File(".").getCanonicalPath().contains("workspace"); |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
e.printStackTrace(); |
||||
} |
||||
|
||||
return desenv; |
||||
} |
||||
|
||||
public static String getOnOffStringForBoolean(boolean state) |
||||
{ |
||||
if(state) |
||||
return "on"; |
||||
else |
||||
return "off"; |
||||
} |
||||
|
||||
// public enum SolarEvent { dawn, sunrise, solarNoon, sunset, dusk };
|
||||
|
||||
/** |
||||
* |
||||
* @param commandToExecute |
||||
* @param timeout |
||||
* @return Returns an array: 0=exit code, 1=cmdline output |
||||
*/ |
||||
public static Object[] runExternalApplication(String commandToExecute, long timeout) |
||||
{ |
||||
/* |
||||
* Classes stolen from https://github.com/stleary/JSON-java
|
||||
*/ |
||||
|
||||
Miscellaneous.logEvent("Running external application " + commandToExecute + "...", 4); |
||||
|
||||
Object[] returnObject = new Object[2]; |
||||
|
||||
StringBuilder output = new StringBuilder(); |
||||
String line = null; |
||||
OutputStream stdin = null; |
||||
InputStream stderr = null; |
||||
InputStream stdout = null; |
||||
|
||||
try |
||||
{ |
||||
Process process = null; |
||||
|
||||
process = Runtime.getRuntime().exec(commandToExecute); |
||||
stdin = process.getOutputStream (); |
||||
stderr = process.getErrorStream (); |
||||
stdout = process.getInputStream (); |
||||
|
||||
// "write" the parms into stdin
|
||||
/*line = "param1" + "\n"; |
||||
stdin.write(line.getBytes() ); |
||||
stdin.flush(); |
||||
|
||||
line = "param2" + "\n"; |
||||
stdin.write(line.getBytes() ); |
||||
stdin.flush(); |
||||
|
||||
line = "param3" + "\n"; |
||||
stdin.write(line.getBytes() ); |
||||
stdin.flush(); |
||||
|
||||
stdin.close(); */ |
||||
|
||||
// clean up if any output in stdout
|
||||
BufferedReader brCleanUp = new BufferedReader (new InputStreamReader (stdout)); |
||||
while ((line = brCleanUp.readLine ()) != null) |
||||
{ |
||||
Miscellaneous.logEvent ("[Stdout] " + line, 4); |
||||
output.append(line); |
||||
} |
||||
brCleanUp.close(); |
||||
|
||||
// clean up if any output in stderr
|
||||
brCleanUp = new BufferedReader (new InputStreamReader (stderr)); |
||||
while ((line = brCleanUp.readLine ()) != null) |
||||
{ |
||||
Miscellaneous.logEvent ("[Stderr] " + line, 4); |
||||
output.append(line); |
||||
} |
||||
brCleanUp.close(); |
||||
|
||||
try |
||||
{ |
||||
// Wait for the process to exit, we want the return code
|
||||
if(timeout > 0) |
||||
{ |
||||
try |
||||
{ |
||||
if(!process.waitFor(timeout, TimeUnit.MILLISECONDS)) |
||||
{ |
||||
Miscellaneous.logEvent("Timeout of " + String.valueOf(timeout) + " ms reached. Killing check attempt.", 3); |
||||
process.destroyForcibly(); |
||||
} |
||||
} |
||||
catch(NoSuchMethodError e) |
||||
{ |
||||
process.waitFor(); |
||||
} |
||||
} |
||||
else |
||||
process.waitFor(); |
||||
} |
||||
catch (InterruptedException e) |
||||
{ |
||||
Miscellaneous.logEvent("Waiting for process failed: " + Diverse.getStackTraceAsString(e), 4); |
||||
Miscellaneous.logEvent(Diverse.getStackTraceAsString(e), 1); |
||||
} |
||||
|
||||
Miscellaneous.logEvent("ReturnCode: " + String.valueOf(process.exitValue()), 4); |
||||
|
||||
returnObject[0] = process.exitValue(); |
||||
returnObject[1] = output.toString(); |
||||
|
||||
return returnObject; |
||||
} |
||||
catch (IOException e) |
||||
{ |
||||
Miscellaneous.logEvent(Diverse.getStackTraceAsString(e), 1); |
||||
} |
||||
|
||||
Miscellaneous.logEvent("Error running external application.", 1); |
||||
|
||||
return null; |
||||
} |
||||
|
||||
public static boolean restartNode() |
||||
{ |
||||
// return true;
|
||||
return (boolean) runExternalApplication("sudo shutdown -r", 60000)[0]; |
||||
} |
||||
|
||||
public static boolean isLeapYear(int year) |
||||
{ |
||||
boolean leap = false; |
||||
|
||||
if(year % 4 == 0) |
||||
{ |
||||
if( year % 100 == 0) |
||||
{ |
||||
// year is divisible by 400, hence the year is a leap year
|
||||
if ( year % 400 == 0) |
||||
leap = true; |
||||
else |
||||
leap = false; |
||||
} |
||||
else |
||||
leap = true; |
||||
} |
||||
else |
||||
leap = false; |
||||
|
||||
return leap; |
||||
|
||||
/*if(leap) |
||||
System.out.println(year + " is a leap year."); |
||||
else |
||||
System.out.println(year + " is not a leap year.");*/ |
||||
} |
||||
|
||||
public static double getStarDate(Calendar when) |
||||
{ |
||||
int y = when.get(Calendar.YEAR); |
||||
|
||||
int n = 0; |
||||
if(Miscellaneous.isLeapYear(y)) |
||||
n = 366; |
||||
else |
||||
n = 365; |
||||
|
||||
int b = 2005; |
||||
|
||||
long c = 58000; |
||||
|
||||
int d = when.get(Calendar.DAY_OF_MONTH); |
||||
|
||||
int m = 0; |
||||
switch(when.get(Calendar.MONTH)) |
||||
{ |
||||
case Calendar.JANUARY: |
||||
m = 0; |
||||
break; |
||||
case Calendar.FEBRUARY: |
||||
m = 31; |
||||
break; |
||||
case Calendar.MARCH: |
||||
m = 59; |
||||
break; |
||||
case Calendar.APRIL: |
||||
m = 90; |
||||
break; |
||||
case Calendar.MAY: |
||||
m = 120; |
||||
break; |
||||
case Calendar.JUNE: |
||||
m = 151; |
||||
break; |
||||
case Calendar.JULY: |
||||
m = 181; |
||||
break; |
||||
case Calendar.AUGUST: |
||||
m = 212; |
||||
break; |
||||
case Calendar.SEPTEMBER: |
||||
m = 243; |
||||
break; |
||||
case Calendar.OCTOBER: |
||||
m = 273; |
||||
break; |
||||
case Calendar.NOVEMBER: |
||||
m = 304; |
||||
break; |
||||
case Calendar.DECEMBER: |
||||
m = 334; |
||||
break; |
||||
} |
||||
|
||||
double stardate = c + (1000 * (y-b)) + (1000/n * (m+d-1)); |
||||
|
||||
return stardate; |
||||
} |
||||
} |
@ -0,0 +1,194 @@
|
||||
package com.jens.rhasspy.shoppinglist; |
||||
import java.sql.Connection; |
||||
import java.sql.PreparedStatement; |
||||
import java.sql.ResultSet; |
||||
import java.sql.SQLException; |
||||
import java.sql.Statement; |
||||
import java.sql.Types; |
||||
import java.util.ArrayList; |
||||
|
||||
public class Product |
||||
{ |
||||
static ArrayList<Product> productCache = null; |
||||
|
||||
long id; |
||||
String name; |
||||
String synonyms; |
||||
StoreType storeType; |
||||
|
||||
public long getId() |
||||
{ |
||||
return id; |
||||
} |
||||
public void setId(long id) |
||||
{ |
||||
this.id = id; |
||||
} |
||||
public String getName() |
||||
{ |
||||
return name; |
||||
} |
||||
public void setName(String name) |
||||
{ |
||||
this.name = name; |
||||
} |
||||
|
||||
public String getSynonyms() |
||||
{ |
||||
return synonyms; |
||||
} |
||||
public void setSynonyms(String synonyms) |
||||
{ |
||||
this.synonyms = synonyms; |
||||
} |
||||
public static ArrayList<Product> readAllProducts() |
||||
{ |
||||
if(productCache == null) |
||||
{ |
||||
try |
||||
{ |
||||