/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.persistence.jdbc.db; import java.math.BigDecimal; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.knowm.yank.Yank; import org.openhab.core.items.GroupItem; import org.openhab.core.items.Item; import org.openhab.core.library.items.ColorItem; import org.openhab.core.library.items.ContactItem; import org.openhab.core.library.items.DateTimeItem; import org.openhab.core.library.items.DimmerItem; import org.openhab.core.library.items.NumberItem; import org.openhab.core.library.items.RollershutterItem; import org.openhab.core.library.items.StringItem; import org.openhab.core.library.items.SwitchItem; import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.HSBType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OpenClosedType; import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.StringType; import org.openhab.core.persistence.FilterCriteria; import org.openhab.core.persistence.FilterCriteria.Ordering; import org.openhab.core.persistence.HistoricItem; import org.openhab.core.types.State; import org.openhab.persistence.jdbc.model.ItemVO; import org.openhab.persistence.jdbc.model.ItemsVO; import org.openhab.persistence.jdbc.model.JdbcItem; import org.openhab.persistence.jdbc.utils.DbMetaData; import org.openhab.persistence.jdbc.utils.StringUtilsExt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Default Database Configuration class. * * @author Helmut Lehmeyer * @since 1.8.0 */ public class JdbcBaseDAO { private static final Logger logger = LoggerFactory.getLogger(JdbcBaseDAO.class); public Properties databaseProps = new Properties(); protected String urlSuffix = ""; public Map<String, String> sqlTypes = new HashMap<String, String>(); // Get Database Meta data protected DbMetaData dbMeta; protected String SQL_PING_DB; protected String SQL_GET_DB; protected String SQL_IF_TABLE_EXISTS; protected String SQL_CREATE_NEW_ENTRY_IN_ITEMS_TABLE; protected String SQL_CREATE_ITEMS_TABLE_IF_NOT; protected String SQL_DELETE_ITEMS_ENTRY; protected String SQL_GET_ITEMID_TABLE_NAMES; protected String SQL_GET_ITEM_TABLES; protected String SQL_CREATE_ITEM_TABLE; protected String SQL_INSERT_ITEM_VALUE; /******** * INIT * ********/ public JdbcBaseDAO() { initSqlTypes(); initDbProps(); initSqlQueries(); } /** * ## Get high precision by fractal seconds, examples ## * * mysql > 5.5 + mariadb > 5.2: * DROP TABLE FractionalSeconds; * CREATE TABLE FractionalSeconds (time TIMESTAMP(3), value TIMESTAMP(3)); * INSERT INTO FractionalSeconds (time, value) VALUES( NOW(3), '1999-01-09 20:11:11.126' ); * SELECT time FROM FractionalSeconds ORDER BY time DESC LIMIT 1; * * mysql <= 5.5 + mariadb <= 5.2: !!! NO high precision and fractal seconds !!! * DROP TABLE FractionalSeconds; * CREATE TABLE FractionalSeconds (time TIMESTAMP, value TIMESTAMP); * INSERT INTO FractionalSeconds (time, value) VALUES( NOW(), '1999-01-09 20:11:11.126' ); * SELECT time FROM FractionalSeconds ORDER BY time DESC LIMIT 1; * * derby: * DROP TABLE FractionalSeconds; * CREATE TABLE FractionalSeconds (time TIMESTAMP, value TIMESTAMP); * INSERT INTO FractionalSeconds (time, value) VALUES( CURRENT_TIMESTAMP, '1999-01-09 20:11:11.126' ); * SELECT time, value FROM FractionalSeconds; * * H2 + postgreSQL + hsqldb: * DROP TABLE FractionalSeconds; * CREATE TABLE FractionalSeconds (time TIMESTAMP, value TIMESTAMP); * INSERT INTO FractionalSeconds (time, value) VALUES( NOW(), '1999-01-09 20:11:11.126' ); * SELECT time, value FROM FractionalSeconds; * * Sqlite: * DROP TABLE FractionalSeconds; * CREATE TABLE FractionalSeconds (time TIMESTAMP, value TIMESTAMP); * INSERT INTO FractionalSeconds (time, value) VALUES( strftime('%Y-%m-%d %H:%M:%f' , 'now' , 'localtime'), * '1999-01-09 20:11:11.124' ); * SELECT time FROM FractionalSeconds ORDER BY time DESC LIMIT 1; * */ private void initSqlQueries() { logger.debug("JDBC::initSqlQueries: '{}'", this.getClass().getSimpleName()); SQL_PING_DB = "SELECT 1"; SQL_GET_DB = "SELECT DATABASE()"; SQL_IF_TABLE_EXISTS = "SHOW TABLES LIKE '#searchTable#'"; // Derby SQL_IF_TABLE_EXISTS = "SELECT * FROM SYS.SYSTABLES WHERE TABLENAME='#searchTable#'"; // h2 SQL_IF_TABLE_EXISTS = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='#searchTable#'"; // hsqldb SQL_IF_TABLE_EXISTS = "SELECT * FROM INFORMATION_SCHEMA.SYSTEM_TABLES WHERE // TABLE_NAME='#searchTable#'"; // hsqldb SQL_IF_TABLE_EXISTS = "SELECT * FROM INFORMATION_SCHEMA.SYSTEM_TABLES WHERE // TABLE_NAME='#searchTable#'"; // mysql SQL_IF_TABLE_EXISTS = "SHOW TABLES LIKE '#searchTable#'"; // postgresql SQL_IF_TABLE_EXISTS = "SELECT * FROM PG_TABLES WHERE TABLENAME='#searchTable#'"; // sqlite SQL_IF_TABLE_EXISTS = "SELECT name FROM sqlite_master WHERE type='table' AND name='#searchTable#'"; SQL_CREATE_NEW_ENTRY_IN_ITEMS_TABLE = "INSERT INTO #itemsManageTable# (ItemName) VALUES ('#itemname#')"; SQL_CREATE_ITEMS_TABLE_IF_NOT = "CREATE TABLE IF NOT EXISTS #itemsManageTable# (ItemId INT NOT NULL AUTO_INCREMENT,#colname# #coltype# NOT NULL,PRIMARY KEY (ItemId))"; SQL_DELETE_ITEMS_ENTRY = "DELETE FROM items WHERE ItemName=#itemname#"; SQL_GET_ITEMID_TABLE_NAMES = "SELECT itemid, itemname FROM #itemsManageTable#"; SQL_GET_ITEM_TABLES = "SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_schema=#jdbcUriDatabaseName# AND NOT table_name=#itemsManageTable#"; SQL_CREATE_ITEM_TABLE = "CREATE TABLE IF NOT EXISTS #tableName# (time #tablePrimaryKey# NOT NULL, value #dbType#, PRIMARY KEY(time))"; SQL_INSERT_ITEM_VALUE = "INSERT INTO #tableName# (TIME, VALUE) VALUES( #tablePrimaryValue#, ? ) ON DUPLICATE KEY UPDATE VALUE= ?"; } /** * INFO: http://www.java2s.com/Code/Java/Database-SQL-JDBC/StandardSQLDataTypeswithTheirJavaEquivalents.htm */ private void initSqlTypes() { logger.debug("JDBC::initSqlTypes: Initialize the type array"); sqlTypes.put("CALLITEM", "VARCHAR(200)"); sqlTypes.put("COLORITEM", "VARCHAR(70)"); sqlTypes.put("CONTACTITEM", "VARCHAR(6)"); sqlTypes.put("DATETIMEITEM", "TIMESTAMP"); sqlTypes.put("DIMMERITEM", "TINYINT"); sqlTypes.put("LOCATIONITEM", "VARCHAR(30)"); sqlTypes.put("NUMBERITEM", "DOUBLE"); sqlTypes.put("ROLLERSHUTTERITEM", "TINYINT"); sqlTypes.put("STRINGITEM", "VARCHAR(65500)");// jdbc max 21845 sqlTypes.put("SWITCHITEM", "VARCHAR(6)"); sqlTypes.put("tablePrimaryKey", "TIMESTAMP"); sqlTypes.put("tablePrimaryValue", "NOW()"); } /** * INFO: https://github.com/brettwooldridge/HikariCP * * driverClassName (used with jdbcUrl): * Derby: org.apache.derby.jdbc.EmbeddedDriver * H2: org.h2.Driver * HSQLDB: org.hsqldb.jdbcDriver * Jaybird: org.firebirdsql.jdbc.FBDriver * MariaDB: org.mariadb.jdbc.Driver * MySQL: com.mysql.jdbc.Driver * MaxDB: com.sap.dbtech.jdbc.DriverSapDB * PostgreSQL: org.postgresql.Driver * SyBase: com.sybase.jdbc3.jdbc.SybDriver * SqLite: org.sqlite.JDBC * * dataSourceClassName (for alternative Configuration): * Derby: org.apache.derby.jdbc.ClientDataSource * H2: org.h2.jdbcx.JdbcDataSource * HSQLDB: org.hsqldb.jdbc.JDBCDataSource * Jaybird: org.firebirdsql.pool.FBSimpleDataSource * MariaDB, MySQL: org.mariadb.jdbc.MySQLDataSource * MaxDB: com.sap.dbtech.jdbc.DriverSapDB * PostgreSQL: org.postgresql.ds.PGSimpleDataSource * SyBase: com.sybase.jdbc4.jdbc.SybDataSource * SqLite: org.sqlite.SQLiteDataSource * * HikariPool - configuration Example: * allowPoolSuspension.............false * autoCommit......................true * catalog......................... * connectionInitSql............... * connectionTestQuery............. * connectionTimeout...............30000 * dataSource...................... * dataSourceClassName............. * dataSourceJNDI.................. * dataSourceProperties............{password=<masked>} * driverClassName................. * healthCheckProperties...........{} * healthCheckRegistry............. * idleTimeout.....................600000 * initializationFailFast..........true * isolateInternalQueries..........false * jdbc4ConnectionTest.............false * jdbcUrl.........................jdbc:mysql://192.168.0.1:3306/test * leakDetectionThreshold..........0 * maxLifetime.....................1800000 * maximumPoolSize.................10 * metricRegistry.................. * metricsTrackerFactory........... * minimumIdle.....................10 * password........................<masked> * poolName........................HikariPool-0 * readOnly........................false * registerMbeans..................false * scheduledExecutorService........ * threadFactory................... * transactionIsolation............ * username........................xxxx * validationTimeout...............5000 */ private void initDbProps() { // databaseProps.setProperty("dataSource.url", "jdbc:mysql://192.168.0.1:3306/test"); // databaseProps.setProperty("dataSource.user", "test"); // databaseProps.setProperty("dataSource.password", "test"); // Most relevant Performance values // maximumPoolSize to 20, minimumIdle to 5, and idleTimeout to 2 minutes. // databaseProps.setProperty("maximumPoolSize", ""+maximumPoolSize); // databaseProps.setProperty("minimumIdle", ""+minimumIdle); // databaseProps.setProperty("idleTimeout", ""+idleTimeout); // databaseProps.setProperty("connectionTimeout",""+connectionTimeout); // databaseProps.setProperty("idleTimeout", ""+idleTimeout); // databaseProps.setProperty("maxLifetime", ""+maxLifetime); // databaseProps.setProperty("validationTimeout",""+validationTimeout); } public void initAfterFirstDbConnection() { logger.debug("JDBC::initAfterFirstDbConnection: Initializing step, after db is connected."); // Initialize sqlTypes, depending on DB version for example dbMeta = new DbMetaData();// get DB information } /************** * ITEMS DAOs * **************/ public Integer doPingDB() { return Yank.queryScalar(SQL_PING_DB, Integer.class, null); } public String doGetDB() { return Yank.queryScalar(SQL_GET_DB, String.class, null); } public boolean doIfTableExists(ItemsVO vo) { String sql = StringUtilsExt.replaceArrayMerge(SQL_IF_TABLE_EXISTS, new String[] { "#searchTable#" }, new String[] { vo.getItemsManageTable() }); logger.debug("JDBC::doIfTableExists sql={}", sql); return Yank.queryScalar(sql, String.class, null) != null; } public Long doCreateNewEntryInItemsTable(ItemsVO vo) { String sql = StringUtilsExt.replaceArrayMerge(SQL_CREATE_NEW_ENTRY_IN_ITEMS_TABLE, new String[] { "#itemsManageTable#", "#itemname#" }, new String[] { vo.getItemsManageTable(), vo.getItemname() }); logger.debug("JDBC::doCreateNewEntryInItemsTable sql={}", sql); return Yank.insert(sql, null); } public ItemsVO doCreateItemsTableIfNot(ItemsVO vo) { String sql = StringUtilsExt.replaceArrayMerge(SQL_CREATE_ITEMS_TABLE_IF_NOT, new String[] { "#itemsManageTable#", "#colname#", "#coltype#" }, new String[] { vo.getItemsManageTable(), vo.getColname(), vo.getColtype() }); logger.debug("JDBC::doCreateItemsTableIfNot sql={}", sql); Yank.execute(sql, null); return vo; } public void doDeleteItemsEntry(ItemsVO vo) { String sql = StringUtilsExt.replaceArrayMerge(SQL_DELETE_ITEMS_ENTRY, new String[] { "#itemname#" }, new String[] { vo.getItemname() }); logger.debug("JDBC::doDeleteItemsEntry sql={}", sql); Yank.execute(sql, null); } public List<ItemsVO> doGetItemIDTableNames(ItemsVO vo) { String sql = StringUtilsExt.replaceArrayMerge(SQL_GET_ITEMID_TABLE_NAMES, new String[] { "#itemsManageTable#" }, new String[] { vo.getItemsManageTable() }); logger.debug("JDBC::doGetItemIDTableNames sql={}", sql); return Yank.queryBeanList(sql, ItemsVO.class, null); } public List<ItemsVO> doGetItemTables(ItemsVO vo) { String sql = StringUtilsExt.replaceArrayMerge(SQL_GET_ITEM_TABLES, new String[] { "#jdbcUriDatabaseName#", "#itemsManageTable#" }, new String[] { vo.getJdbcUriDatabaseName(), vo.getItemsManageTable() }); logger.debug("JDBC::doGetItemTables sql={}", sql); return Yank.queryBeanList(sql, ItemsVO.class, null); } /************* * ITEM DAOs * *************/ public void doUpdateItemTableNames(List<ItemVO> vol) { String sql = updateItemTableNamesProvider(vol); Yank.execute(sql, null); } public void doCreateItemTable(ItemVO vo) { String sql = StringUtilsExt.replaceArrayMerge(SQL_CREATE_ITEM_TABLE, new String[] { "#tableName#", "#dbType#", "#tablePrimaryKey#" }, new String[] { vo.getTableName(), vo.getDbType(), sqlTypes.get("tablePrimaryKey") }); Yank.execute(sql, null); } public void doStoreItemValue(Item item, ItemVO vo) { vo = storeItemValueProvider(item, vo); String sql = StringUtilsExt.replaceArrayMerge(SQL_INSERT_ITEM_VALUE, new String[] { "#tableName#", "#tablePrimaryValue#" }, new String[] { vo.getTableName(), sqlTypes.get("tablePrimaryValue") }); Object[] params = new Object[] { vo.getValue(), vo.getValue() }; logger.debug("JDBC::doStoreItemValue sql={} value='{}'", sql, vo.getValue()); Yank.execute(sql, params); } public List<HistoricItem> doGetHistItemFilterQuery(Item item, FilterCriteria filter, int numberDecimalcount, String table, String name) { String sql = histItemFilterQueryProvider(filter, numberDecimalcount, table, name); logger.debug("JDBC::doGetHistItemFilterQuery sql={}", sql); List<Object[]> m = Yank.queryObjectArrays(sql, null); List<HistoricItem> items = new ArrayList<HistoricItem>(); for (int i = 0; i < m.size(); i++) { items.add(new JdbcItem(item.getName(), getState(item, m.get(i)[1]), objectAsDate(m.get(i)[0]))); } return items; } /************* * Providers * *************/ static final DateTimeFormatter jdbcDateFormat = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); private String histItemFilterQueryProvider(FilterCriteria filter, int numberDecimalcount, String table, String simpleName) { logger.debug( "JDBC::getHistItemFilterQueryProvider filter = {}, numberDecimalcount = {}, table = {}, simpleName = {}", filter.toString(), numberDecimalcount, table, simpleName); String filterString = ""; if (filter.getBeginDate() != null) { filterString += filterString.isEmpty() ? " WHERE" : " AND"; filterString += " TIME>'" + jdbcDateFormat.print(new DateTime(filter.getBeginDate().getTime())) + "'"; } if (filter.getEndDate() != null) { filterString += filterString.isEmpty() ? " WHERE" : " AND"; filterString += " TIME<'" + jdbcDateFormat.print(new DateTime(filter.getEndDate().getTime())) + "'"; } filterString += (filter.getOrdering() == Ordering.ASCENDING) ? " ORDER BY time ASC" : " ORDER BY time DESC "; if (filter.getPageSize() != 0x7fffffff) { filterString += " LIMIT " + filter.getPageNumber() * filter.getPageSize() + "," + filter.getPageSize(); } // SELECT time, ROUND(value,3) FROM number_item_0114 ORDER BY time DESC LIMIT 0,1 // rounding HALF UP String queryString = "NUMBERITEM".equalsIgnoreCase(simpleName) && numberDecimalcount > -1 ? "SELECT time, ROUND(value," + numberDecimalcount + ") FROM " + table : "SELECT time, value FROM " + table; if (!filterString.isEmpty()) { queryString += filterString; } logger.debug("JDBC::query queryString = {}", queryString); return queryString; } private String updateItemTableNamesProvider(List<ItemVO> namesList) { logger.debug("JDBC::updateItemTableNamesProvider namesList.size = {}", namesList.size()); String queryString = ""; for (int i = 0; i < namesList.size(); i++) { ItemVO it = namesList.get(i); queryString += "ALTER TABLE " + it.getTableName() + " RENAME TO " + it.getNewTableName() + ";"; } logger.debug("JDBC::query queryString = {}", queryString); return queryString; } protected ItemVO storeItemValueProvider(Item item, ItemVO vo) { String itemType = getItemType(item); logger.debug("JDBC::storeItemValueProvider: item '{}' as Type '{}' in '{}' with state '{}'", item.getName(), itemType, vo.getTableName(), item.getState().toString()); // insertItemValue logger.debug("JDBC::storeItemValueProvider: getState: '{}'", item.getState().toString()); if ("COLORITEM".equals(itemType)) { vo.setValueTypes(getSqlTypes().get(itemType), java.lang.String.class); vo.setValue(item.getState().toString()); } else if ("NUMBERITEM".equals(itemType)) { String it = getSqlTypes().get(itemType); if (it.toUpperCase().contains("DOUBLE")) { vo.setValueTypes(it, java.lang.Double.class); Number newVal = ((DecimalType) item.getState()); logger.debug("JDBC::storeItemValueProvider: newVal.doubleValue: '{}'", newVal.doubleValue()); vo.setValue(newVal.doubleValue()); } else if (it.toUpperCase().contains("DECIMAL") || it.toUpperCase().contains("NUMERIC")) { vo.setValueTypes(it, java.math.BigDecimal.class); DecimalType newVal = ((DecimalType) item.getState()); logger.debug("JDBC::storeItemValueProvider: newVal.toBigDecimal: '{}'", newVal.toBigDecimal()); vo.setValue(newVal.toBigDecimal()); } else if (it.toUpperCase().contains("INT")) { vo.setValueTypes(it, java.lang.Integer.class); Number newVal = ((DecimalType) item.getState()); logger.debug("JDBC::storeItemValueProvider: newVal.intValue: '{}'", newVal.intValue()); vo.setValue(newVal.intValue()); } else {// fall back to String vo.setValueTypes(it, java.lang.String.class); logger.warn("JDBC::storeItemValueProvider: item.getState().toString(): '{}'", item.getState().toString()); vo.setValue(item.getState().toString()); } } else if ("ROLLERSHUTTERITEM".equals(itemType) || "DIMMERITEM".equals(itemType)) { vo.setValueTypes(getSqlTypes().get(itemType), java.lang.Integer.class); Number newVal = ((DecimalType) item.getState()); logger.debug("JDBC::storeItemValueProvider: newVal.intValue: '{}'", newVal.intValue()); vo.setValue(newVal.intValue()); } else if ("DATETIMEITEM".equals(itemType)) { // vo.setValueTypes(getSqlTypes().get(itemType), java.util.Date.class); vo.setValueTypes(getSqlTypes().get(itemType), java.sql.Date.class); Calendar x = ((DateTimeType) item.getState()).getCalendar(); java.sql.Date d = new java.sql.Date(x.getTimeInMillis()); logger.debug("JDBC::storeItemValueProvider: DateTimeItem: '{}'", d); vo.setValue(d); } else { /* * !!ATTENTION!! * * 1. DimmerItem.getStateAs(PercentType.class).toString() always * returns 0 * RollershutterItem.getStateAs(PercentType.class).toString() works * as expected * * 2. (item instanceof ColorItem) == (item instanceof DimmerItem) = * true Therefore for instance tests ColorItem always has to be * tested before DimmerItem * * !!ATTENTION!! */ // All other items should return the best format by default vo.setValueTypes(getSqlTypes().get(itemType), java.lang.String.class); logger.debug("JDBC::storeItemValueProvider: other: item.getState().toString(): '{}'", item.getState().toString()); vo.setValue(item.getState().toString()); } return vo; } /***************** * H E L P E R S * *****************/ protected State getState(Item item, Object v) { String clazz = v.getClass().getSimpleName(); logger.debug("JDBC::ItemResultHandler::handleResult getState value = '{}', getClass = '{}', clazz = '{}'", v.toString(), v.getClass(), clazz); if (item instanceof NumberItem) { String it = getSqlTypes().get("NUMBERITEM"); if (it.toUpperCase().contains("DOUBLE")) { return new DecimalType(((Number) v).doubleValue()); } else if (it.toUpperCase().contains("DECIMAL") || it.toUpperCase().contains("NUMERIC")) { return new DecimalType((BigDecimal) v); } else if (it.toUpperCase().contains("INT")) { return new DecimalType(((Integer) v).intValue()); } return DecimalType.valueOf(((String) v).toString()); } else if (item instanceof ColorItem) { return HSBType.valueOf(((String) v).toString()); } else if (item instanceof DimmerItem) { return new PercentType(objectAsInteger(v)); } else if (item instanceof SwitchItem) { return OnOffType.valueOf(((String) v).toString().trim()); } else if (item instanceof ContactItem) { return OpenClosedType.valueOf(((String) v).toString().trim()); } else if (item instanceof RollershutterItem) { return new PercentType(objectAsInteger(v)); } else if (item instanceof DateTimeItem) { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(objectAsLong(v)); return new DateTimeType(calendar); } else if (item instanceof StringItem) { return StringType.valueOf(((String) v).toString()); } else {// Call, Location, String return StringType.valueOf(((String) v).toString()); } } protected Date objectAsDate(Object v) { if (v instanceof java.lang.String) { // toInstant is Java8 only: return Date.from(Timestamp.valueOf(v.toString()).toInstant()); return new Date(Timestamp.valueOf(v.toString()).getTime()); } // toInstant is Java8 only: return Date.from(((Timestamp) v).toInstant()); return new Date(((Timestamp) v).getTime()); } protected Long objectAsLong(Object v) { if (v instanceof Long) { return ((Number) v).longValue(); } else if (v instanceof java.sql.Date) { return ((java.sql.Date) v).getTime(); } return ((java.sql.Timestamp) v).getTime(); } protected Integer objectAsInteger(Object v) { if (v instanceof Byte) { return ((Byte) v).intValue(); } return ((Integer) v).intValue(); } public String getItemType(Item i) { Item item = i; String def = "STRINGITEM"; if (i instanceof GroupItem) { item = ((GroupItem) i).getBaseItem(); if (item == null) { // if GroupItem:<ItemType> is not defined in // *.items using StringType // logger.debug("JDBC: BaseItem GroupItem:<ItemType> is not // defined in *.items searching for first Member and try to use // as ItemType"); logger.debug( "JDBC::getItemType: Cannot detect ItemType for {} because the GroupItems' base type isn't set in *.items File.", i.getName()); item = ((GroupItem) i).getMembers().get(0); if (item == null) { logger.debug( "JDBC::getItemType: No ItemType found for first Child-Member of GroupItem {}, use ItemType for STRINGITEM as Fallback", i.getName()); return def; } } } String itemType = item.getClass().getSimpleName().toUpperCase(); logger.debug("JDBC::getItemType: Try to use ItemType {} for Item {}", itemType, i.getName()); if (sqlTypes.get(itemType) == null) { logger.warn( "JDBC::getItemType: No sqlType found for ItemType {}, use ItemType for STRINGITEM as Fallback for {}", itemType, i.getName()); return def; } return itemType; } /****************************** * public Getters and Setters * ******************************/ public Map<String, String> getSqlTypes() { return sqlTypes; } public String getDataType(Item item) { return sqlTypes.get(getItemType(item)); } }