From 3bc7fe2531365f640ad01538d1c5b02ee8e6bd9f Mon Sep 17 00:00:00 2001 From: Wolfgang Hottgenroth Date: Wed, 22 Nov 2017 17:32:04 +0100 Subject: [PATCH] initial --- .classpath | 26 +++ .gitignore | 1 + .project | 23 +++ .settings/org.eclipse.jdt.core.prefs | 5 + .settings/org.eclipse.m2e.core.prefs | 4 + .vscode/settings.json | 3 + measurementDataEngine.props | 9 + pom.xml | 54 +++++ .../DatabaseEngine.java | 190 ++++++++++++++++++ .../MeasurementDatabaseEngine.java | 36 ++++ .../MeasurementDatabaseEngineException.java | 14 ++ src/main/resources/log4j2.xml | 17 ++ .../measurementDatabaseEngine/AppTest.java | 38 ++++ 13 files changed, 420 insertions(+) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 .vscode/settings.json create mode 100644 measurementDataEngine.props create mode 100644 pom.xml create mode 100644 src/main/java/de/hottis/measurementDatabaseEngine/DatabaseEngine.java create mode 100644 src/main/java/de/hottis/measurementDatabaseEngine/MeasurementDatabaseEngine.java create mode 100644 src/main/java/de/hottis/measurementDatabaseEngine/MeasurementDatabaseEngineException.java create mode 100644 src/main/resources/log4j2.xml create mode 100644 src/test/java/de/hottis/measurementDatabaseEngine/AppTest.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..af1430b --- /dev/null +++ b/.classpath @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/.project b/.project new file mode 100644 index 0000000..61a3dd3 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + MeasurementDatabaseEngine + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..714351a --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e0f15db --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file diff --git a/measurementDataEngine.props b/measurementDataEngine.props new file mode 100644 index 0000000..7310c4e --- /dev/null +++ b/measurementDataEngine.props @@ -0,0 +1,9 @@ +db.period = 3600 +db.url = jdbc:mysql://localhost/smarthome +db.driver = com.mysql.jdbc.Driver +db.user = smarthome +db.password = smarthome123 + +jms.broker = tcp://localhost:61616 +jms.clientid = mdb +jms.parseddata.topic = IoT/Measurement \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2214ba1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,54 @@ + + 4.0.0 + de.hottis.measurementDatabaseEngine + MeasurementDatabaseEngine + jar + 1.0-SNAPSHOT + MeasurementDatabaseEngine + http://maven.apache.org + + 1.8 + 1.8 + + + + junit + junit + 3.8.1 + test + + + de.hottis.common + HottisLibJava + 1.0-SNAPSHOT + + + de.hottis.smarthomelib + SmarthomeLib + 1.0-SNAPSHOT + + + mysql + mysql-connector-java + 5.1.44 + + + + + + maven-assembly-plugin + + + + de.hottis.measurementDatabaseEngine.MeasurementDatabaseEngine + + + + jar-with-dependencies + + + + + + diff --git a/src/main/java/de/hottis/measurementDatabaseEngine/DatabaseEngine.java b/src/main/java/de/hottis/measurementDatabaseEngine/DatabaseEngine.java new file mode 100644 index 0000000..8ee84c9 --- /dev/null +++ b/src/main/java/de/hottis/measurementDatabaseEngine/DatabaseEngine.java @@ -0,0 +1,190 @@ +package de.hottis.measurementDatabaseEngine; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Properties; +import java.util.Timer; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import de.hottis.common.ITriggerable; +import de.hottis.common.MyQueue; +import de.hottis.common.TriggerTimer; +import de.hottis.smarthomelib.ADataObject; + +public class DatabaseEngine extends Thread implements ITriggerable { + static final String DATABASE_ENGINE_PERIOD_PROP = "db.period"; + static final String DATABASE_URL_PROP = "db.url"; + static final String DATABASE_USER_PROP = "db.user"; + static final String DATABASE_PASSWORD_PROP = "db.password"; + static final String DATABASE_DRIVER_PROP = "db.driver"; + + final protected Logger logger = LogManager.getRootLogger(); + + private Properties config; + private MyQueue queue; + private boolean stop; + private boolean triggerFlag; + private Timer timer; + private int period; + private String dbUrl; + private String dbUsername; + private String dbPassword; + + public DatabaseEngine(Properties config, MyQueue queue) { + super("MeasurementDatabaseEngine.DatabaseEngine"); + this.config = config; + this.queue = queue; + this.stop = false; + this.triggerFlag = false; + this.period = Integer.parseInt(this.config.getProperty(DATABASE_ENGINE_PERIOD_PROP)); + this.dbUrl = this.config.getProperty(DATABASE_URL_PROP); + this.dbUsername = this.config.getProperty(DATABASE_USER_PROP); + this.dbPassword = this.config.getProperty(DATABASE_PASSWORD_PROP); + } + + public void requestShutdown() { + logger.info("Shutdown of database engine requested"); + this.stop = true; + try { + this.join(); + logger.info("Database engine is down"); + } catch (InterruptedException e) { + logger.error("Waiting for shutdown of database engine interrupted"); + } + } + + public synchronized void trigger() { + logger.debug("DatabaseEngine triggered"); + triggerFlag = true; + notify(); + } + + public void init() throws MeasurementDatabaseEngineException { + timer = new Timer("DatabaseEngineTrigger"); + timer.schedule(new TriggerTimer(this), 0, period * 1000); + try { + Class.forName(config.getProperty(DATABASE_DRIVER_PROP)); + } catch (ClassNotFoundException e) { + logger.error("Database driver class not found", e); + throw new MeasurementDatabaseEngineException("Database driver class not found", e); + } + } + + private String createStatementFromDataObject(ADataObject ado) { + StringBuffer sb = new StringBuffer(); + sb.append("INSERT INTO " + ado.getTableName()); + sb.append("(name,ts,"); + sb.append(String.join(",", ado.getValues().keySet())); + sb.append(") "); + sb.append("VALUES(?,?,"); + + String[] marks = (String[]) ado.getValues().values().stream() + .map(c -> "?") + .toArray(String[]::new); + sb.append(String.join(",", marks)); + + sb.append(")"); + return sb.toString(); + } + + private void bindValue(PreparedStatement pstmt, int pos, Object o) throws SQLException { + if (o instanceof Integer) { + pstmt.setInt(pos, (Integer)o); + } else if (o instanceof Byte) { + pstmt.setByte(pos, (Byte)o); + } else if (o instanceof Double) { + pstmt.setDouble(pos, (Double)o); + } else if (o instanceof String) { + pstmt.setString(pos, (String)o); + } else if (o instanceof LocalDateTime) { + pstmt.setTimestamp(pos, Timestamp.valueOf(((LocalDateTime)o))); + } else { + throw new SQLException("illegal parameter type: " + o.getClass().getName()); + } + } + + + @Override + public synchronized void run() { + while (! stop) { + logger.debug("DatabaseEngine is about to wait for (regularly) " + period + "s"); + while (! triggerFlag) { + try { + wait(); + } catch (InterruptedException e) { + } + } + triggerFlag = false; + logger.debug("DatabaseEngine has received trigger"); + + Connection dbCon = null; + HashMap preparedStatements = new HashMap(); + try { + int itemCnt = 0; + + while (true) { + try { + ADataObject ado = queue.dequeue(); + if (ado == null) { + logger.warn("DatabaseEngine found no data"); + break; + } + dbCon = DriverManager.getConnection(dbUrl, dbUsername, dbPassword); + + String key = ado.getClass().getName(); + PreparedStatement pstmt; + if (! preparedStatements.containsKey(key)) { + pstmt = dbCon.prepareStatement(createStatementFromDataObject(ado)); + preparedStatements.put(key, pstmt); + } else { + pstmt = preparedStatements.get(key); + } + bindValue(pstmt, 1, ado.getName()); + bindValue(pstmt, 2, ado.getTimestamp()); + int pos = 3; + for (Object o : ado.getValues().values()) { + bindValue(pstmt, pos, o); + pos++; + } + itemCnt++; + logger.info("DatabaseEngine received (" + itemCnt + ") " + ado); + logger.info("Statement is " + pstmt.toString()); + pstmt.execute(); + logger.info("Database insert executed"); + pstmt.clearParameters(); + } catch (SQLException e) { + logger.error("SQLException in inner database engine loop", e); + } + } + } catch (Exception e) { + logger.error("Exception in outer database engine loop", e); + } finally { + for (PreparedStatement p : preparedStatements.values()) { + try { + p.close(); + } catch (SQLException e) { + logger.warn("SQLException when closing prepared statement, nothing will be done"); + } + } + preparedStatements.clear(); + if (dbCon != null) { + try { + dbCon.close(); + } catch (SQLException e) { + logger.warn("SQLException when closing connection, nothing will be done"); + } finally { + dbCon = null; + } + } + } + } + logger.info("Database engine is terminating"); + } +} diff --git a/src/main/java/de/hottis/measurementDatabaseEngine/MeasurementDatabaseEngine.java b/src/main/java/de/hottis/measurementDatabaseEngine/MeasurementDatabaseEngine.java new file mode 100644 index 0000000..66643b5 --- /dev/null +++ b/src/main/java/de/hottis/measurementDatabaseEngine/MeasurementDatabaseEngine.java @@ -0,0 +1,36 @@ +package de.hottis.measurementDatabaseEngine; + +import java.io.FileInputStream; +import java.util.Properties; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import de.hottis.common.JmsTopic; +import de.hottis.smarthomelib.ADataObject; + + +public class MeasurementDatabaseEngine { + static final String PROPS_FILENAME = "measurementDataEngine.props"; + static final Logger logger = LogManager.getRootLogger(); + + + public static void main(String[] args) throws Exception { + logger.info("MeasurementDatabaseEngine starting"); + + final Properties config = new Properties(); + try (FileInputStream propsFileInputStream = new FileInputStream(PROPS_FILENAME)) { + config.load(propsFileInputStream); + } + logger.debug("Configuration loaded"); + + JmsTopic queue = new JmsTopic(config, JmsTopic.Mode.CONSUMER); + queue.init(); + + DatabaseEngine databaseEngine = new DatabaseEngine(config, queue); + databaseEngine.init(); + databaseEngine.start(); + logger.debug("DatabaseEngine started"); + } + +} diff --git a/src/main/java/de/hottis/measurementDatabaseEngine/MeasurementDatabaseEngineException.java b/src/main/java/de/hottis/measurementDatabaseEngine/MeasurementDatabaseEngineException.java new file mode 100644 index 0000000..b2cd514 --- /dev/null +++ b/src/main/java/de/hottis/measurementDatabaseEngine/MeasurementDatabaseEngineException.java @@ -0,0 +1,14 @@ +package de.hottis.measurementDatabaseEngine; + +public class MeasurementDatabaseEngineException extends Exception { + private static final long serialVersionUID = 1L; + + public MeasurementDatabaseEngineException(String msg, Throwable cause) { + super(msg, cause); + } + + public MeasurementDatabaseEngineException(String msg) { + super(msg); + } + +} diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..0e87b69 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/de/hottis/measurementDatabaseEngine/AppTest.java b/src/test/java/de/hottis/measurementDatabaseEngine/AppTest.java new file mode 100644 index 0000000..bfed46a --- /dev/null +++ b/src/test/java/de/hottis/measurementDatabaseEngine/AppTest.java @@ -0,0 +1,38 @@ +package de.hottis.measurementDatabaseEngine; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +}