/** * 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.internal; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import org.openhab.core.items.GroupItem; import org.openhab.core.items.Item; import org.openhab.core.items.ItemNotFoundException; import org.openhab.core.items.ItemRegistry; import org.openhab.core.persistence.FilterCriteria; import org.openhab.core.persistence.HistoricItem; import org.openhab.core.persistence.PersistenceService; import org.openhab.core.persistence.QueryablePersistenceService; import org.openhab.core.types.UnDefType; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Helmut Lehmeyer * @since 1.8.0 * * */ public class JdbcPersistenceService extends JdbcMapper implements QueryablePersistenceService { static final Logger logger = LoggerFactory.getLogger(JdbcPersistenceService.class); protected ItemRegistry itemRegistry; /** * The BundleContext. This is only valid when the bundle is ACTIVE. It is * set in the activate() method and must not be accessed anymore once the * deactivate() method was called or before activate() was called. */ @SuppressWarnings("unused") private BundleContext bundleContext; /** * Called by the SCR to activate the component with its configuration read * from CAS * * @param bundleContext * BundleContext of the Bundle that defines this component * @param configuration * Configuration properties for this component obtained from the * ConfigAdmin service */ public void activate(BundleContext bundleContext, Map<Object, Object> configuration) { logger.debug("JDBC::activate: persistence service activated"); this.bundleContext = bundleContext; updateConfig(configuration); } /** * Called by the SCR to deactivate the component when either the * configuration is removed or mandatory references are no longer satisfied * or the component has simply been stopped. * * @param reason * Reason code for the deactivation:<br> * <ul> * <li>0 – Unspecified * <li>1 – The component was disabled * <li>2 – A reference became unsatisfied * <li>3 – A configuration was changed * <li>4 – A configuration was deleted * <li>5 – The component was disposed * <li>6 – The bundle was stopped * </ul> */ public void deactivate(final int reason) { logger.debug("JDBC::deactivate: persistence bundle stopping. Disconnecting from database. reason={}", reason); // closeConnection(); this.bundleContext = null; initialized = false; } public void setItemRegistry(ItemRegistry itemRegistry) { logger.debug("JDBC::setItemRegistry"); this.itemRegistry = itemRegistry; } public void unsetItemRegistry(ItemRegistry itemRegistry) { logger.debug("JDBC::unsetItemRegistry"); // closeConnection(); this.itemRegistry = null; } /** * @{inheritDoc */ @Override public String getName() { logger.debug("JDBC::getName: returning name 'jdbc' for queryable persistence service."); return "jdbc"; } /** * @{inheritDoc */ @Override public void store(Item item) { store(item, null); } /** * @{inheritDoc */ @Override public void store(Item item, String alias) { // Don not store undefined/uninitialised data if (item.getState() instanceof UnDefType) { logger.warn("JDBC::store: ignore Item '{}' because it is UnDefType", item.getName()); return; } if (!checkDBAccessability()) { logger.warn( "JDBC::store: No connection to database. Cannot persist item '{}'! Will retry connecting to database when error count:{} equals errReconnectThreshold:{}", item, errCnt, conf.getErrReconnectThreshold()); return; } long timerStart = System.currentTimeMillis(); storeItemValue(item); logger.debug("JDBC: Stored item '{}' as '{}' in SQL database at {} in {} ms.", item.getName(), item.getState().toString(), (new java.util.Date()).toString(), System.currentTimeMillis() - timerStart); } /** * Queries the {@link PersistenceService} for data with a given filter * criteria * * @param filter * the filter to apply to the query * @return a time series of items */ @Override public Iterable<HistoricItem> query(FilterCriteria filter) { if (!checkDBAccessability()) { logger.warn("JDBC::query: database not connected, query aborted for item '{}'", filter.getItemName()); return Collections.emptyList(); } if (itemRegistry == null) { logger.error("JDBC::query: itemRegistry == null. Ignore and give up!"); return Collections.emptyList(); } // Get the item name from the filter // Also get the Item object so we can determine the type Item item = null; String itemName = filter.getItemName(); logger.debug("JDBC::query: item is {}", itemName); try { item = itemRegistry.getItem(itemName); } catch (ItemNotFoundException e1) { logger.error("JDBC::query: unable to get item for itemName: '{}'. Ignore and give up!", itemName); return Collections.emptyList(); } if (item instanceof GroupItem) { // For Group Item is BaseItem needed to get correct Type of Value. item = GroupItem.class.cast(item).getBaseItem(); logger.debug("JDBC::query: item is instanceof GroupItem '{}'", itemName); if (item == null) { logger.debug("JDBC::query: BaseItem of GroupItem is null. Ignore and give up!"); return Collections.emptyList(); } if (item instanceof GroupItem) { logger.debug("JDBC::query: BaseItem of GroupItem is a GroupItem too. Ignore and give up!"); return Collections.emptyList(); } } String table = sqlTables.get(itemName); if (table == null) { logger.warn( "JDBC::query: unable to find table for query, no data in database for item '{}'. Current number of tables in the database: {}", itemName, sqlTables.size()); // if enabled, table will be created immediately if (item != null) { logger.warn("JDBC::query: try to generate the table for item '{}'", itemName); table = getTable(item); } else { logger.warn("JDBC::query: no way to generate the table for item '{}'", itemName); return Collections.emptyList(); } } long timerStart = System.currentTimeMillis(); List<HistoricItem> items = new ArrayList<HistoricItem>(); items = getHistItemFilterQuery(filter, conf.getNumberDecimalcount(), table, item); logger.debug("JDBC::query: query for {} returned {} rows in {} ms", item.getName(), items.size(), System.currentTimeMillis() - timerStart); // Success errCnt = 0; return items; } /** * @{inheritDoc */ public void updateConfig(Map<Object, Object> configuration) { logger.debug("JDBC::updateConfig"); conf = new JdbcConfiguration(configuration); if (checkDBAccessability()) { checkDBSchema(); // connection has been established ... initialization completed! initialized = true; } else { initialized = false; } logger.debug("JDBC::updateConfig: configuration complete for service={}.", getName()); } }