[jdbc] Fix warnings and apply null annotations (#13429)

* Fix warnings and apply null annotations

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
Jacob Laursen 2022-10-02 11:14:41 +02:00 committed by GitHub
parent c41c38405e
commit c706ac8478
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 169 additions and 145 deletions

View File

@ -19,6 +19,7 @@ import java.time.ZoneId;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -27,6 +28,7 @@ import java.util.stream.Collectors;
import javax.measure.Quantity; import javax.measure.Quantity;
import javax.measure.Unit; import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.core.items.GroupItem; import org.openhab.core.items.GroupItem;
@ -65,6 +67,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Helmut Lehmeyer - Initial contribution * @author Helmut Lehmeyer - Initial contribution
*/ */
@NonNullByDefault
public class JdbcBaseDAO { public class JdbcBaseDAO {
private final Logger logger = LoggerFactory.getLogger(JdbcBaseDAO.class); private final Logger logger = LoggerFactory.getLogger(JdbcBaseDAO.class);
@ -73,18 +76,18 @@ public class JdbcBaseDAO {
public final Map<String, String> sqlTypes = new HashMap<>(); public final Map<String, String> sqlTypes = new HashMap<>();
// Get Database Meta data // Get Database Meta data
protected DbMetaData dbMeta; protected @Nullable DbMetaData dbMeta;
protected String sqlPingDB; protected String sqlPingDB = "SELECT 1";
protected String sqlGetDB; protected String sqlGetDB = "SELECT DATABASE()";
protected String sqlIfTableExists; protected String sqlIfTableExists = "SHOW TABLES LIKE '#searchTable#'";
protected String sqlCreateNewEntryInItemsTable; protected String sqlCreateNewEntryInItemsTable = "INSERT INTO #itemsManageTable# (ItemName) VALUES ('#itemname#')";
protected String sqlCreateItemsTableIfNot; protected String sqlCreateItemsTableIfNot = "CREATE TABLE IF NOT EXISTS #itemsManageTable# (ItemId INT NOT NULL AUTO_INCREMENT,#colname# #coltype# NOT NULL,PRIMARY KEY (ItemId))";
protected String sqlDeleteItemsEntry; protected String sqlDeleteItemsEntry = "DELETE FROM items WHERE ItemName=#itemname#";
protected String sqlGetItemIDTableNames; protected String sqlGetItemIDTableNames = "SELECT itemid, itemname FROM #itemsManageTable#";
protected String sqlGetItemTables; protected String sqlGetItemTables = "SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_schema='#jdbcUriDatabaseName#' AND NOT table_name='#itemsManageTable#'";
protected String sqlCreateItemTable; protected String sqlCreateItemTable = "CREATE TABLE IF NOT EXISTS #tableName# (time #tablePrimaryKey# NOT NULL, value #dbType#, PRIMARY KEY(time))";
protected String sqlInsertItemValue; protected String sqlInsertItemValue = "INSERT INTO #tableName# (TIME, VALUE) VALUES( #tablePrimaryValue#, ? ) ON DUPLICATE KEY UPDATE VALUE= ?";
/******** /********
* INIT * * INIT *
@ -92,7 +95,6 @@ public class JdbcBaseDAO {
public JdbcBaseDAO() { public JdbcBaseDAO() {
initSqlTypes(); initSqlTypes();
initDbProps(); initDbProps();
initSqlQueries();
} }
/** /**
@ -131,21 +133,6 @@ public class JdbcBaseDAO {
* *
*/ */
private void initSqlQueries() {
logger.debug("JDBC::initSqlQueries: '{}'", this.getClass().getSimpleName());
sqlPingDB = "SELECT 1";
sqlGetDB = "SELECT DATABASE()";
sqlIfTableExists = "SHOW TABLES LIKE '#searchTable#'";
sqlCreateNewEntryInItemsTable = "INSERT INTO #itemsManageTable# (ItemName) VALUES ('#itemname#')";
sqlCreateItemsTableIfNot = "CREATE TABLE IF NOT EXISTS #itemsManageTable# (ItemId INT NOT NULL AUTO_INCREMENT,#colname# #coltype# NOT NULL,PRIMARY KEY (ItemId))";
sqlDeleteItemsEntry = "DELETE FROM items WHERE ItemName=#itemname#";
sqlGetItemIDTableNames = "SELECT itemid, itemname FROM #itemsManageTable#";
sqlGetItemTables = "SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_schema='#jdbcUriDatabaseName#' AND NOT table_name='#itemsManageTable#'";
sqlCreateItemTable = "CREATE TABLE IF NOT EXISTS #tableName# (time #tablePrimaryKey# NOT NULL, value #dbType#, PRIMARY KEY(time))";
sqlInsertItemValue = "INSERT INTO #tableName# (TIME, VALUE) VALUES( #tablePrimaryValue#, ? ) ON DUPLICATE KEY UPDATE VALUE= ?";
}
/** /**
* INFO: http://www.java2s.com/Code/Java/Database-SQL-JDBC/StandardSQLDataTypeswithTheirJavaEquivalents.htm * INFO: http://www.java2s.com/Code/Java/Database-SQL-JDBC/StandardSQLDataTypeswithTheirJavaEquivalents.htm
*/ */
@ -257,19 +244,19 @@ public class JdbcBaseDAO {
/************** /**************
* ITEMS DAOs * * ITEMS DAOs *
**************/ **************/
public Integer doPingDB() { public @Nullable Integer doPingDB() {
return Yank.queryScalar(sqlPingDB, Integer.class, null); return Yank.queryScalar(sqlPingDB, (Class<@Nullable Integer>) Integer.class, null);
} }
public String doGetDB() { public @Nullable String doGetDB() {
return Yank.queryScalar(sqlGetDB, String.class, null); return Yank.queryScalar(sqlGetDB, (Class<@Nullable String>) String.class, null);
} }
public boolean doIfTableExists(ItemsVO vo) { public boolean doIfTableExists(ItemsVO vo) {
String sql = StringUtilsExt.replaceArrayMerge(sqlIfTableExists, new String[] { "#searchTable#" }, String sql = StringUtilsExt.replaceArrayMerge(sqlIfTableExists, new String[] { "#searchTable#" },
new String[] { vo.getItemsManageTable() }); new String[] { vo.getItemsManageTable() });
logger.debug("JDBC::doIfTableExists sql={}", sql); logger.debug("JDBC::doIfTableExists sql={}", sql);
return Yank.queryScalar(sql, String.class, null) != null; return Yank.queryScalar(sql, (Class<@Nullable String>) String.class, null) != null;
} }
public Long doCreateNewEntryInItemsTable(ItemsVO vo) { public Long doCreateNewEntryInItemsTable(ItemsVO vo) {
@ -477,7 +464,9 @@ public class JdbcBaseDAO {
} }
} }
String it = getSqlTypes().get(itemType); String it = getSqlTypes().get(itemType);
if (it.toUpperCase().contains("DOUBLE")) { if (it == null) {
logger.warn("JDBC::storeItemValueProvider: No SQL type defined for item type {}", itemType);
} else if (it.toUpperCase().contains("DOUBLE")) {
vo.setValueTypes(it, java.lang.Double.class); vo.setValueTypes(it, java.lang.Double.class);
double value = ((Number) convertedState).doubleValue(); double value = ((Number) convertedState).doubleValue();
logger.debug("JDBC::storeItemValueProvider: newVal.doubleValue: '{}'", value); logger.debug("JDBC::storeItemValueProvider: newVal.doubleValue: '{}'", value);
@ -537,6 +526,9 @@ public class JdbcBaseDAO {
v, unit, v.getClass(), v.getClass().getSimpleName()); v, unit, v.getClass(), v.getClass().getSimpleName());
if (item instanceof NumberItem) { if (item instanceof NumberItem) {
String it = getSqlTypes().get("NUMBERITEM"); String it = getSqlTypes().get("NUMBERITEM");
if (it == null) {
throw new UnsupportedOperationException("No SQL type defined for item type NUMBERITEM");
}
if (it.toUpperCase().contains("DOUBLE")) { if (it.toUpperCase().contains("DOUBLE")) {
return unit == null ? new DecimalType(((Number) v).doubleValue()) return unit == null ? new DecimalType(((Number) v).doubleValue())
: QuantityType.valueOf(((Number) v).doubleValue(), unit); : QuantityType.valueOf(((Number) v).doubleValue(), unit);
@ -558,9 +550,17 @@ public class JdbcBaseDAO {
} else if (item instanceof ImageItem) { } else if (item instanceof ImageItem) {
return RawType.valueOf(objectAsString(v)); return RawType.valueOf(objectAsString(v));
} else if (item instanceof ContactItem || item instanceof PlayerItem || item instanceof SwitchItem) { } else if (item instanceof ContactItem || item instanceof PlayerItem || item instanceof SwitchItem) {
return TypeParser.parseState(item.getAcceptedDataTypes(), ((String) v).toString().trim()); State state = TypeParser.parseState(item.getAcceptedDataTypes(), ((String) v).toString().trim());
if (state == null) {
throw new UnsupportedOperationException("Unable to parse state for item " + item.toString());
}
return state;
} else { } else {
return TypeParser.parseState(item.getAcceptedDataTypes(), ((String) v).toString()); State state = TypeParser.parseState(item.getAcceptedDataTypes(), ((String) v).toString());
if (state == null) {
throw new UnsupportedOperationException("Unable to parse state for item " + item.toString());
}
return state;
} }
} }
@ -617,13 +617,14 @@ public class JdbcBaseDAO {
logger.debug( logger.debug(
"JDBC::getItemType: Cannot detect ItemType for {} because the GroupItems' base type isn't set in *.items File.", "JDBC::getItemType: Cannot detect ItemType for {} because the GroupItems' base type isn't set in *.items File.",
i.getName()); i.getName());
item = ((GroupItem) i).getMembers().iterator().next(); Iterator<Item> iterator = ((GroupItem) i).getMembers().iterator();
if (item == null) { if (!iterator.hasNext()) {
logger.debug( logger.debug(
"JDBC::getItemType: No ItemType found for first Child-Member of GroupItem {}, use ItemType for STRINGITEM as Fallback", "JDBC::getItemType: No Child-Members of GroupItem {}, use ItemType for STRINGITEM as Fallback",
i.getName()); i.getName());
return def; return def;
} }
item = iterator.next();
} }
} }
String itemType = item.getClass().getSimpleName().toUpperCase(); String itemType = item.getClass().getSimpleName().toUpperCase();
@ -645,6 +646,10 @@ public class JdbcBaseDAO {
} }
public String getDataType(Item item) { public String getDataType(Item item) {
return sqlTypes.get(getItemType(item)); String dataType = sqlTypes.get(getItemType(item));
if (dataType == null) {
throw new UnsupportedOperationException("No data type found for " + getItemType(item));
}
return dataType;
} }
} }

View File

@ -19,6 +19,8 @@ import java.util.stream.Collectors;
import javax.measure.Quantity; import javax.measure.Quantity;
import javax.measure.Unit; import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.core.items.Item; import org.openhab.core.items.Item;
import org.openhab.core.library.items.NumberItem; import org.openhab.core.library.items.NumberItem;
@ -40,6 +42,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Helmut Lehmeyer - Initial contribution * @author Helmut Lehmeyer - Initial contribution
*/ */
@NonNullByDefault
public class JdbcDerbyDAO extends JdbcBaseDAO { public class JdbcDerbyDAO extends JdbcBaseDAO {
private final Logger logger = LoggerFactory.getLogger(JdbcDerbyDAO.class); private final Logger logger = LoggerFactory.getLogger(JdbcDerbyDAO.class);
@ -99,8 +102,8 @@ public class JdbcDerbyDAO extends JdbcBaseDAO {
* ITEMS DAOs * * ITEMS DAOs *
**************/ **************/
@Override @Override
public Integer doPingDB() { public @Nullable Integer doPingDB() {
return Yank.queryScalar(sqlPingDB, Integer.class, null); return Yank.queryScalar(sqlPingDB, (Class<@Nullable Integer>) Integer.class, null);
} }
@Override @Override
@ -108,7 +111,7 @@ public class JdbcDerbyDAO extends JdbcBaseDAO {
String sql = StringUtilsExt.replaceArrayMerge(sqlIfTableExists, new String[] { "#searchTable#" }, String sql = StringUtilsExt.replaceArrayMerge(sqlIfTableExists, new String[] { "#searchTable#" },
new String[] { vo.getItemsManageTable().toUpperCase() }); new String[] { vo.getItemsManageTable().toUpperCase() });
logger.debug("JDBC::doIfTableExists sql={}", sql); logger.debug("JDBC::doIfTableExists sql={}", sql);
return Yank.queryScalar(sql, String.class, null) != null; return Yank.queryScalar(sql, (Class<@Nullable String>) String.class, null) != null;
} }
@Override @Override

View File

@ -12,6 +12,7 @@
*/ */
package org.openhab.persistence.jdbc.db; package org.openhab.persistence.jdbc.db;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.core.items.Item; import org.openhab.core.items.Item;
import org.openhab.core.types.State; import org.openhab.core.types.State;
@ -27,6 +28,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Helmut Lehmeyer - Initial contribution * @author Helmut Lehmeyer - Initial contribution
*/ */
@NonNullByDefault
public class JdbcH2DAO extends JdbcBaseDAO { public class JdbcH2DAO extends JdbcBaseDAO {
private final Logger logger = LoggerFactory.getLogger(JdbcH2DAO.class); private final Logger logger = LoggerFactory.getLogger(JdbcH2DAO.class);

View File

@ -12,6 +12,8 @@
*/ */
package org.openhab.persistence.jdbc.db; package org.openhab.persistence.jdbc.db;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.core.items.Item; import org.openhab.core.items.Item;
import org.openhab.core.types.State; import org.openhab.core.types.State;
@ -28,6 +30,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Helmut Lehmeyer - Initial contribution * @author Helmut Lehmeyer - Initial contribution
*/ */
@NonNullByDefault
public class JdbcHsqldbDAO extends JdbcBaseDAO { public class JdbcHsqldbDAO extends JdbcBaseDAO {
private final Logger logger = LoggerFactory.getLogger(JdbcHsqldbDAO.class); private final Logger logger = LoggerFactory.getLogger(JdbcHsqldbDAO.class);
@ -75,8 +78,8 @@ public class JdbcHsqldbDAO extends JdbcBaseDAO {
* ITEMS DAOs * * ITEMS DAOs *
**************/ **************/
@Override @Override
public Integer doPingDB() { public @Nullable Integer doPingDB() {
return Yank.queryScalar(sqlPingDB, Integer.class, null); return Yank.queryScalar(sqlPingDB, (Class<@Nullable Integer>) Integer.class, null);
} }
@Override @Override

View File

@ -13,6 +13,7 @@
package org.openhab.persistence.jdbc.db; package org.openhab.persistence.jdbc.db;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.persistence.jdbc.utils.DbMetaData; import org.openhab.persistence.jdbc.utils.DbMetaData;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -75,7 +76,8 @@ public class JdbcMariadbDAO extends JdbcBaseDAO {
@Override @Override
public void initAfterFirstDbConnection() { public void initAfterFirstDbConnection() {
logger.debug("JDBC::initAfterFirstDbConnection: Initializing step, after db is connected."); logger.debug("JDBC::initAfterFirstDbConnection: Initializing step, after db is connected.");
dbMeta = new DbMetaData(); DbMetaData dbMeta = new DbMetaData();
this.dbMeta = dbMeta;
// Initialize sqlTypes, depending on DB version for example // Initialize sqlTypes, depending on DB version for example
if (dbMeta.isDbVersionGreater(5, 1)) { if (dbMeta.isDbVersionGreater(5, 1)) {
sqlTypes.put("DATETIMEITEM", "TIMESTAMP(3)"); sqlTypes.put("DATETIMEITEM", "TIMESTAMP(3)");
@ -88,8 +90,9 @@ public class JdbcMariadbDAO extends JdbcBaseDAO {
* ITEMS DAOs * * ITEMS DAOs *
**************/ **************/
@Override @Override
public Integer doPingDB() { public @Nullable Integer doPingDB() {
return Yank.queryScalar(sqlPingDB, Long.class, null).intValue(); final @Nullable Long result = Yank.queryScalar(sqlPingDB, (Class<@Nullable Long>) Long.class, null);
return result != null ? result.intValue() : null;
} }
/************* /*************

View File

@ -13,6 +13,7 @@
package org.openhab.persistence.jdbc.db; package org.openhab.persistence.jdbc.db;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.persistence.jdbc.utils.DbMetaData; import org.openhab.persistence.jdbc.utils.DbMetaData;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -78,7 +79,8 @@ public class JdbcMysqlDAO extends JdbcBaseDAO {
@Override @Override
public void initAfterFirstDbConnection() { public void initAfterFirstDbConnection() {
logger.debug("JDBC::initAfterFirstDbConnection: Initializing step, after db is connected."); logger.debug("JDBC::initAfterFirstDbConnection: Initializing step, after db is connected.");
dbMeta = new DbMetaData(); DbMetaData dbMeta = new DbMetaData();
this.dbMeta = dbMeta;
// Initialize sqlTypes, depending on DB version for example // Initialize sqlTypes, depending on DB version for example
if (dbMeta.isDbVersionGreater(5, 5)) { if (dbMeta.isDbVersionGreater(5, 5)) {
sqlTypes.put("DATETIMEITEM", "TIMESTAMP(3)"); sqlTypes.put("DATETIMEITEM", "TIMESTAMP(3)");
@ -91,8 +93,9 @@ public class JdbcMysqlDAO extends JdbcBaseDAO {
* ITEMS DAOs * * ITEMS DAOs *
**************/ **************/
@Override @Override
public Integer doPingDB() { public @Nullable Integer doPingDB() {
return Yank.queryScalar(sqlPingDB, Long.class, null).intValue(); final @Nullable Long result = Yank.queryScalar(sqlPingDB, (Class<@Nullable Long>) Long.class, null);
return result != null ? result.intValue() : null;
} }
/************* /*************

View File

@ -15,6 +15,7 @@ package org.openhab.persistence.jdbc.db;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.List; import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.core.items.Item; import org.openhab.core.items.Item;
import org.openhab.core.persistence.FilterCriteria; import org.openhab.core.persistence.FilterCriteria;
@ -33,6 +34,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Helmut Lehmeyer - Initial contribution * @author Helmut Lehmeyer - Initial contribution
*/ */
@NonNullByDefault
public class JdbcPostgresqlDAO extends JdbcBaseDAO { public class JdbcPostgresqlDAO extends JdbcBaseDAO {
private final Logger logger = LoggerFactory.getLogger(JdbcPostgresqlDAO.class); private final Logger logger = LoggerFactory.getLogger(JdbcPostgresqlDAO.class);

View File

@ -12,6 +12,8 @@
*/ */
package org.openhab.persistence.jdbc.db; package org.openhab.persistence.jdbc.db;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.core.items.Item; import org.openhab.core.items.Item;
import org.openhab.core.types.State; import org.openhab.core.types.State;
@ -28,6 +30,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Helmut Lehmeyer - Initial contribution * @author Helmut Lehmeyer - Initial contribution
*/ */
@NonNullByDefault
public class JdbcSqliteDAO extends JdbcBaseDAO { public class JdbcSqliteDAO extends JdbcBaseDAO {
private final Logger logger = LoggerFactory.getLogger(JdbcSqliteDAO.class); private final Logger logger = LoggerFactory.getLogger(JdbcSqliteDAO.class);
@ -73,8 +76,8 @@ public class JdbcSqliteDAO extends JdbcBaseDAO {
**************/ **************/
@Override @Override
public String doGetDB() { public @Nullable String doGetDB() {
return Yank.queryColumn(sqlGetDB, "file", String.class, null).get(0); return Yank.queryColumn(sqlGetDB, "file", (Class<@Nullable String>) String.class, null).get(0);
} }
@Override @Override

View File

@ -14,6 +14,7 @@ package org.openhab.persistence.jdbc.db;
import java.util.Properties; import java.util.Properties;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.persistence.jdbc.dto.ItemVO; import org.openhab.persistence.jdbc.dto.ItemVO;
import org.openhab.persistence.jdbc.utils.StringUtilsExt; import org.openhab.persistence.jdbc.utils.StringUtilsExt;
@ -27,6 +28,7 @@ import org.slf4j.LoggerFactory;
* @author Riccardo Nimser-Joseph - Initial contribution * @author Riccardo Nimser-Joseph - Initial contribution
* @author Dan Cunningham - Fixes and refactoring * @author Dan Cunningham - Fixes and refactoring
*/ */
@NonNullByDefault
public class JdbcTimescaledbDAO extends JdbcPostgresqlDAO { public class JdbcTimescaledbDAO extends JdbcPostgresqlDAO {
private final Logger logger = LoggerFactory.getLogger(JdbcTimescaledbDAO.class); private final Logger logger = LoggerFactory.getLogger(JdbcTimescaledbDAO.class);

View File

@ -21,6 +21,8 @@ import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.persistence.jdbc.db.JdbcBaseDAO; import org.openhab.persistence.jdbc.db.JdbcBaseDAO;
import org.openhab.persistence.jdbc.utils.MovingAverage; import org.openhab.persistence.jdbc.utils.MovingAverage;
import org.openhab.persistence.jdbc.utils.StringUtilsExt; import org.openhab.persistence.jdbc.utils.StringUtilsExt;
@ -32,6 +34,7 @@ import org.slf4j.LoggerFactory;
* *
* @author Helmut Lehmeyer - Initial contribution * @author Helmut Lehmeyer - Initial contribution
*/ */
@NonNullByDefault
public class JdbcConfiguration { public class JdbcConfiguration {
private final Logger logger = LoggerFactory.getLogger(JdbcConfiguration.class); private final Logger logger = LoggerFactory.getLogger(JdbcConfiguration.class);
@ -40,12 +43,12 @@ public class JdbcConfiguration {
private Map<Object, Object> configuration; private Map<Object, Object> configuration;
private JdbcBaseDAO dBDAO = null; private @NonNullByDefault({}) JdbcBaseDAO dBDAO;
private String dbName = null; private @Nullable String dbName;
boolean dbConnected = false; boolean dbConnected = false;
boolean driverAvailable = false; boolean driverAvailable = false;
private String serviceName; private @Nullable String serviceName;
private String name = "jdbc"; private String name = "jdbc";
public final boolean valid; public final boolean valid;
@ -70,12 +73,11 @@ public class JdbcConfiguration {
public JdbcConfiguration(Map<Object, Object> configuration) { public JdbcConfiguration(Map<Object, Object> configuration) {
logger.debug("JDBC::JdbcConfiguration"); logger.debug("JDBC::JdbcConfiguration");
valid = updateConfig(configuration); this.configuration = configuration;
valid = updateConfig();
} }
private boolean updateConfig(Map<Object, Object> config) { private boolean updateConfig() {
configuration = config;
logger.debug("JDBC::updateConfig: configuration size = {}", configuration.size()); logger.debug("JDBC::updateConfig: configuration size = {}", configuration.size());
String user = (String) configuration.get("user"); String user = (String) configuration.get("user");
@ -226,15 +228,17 @@ public class JdbcConfiguration {
} }
private void setDBDAOClass(String sn) { private void setDBDAOClass(String sn) {
serviceName = "none"; String serviceName;
// set database type // set database type
if (sn == null || sn.isBlank() || sn.length() < 2) { if (sn.isBlank() || sn.length() < 2) {
logger.error( logger.error(
"JDBC::updateConfig: Required database url like 'jdbc:<service>:<host>[:<port>;<attributes>]' - please configure the jdbc:url parameter in openhab.cfg"); "JDBC::updateConfig: Required database url like 'jdbc:<service>:<host>[:<port>;<attributes>]' - please configure the jdbc:url parameter in openhab.cfg");
serviceName = "none";
} else { } else {
serviceName = sn; serviceName = sn;
} }
this.serviceName = serviceName;
logger.debug("JDBC::updateConfig: found serviceName = '{}'", serviceName); logger.debug("JDBC::updateConfig: found serviceName = '{}'", serviceName);
// set class for database type // set class for database type
@ -277,9 +281,11 @@ public class JdbcConfiguration {
} }
String value = (String) configuration.get(key); String value = (String) configuration.get(key);
logger.debug("JDBC::updateConfig: set sqlTypes: itemType={} value={}", itemType, value); logger.debug("JDBC::updateConfig: set sqlTypes: itemType={} value={}", itemType, value);
if (value != null) {
dBDAO.sqlTypes.put(itemType, value); dBDAO.sqlTypes.put(itemType, value);
} }
} }
}
private void testJDBCDriver(String driver) { private void testJDBCDriver(String driver) {
driverAvailable = true; driverAvailable = true;
@ -294,6 +300,8 @@ public class JdbcConfiguration {
String warn = "" String warn = ""
+ "\n\n\t!!!\n\tTo avoid this error, place an appropriate JDBC driver file for serviceName '{}' in addons directory.\n" + "\n\n\t!!!\n\tTo avoid this error, place an appropriate JDBC driver file for serviceName '{}' in addons directory.\n"
+ "\tCopy missing JDBC-Driver-jar to your openHab/addons Folder.\n\t!!!\n" + "\tDOWNLOAD: \n"; + "\tCopy missing JDBC-Driver-jar to your openHab/addons Folder.\n\t!!!\n" + "\tDOWNLOAD: \n";
String serviceName = this.serviceName;
if (serviceName != null) {
switch (serviceName) { switch (serviceName) {
case "derby": case "derby":
warn += "\tDerby: version >= 10.11.1.1 from https://mvnrepository.com/artifact/org.apache.derby/derby\n"; warn += "\tDerby: version >= 10.11.1.1 from https://mvnrepository.com/artifact/org.apache.derby/derby\n";
@ -317,6 +325,7 @@ public class JdbcConfiguration {
warn += "\tSQLite: version >= 3.16.1 from https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc\n"; warn += "\tSQLite: version >= 3.16.1 from https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc\n";
break; break;
} }
}
logger.warn(warn, serviceName); logger.warn(warn, serviceName);
} }
} }
@ -330,7 +339,7 @@ public class JdbcConfiguration {
return name; return name;
} }
public String getServiceName() { public @Nullable String getServiceName() {
return serviceName; return serviceName;
} }
@ -362,7 +371,7 @@ public class JdbcConfiguration {
return dBDAO; return dBDAO;
} }
public String getDbName() { public @Nullable String getDbName() {
return dbName; return dbName;
} }

View File

@ -21,6 +21,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.i18n.TimeZoneProvider;
@ -42,6 +43,7 @@ import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
* *
* @author Helmut Lehmeyer - Initial contribution * @author Helmut Lehmeyer - Initial contribution
*/ */
@NonNullByDefault
public class JdbcMapper { public class JdbcMapper {
private final Logger logger = LoggerFactory.getLogger(JdbcMapper.class); private final Logger logger = LoggerFactory.getLogger(JdbcMapper.class);
@ -50,7 +52,7 @@ public class JdbcMapper {
// Error counter - used to reconnect to database on error // Error counter - used to reconnect to database on error
protected int errCnt; protected int errCnt;
protected boolean initialized = false; protected boolean initialized = false;
protected JdbcConfiguration conf = null; protected @NonNullByDefault({}) JdbcConfiguration conf;
protected final Map<String, String> sqlTables = new HashMap<>(); protected final Map<String, String> sqlTables = new HashMap<>();
private long afterAccessMin = 10000; private long afterAccessMin = 10000;
private long afterAccessMax = 0; private long afterAccessMax = 0;
@ -72,10 +74,15 @@ public class JdbcMapper {
logger.debug( logger.debug(
"JDBC::pingDB asking db for name as absolutely first db action, after connection is established."); "JDBC::pingDB asking db for name as absolutely first db action, after connection is established.");
String dbName = conf.getDBDAO().doGetDB(); String dbName = conf.getDBDAO().doGetDB();
if (dbName == null) {
ret = false;
} else {
conf.setDbName(dbName); conf.setDbName(dbName);
ret = dbName.length() > 0; ret = dbName.length() > 0;
}
} else { } else {
ret = conf.getDBDAO().doPingDB() > 0; final @Nullable Integer result = conf.getDBDAO().doPingDB();
ret = result != null && result > 0;
} }
} }
logTime("pingDB", timerStart, System.currentTimeMillis()); logTime("pingDB", timerStart, System.currentTimeMillis());
@ -86,8 +93,8 @@ public class JdbcMapper {
logger.debug("JDBC::getDB"); logger.debug("JDBC::getDB");
long timerStart = System.currentTimeMillis(); long timerStart = System.currentTimeMillis();
String res = conf.getDBDAO().doGetDB(); String res = conf.getDBDAO().doGetDB();
logTime("pingDB", timerStart, System.currentTimeMillis()); logTime("getDB", timerStart, System.currentTimeMillis());
return res; return res != null ? res : "";
} }
public ItemsVO createNewEntryInItemsTable(ItemsVO vo) { public ItemsVO createNewEntryInItemsTable(ItemsVO vo) {
@ -154,10 +161,6 @@ public class JdbcMapper {
public Item storeItemValue(Item item, State itemState, @Nullable ZonedDateTime date) { public Item storeItemValue(Item item, State itemState, @Nullable ZonedDateTime date) {
logger.debug("JDBC::storeItemValue: item={} state={} date={}", item, itemState, date); logger.debug("JDBC::storeItemValue: item={} state={} date={}", item, itemState, date);
String tableName = getTable(item); String tableName = getTable(item);
if (tableName == null) {
logger.error("JDBC::store: Unable to store item '{}'.", item.getName());
return item;
}
long timerStart = System.currentTimeMillis(); long timerStart = System.currentTimeMillis();
if (date == null) { if (date == null) {
conf.getDBDAO().doStoreItemValue(item, itemState, new ItemVO(tableName, null)); conf.getDBDAO().doStoreItemValue(item, itemState, new ItemVO(tableName, null));
@ -173,40 +176,27 @@ public class JdbcMapper {
Item item) { Item item) {
logger.debug( logger.debug(
"JDBC::getHistItemFilterQuery filter='{}' numberDecimalcount='{}' table='{}' item='{}' itemName='{}'", "JDBC::getHistItemFilterQuery filter='{}' numberDecimalcount='{}' table='{}' item='{}' itemName='{}'",
(filter != null), numberDecimalcount, table, item, item.getName()); true, numberDecimalcount, table, item, item.getName());
if (table != null) {
long timerStart = System.currentTimeMillis(); long timerStart = System.currentTimeMillis();
List<HistoricItem> result = conf.getDBDAO().doGetHistItemFilterQuery(item, filter, numberDecimalcount, List<HistoricItem> result = conf.getDBDAO().doGetHistItemFilterQuery(item, filter, numberDecimalcount, table,
table, item.getName(), timeZoneProvider.getTimeZone()); item.getName(), timeZoneProvider.getTimeZone());
logTime("getHistItemFilterQuery", timerStart, System.currentTimeMillis()); logTime("getHistItemFilterQuery", timerStart, System.currentTimeMillis());
errCnt = 0; errCnt = 0;
return result; return result;
} else {
logger.error("JDBC::getHistItemFilterQuery: TABLE is NULL; cannot get data from non-existent table.");
}
return null;
} }
@SuppressWarnings("null")
public boolean deleteItemValues(FilterCriteria filter, String table) { public boolean deleteItemValues(FilterCriteria filter, String table) {
logger.debug("JDBC::deleteItemValues filter='{}' table='{}' itemName='{}'", (filter != null), table, logger.debug("JDBC::deleteItemValues filter='{}' table='{}' itemName='{}'", true, table, filter.getItemName());
filter.getItemName());
if (table != null) {
long timerStart = System.currentTimeMillis(); long timerStart = System.currentTimeMillis();
conf.getDBDAO().doDeleteItemValues(filter, table, timeZoneProvider.getTimeZone()); conf.getDBDAO().doDeleteItemValues(filter, table, timeZoneProvider.getTimeZone());
logTime("deleteItemValues", timerStart, System.currentTimeMillis()); logTime("deleteItemValues", timerStart, System.currentTimeMillis());
errCnt = 0; errCnt = 0;
return true; return true;
} else {
logger.error("JDBC::deleteItemValues: TABLE is NULL; cannot delete data from non-existent table.");
return false;
}
} }
/*********************** /***********************
* DATABASE CONNECTION * * DATABASE CONNECTION *
***********************/ ***********************/
@SuppressWarnings("null")
protected boolean openConnection() { protected boolean openConnection() {
logger.debug("JDBC::openConnection isDriverAvailable: {}", conf.isDriverAvailable()); logger.debug("JDBC::openConnection isDriverAvailable: {}", conf.isDriverAvailable());
if (conf.isDriverAvailable() && !conf.isDbConnected()) { if (conf.isDriverAvailable() && !conf.isDbConnected()) {
@ -216,8 +206,9 @@ public class JdbcMapper {
conf.setDbConnected(true); conf.setDbConnected(true);
return true; return true;
} catch (PoolInitializationException e) { } catch (PoolInitializationException e) {
if (e.getCause() instanceof SQLInvalidAuthorizationSpecException) { Throwable cause = e.getCause();
logger.warn("JDBC::openConnection: failed to open connection: {}", e.getCause().getMessage()); if (cause instanceof SQLInvalidAuthorizationSpecException) {
logger.warn("JDBC::openConnection: failed to open connection: {}", cause.getMessage());
} else { } else {
logger.warn("JDBC::openConnection: failed to open connection: {}", e.getMessage()); logger.warn("JDBC::openConnection: failed to open connection: {}", e.getMessage());
} }
@ -303,12 +294,6 @@ public class JdbcMapper {
logger.debug("JDBC::getTable: getTableName with rowId={} itemName={}", rowId, itemName); logger.debug("JDBC::getTable: getTableName with rowId={} itemName={}", rowId, itemName);
tableName = getTableName(rowId, itemName); tableName = getTableName(rowId, itemName);
// An error occurred adding the item name into the index list!
if (tableName == null) {
logger.error("JDBC::getTable: tableName was null; could not create a table for item '{}'", itemName);
return null;
}
// Create table for item // Create table for item
String dataType = conf.getDBDAO().getDataType(item); String dataType = conf.getDBDAO().getDataType(item);
ivo = new ItemVO(tableName, itemName); ivo = new ItemVO(tableName, itemName);

View File

@ -15,6 +15,8 @@ package org.openhab.persistence.jdbc.utils;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.knowm.yank.Yank; import org.knowm.yank.Yank;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -26,6 +28,7 @@ import com.zaxxer.hikari.HikariDataSource;
* *
* @author Helmut Lehmeyer - Initial contribution * @author Helmut Lehmeyer - Initial contribution
*/ */
@NonNullByDefault
public class DbMetaData { public class DbMetaData {
private final Logger logger = LoggerFactory.getLogger(DbMetaData.class); private final Logger logger = LoggerFactory.getLogger(DbMetaData.class);
@ -34,8 +37,8 @@ public class DbMetaData {
private int dbMinorVersion; private int dbMinorVersion;
private int driverMajorVersion; private int driverMajorVersion;
private int driverMinorVersion; private int driverMinorVersion;
private String dbProductName; private @Nullable String dbProductName;
private String dbProductVersion; private @Nullable String dbProductVersion;
public DbMetaData() { public DbMetaData() {
HikariDataSource h = Yank.getDefaultConnectionPool(); HikariDataSource h = Yank.getDefaultConnectionPool();
@ -116,11 +119,11 @@ public class DbMetaData {
return false; return false;
} }
public String getDbProductName() { public @Nullable String getDbProductName() {
return dbProductName; return dbProductName;
} }
public String getDbProductVersion() { public @Nullable String getDbProductVersion() {
return dbProductVersion; return dbProductVersion;
} }
} }

View File

@ -101,7 +101,7 @@ public class StringUtilsExt {
props = new Properties(def); props = new Properties(def);
} }
if (url == null || url.length() < 9) { if (url.length() < 9) {
return props; return props;
} }

View File

@ -14,6 +14,7 @@ package org.openhab.persistence.jdbc.db;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -79,32 +80,32 @@ public class JdbcBaseDAOTest {
public void testObjectAsStateReturnsValidState() { public void testObjectAsStateReturnsValidState() {
State decimalType = jdbcBaseDAO.objectAsState(new NumberItem("testNumberItem"), null, 7.3); State decimalType = jdbcBaseDAO.objectAsState(new NumberItem("testNumberItem"), null, 7.3);
assertInstanceOf(DecimalType.class, decimalType); assertInstanceOf(DecimalType.class, decimalType);
assertThat(decimalType, is(DecimalType.valueOf("7.3"))); assertEquals(DecimalType.valueOf("7.3"), decimalType);
State quantityType = jdbcBaseDAO.objectAsState(new NumberItem("testNumberItem"), SIUnits.CELSIUS, 7.3); State quantityType = jdbcBaseDAO.objectAsState(new NumberItem("testNumberItem"), SIUnits.CELSIUS, 7.3);
assertInstanceOf(QuantityType.class, quantityType); assertInstanceOf(QuantityType.class, quantityType);
assertThat(quantityType, is(QuantityType.valueOf("7.3 °C"))); assertEquals(QuantityType.valueOf("7.3 °C"), quantityType);
State dateTimeType = jdbcBaseDAO.objectAsState(new DateTimeItem("testDateTimeItem"), null, State dateTimeType = jdbcBaseDAO.objectAsState(new DateTimeItem("testDateTimeItem"), null,
java.sql.Timestamp.valueOf("2021-02-01 23:30:02.049")); java.sql.Timestamp.valueOf("2021-02-01 23:30:02.049"));
assertInstanceOf(DateTimeType.class, dateTimeType); assertInstanceOf(DateTimeType.class, dateTimeType);
assertThat(dateTimeType, is(DateTimeType.valueOf("2021-02-01T23:30:02.049"))); assertEquals(DateTimeType.valueOf("2021-02-01T23:30:02.049"), dateTimeType);
dateTimeType = jdbcBaseDAO.objectAsState(new DateTimeItem("testDateTimeItem"), null, dateTimeType = jdbcBaseDAO.objectAsState(new DateTimeItem("testDateTimeItem"), null,
LocalDateTime.parse("2021-02-01T23:30:02.049")); LocalDateTime.parse("2021-02-01T23:30:02.049"));
assertInstanceOf(DateTimeType.class, dateTimeType); assertInstanceOf(DateTimeType.class, dateTimeType);
assertThat(dateTimeType, is(DateTimeType.valueOf("2021-02-01T23:30:02.049"))); assertEquals(DateTimeType.valueOf("2021-02-01T23:30:02.049"), dateTimeType);
State hsbType = jdbcBaseDAO.objectAsState(new ColorItem("testColorItem"), null, "184,100,52"); State hsbType = jdbcBaseDAO.objectAsState(new ColorItem("testColorItem"), null, "184,100,52");
assertInstanceOf(HSBType.class, hsbType); assertInstanceOf(HSBType.class, hsbType);
assertThat(hsbType, is(HSBType.valueOf("184,100,52"))); assertEquals(HSBType.valueOf("184,100,52"), hsbType);
State percentType = jdbcBaseDAO.objectAsState(new DimmerItem("testDimmerItem"), null, 52); State percentType = jdbcBaseDAO.objectAsState(new DimmerItem("testDimmerItem"), null, 52);
assertInstanceOf(PercentType.class, percentType); assertInstanceOf(PercentType.class, percentType);
assertThat(percentType, is(PercentType.valueOf("52"))); assertEquals(PercentType.valueOf("52"), percentType);
percentType = jdbcBaseDAO.objectAsState(new RollershutterItem("testRollershutterItem"), null, 39); percentType = jdbcBaseDAO.objectAsState(new RollershutterItem("testRollershutterItem"), null, 39);
assertInstanceOf(PercentType.class, percentType); assertInstanceOf(PercentType.class, percentType);
assertThat(percentType, is(PercentType.valueOf("39"))); assertEquals(PercentType.valueOf("39"), percentType);
State openClosedType = jdbcBaseDAO.objectAsState(new ContactItem("testContactItem"), null, "OPEN"); State openClosedType = jdbcBaseDAO.objectAsState(new ContactItem("testContactItem"), null, "OPEN");
assertInstanceOf(OpenClosedType.class, openClosedType); assertInstanceOf(OpenClosedType.class, openClosedType);
@ -123,7 +124,7 @@ public class JdbcBaseDAOTest {
State stringListType = jdbcBaseDAO.objectAsState(new CallItem("testCallItem"), null, "0699222222,0179999998"); State stringListType = jdbcBaseDAO.objectAsState(new CallItem("testCallItem"), null, "0699222222,0179999998");
assertInstanceOf(StringListType.class, stringListType); assertInstanceOf(StringListType.class, stringListType);
assertThat(stringListType, is(StringListType.valueOf("0699222222,0179999998"))); assertEquals(StringListType.valueOf("0699222222,0179999998"), stringListType);
State expectedRawType = new RawType(new byte[0], "application/octet-stream"); State expectedRawType = new RawType(new byte[0], "application/octet-stream");
State rawType = jdbcBaseDAO.objectAsState(new ImageItem("testImageItem"), null, expectedRawType.toFullString()); State rawType = jdbcBaseDAO.objectAsState(new ImageItem("testImageItem"), null, expectedRawType.toFullString());
@ -132,11 +133,11 @@ public class JdbcBaseDAOTest {
State pointType = jdbcBaseDAO.objectAsState(new LocationItem("testLocationItem"), null, "1,2,3"); State pointType = jdbcBaseDAO.objectAsState(new LocationItem("testLocationItem"), null, "1,2,3");
assertInstanceOf(PointType.class, pointType); assertInstanceOf(PointType.class, pointType);
assertThat(pointType, is(PointType.valueOf("1,2,3"))); assertEquals(PointType.valueOf("1,2,3"), pointType);
State stringType = jdbcBaseDAO.objectAsState(new StringItem("testStringItem"), null, "String"); State stringType = jdbcBaseDAO.objectAsState(new StringItem("testStringItem"), null, "String");
assertInstanceOf(StringType.class, stringType); assertInstanceOf(StringType.class, stringType);
assertThat(stringType, is(StringType.valueOf("String"))); assertEquals(StringType.valueOf("String"), stringType);
} }
@Test @Test