2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.persistence.jdbc.internal;
15 import java.util.List;
16 import java.util.Locale;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.core.config.core.ConfigurableService;
23 import org.openhab.core.items.GroupItem;
24 import org.openhab.core.items.Item;
25 import org.openhab.core.items.ItemNotFoundException;
26 import org.openhab.core.items.ItemRegistry;
27 import org.openhab.core.persistence.FilterCriteria;
28 import org.openhab.core.persistence.HistoricItem;
29 import org.openhab.core.persistence.PersistenceItemInfo;
30 import org.openhab.core.persistence.PersistenceService;
31 import org.openhab.core.persistence.QueryablePersistenceService;
32 import org.openhab.core.persistence.strategy.PersistenceStrategy;
33 import org.openhab.core.types.UnDefType;
34 import org.osgi.framework.BundleContext;
35 import org.osgi.framework.Constants;
36 import org.osgi.service.component.annotations.Activate;
37 import org.osgi.service.component.annotations.Component;
38 import org.osgi.service.component.annotations.Deactivate;
39 import org.osgi.service.component.annotations.Reference;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * This is the implementation of the JDBC {@link PersistenceService}.
46 * @author Helmut Lehmeyer - Initial contribution
47 * @author Kai Kreuzer - Migration to 3.x
50 @Component(service = { PersistenceService.class,
51 QueryablePersistenceService.class }, configurationPid = "org.openhab.jdbc", //
52 property = Constants.SERVICE_PID + "=org.openhab.jdbc")
53 @ConfigurableService(category = "persistence", label = "JDBC Persistence Service", description_uri = JdbcPersistenceService.CONFIG_URI)
54 public class JdbcPersistenceService extends JdbcMapper implements QueryablePersistenceService {
56 protected static final String CONFIG_URI = "persistence:jdbc";
58 private final Logger logger = LoggerFactory.getLogger(JdbcPersistenceService.class);
60 private final ItemRegistry itemRegistry;
63 public JdbcPersistenceService(final @Reference ItemRegistry itemRegistry) {
64 this.itemRegistry = itemRegistry;
68 * Called by the SCR to activate the component with its configuration read
71 * @param bundleContext
72 * BundleContext of the Bundle that defines this component
73 * @param configuration
74 * Configuration properties for this component obtained from the
78 public void activate(BundleContext bundleContext, Map<Object, Object> configuration) {
79 logger.debug("JDBC::activate: persistence service activated");
80 updateConfig(configuration);
84 * Called by the SCR to deactivate the component when either the
85 * configuration is removed or mandatory references are no longer satisfied
86 * or the component has simply been stopped.
89 * Reason code for the deactivation:<br>
92 * <li>1 – The component was disabled
93 * <li>2 – A reference became unsatisfied
94 * <li>3 – A configuration was changed
95 * <li>4 – A configuration was deleted
96 * <li>5 – The component was disposed
97 * <li>6 – The bundle was stopped
101 public void deactivate(final int reason) {
102 logger.debug("JDBC::deactivate: persistence bundle stopping. Disconnecting from database. reason={}", reason);
103 // closeConnection();
108 public String getId() {
109 logger.debug("JDBC::getName: returning name 'jdbc' for queryable persistence service.");
114 public String getLabel(@Nullable Locale locale) {
119 public void store(Item item) {
127 public void store(Item item, @Nullable String alias) {
128 // Don not store undefined/uninitialised data
129 if (item.getState() instanceof UnDefType) {
130 logger.debug("JDBC::store: ignore Item '{}' because it is UnDefType", item.getName());
133 if (!checkDBAccessability()) {
135 "JDBC::store: No connection to database. Cannot persist item '{}'! Will retry connecting to database when error count:{} equals errReconnectThreshold:{}",
136 item, errCnt, conf.getErrReconnectThreshold());
139 long timerStart = System.currentTimeMillis();
140 storeItemValue(item);
141 logger.debug("JDBC: Stored item '{}' as '{}' in SQL database at {} in {} ms.", item.getName(),
142 item.getState().toString(), (new java.util.Date()).toString(), System.currentTimeMillis() - timerStart);
146 public Set<PersistenceItemInfo> getItemInfo() {
151 * Queries the {@link PersistenceService} for data with a given filter
155 * the filter to apply to the query
156 * @return a time series of items
159 public Iterable<HistoricItem> query(FilterCriteria filter) {
160 if (!checkDBAccessability()) {
161 logger.warn("JDBC::query: database not connected, query aborted for item '{}'", filter.getItemName());
165 // Get the item name from the filter
166 // Also get the Item object so we can determine the type
168 String itemName = filter.getItemName();
169 logger.debug("JDBC::query: item is {}", itemName);
171 item = itemRegistry.getItem(itemName);
172 } catch (ItemNotFoundException e1) {
173 logger.error("JDBC::query: unable to get item for itemName: '{}'. Ignore and give up!", itemName);
177 if (item instanceof GroupItem) {
178 // For Group Item is BaseItem needed to get correct Type of Value.
179 item = GroupItem.class.cast(item).getBaseItem();
180 logger.debug("JDBC::query: item is instanceof GroupItem '{}'", itemName);
182 logger.debug("JDBC::query: BaseItem of GroupItem is null. Ignore and give up!");
185 if (item instanceof GroupItem) {
186 logger.debug("JDBC::query: BaseItem of GroupItem is a GroupItem too. Ignore and give up!");
191 String table = sqlTables.get(itemName);
194 "JDBC::query: unable to find table for query, no data in database for item '{}'. Current number of tables in the database: {}",
195 itemName, sqlTables.size());
196 // if enabled, table will be created immediately
197 logger.warn("JDBC::query: try to generate the table for item '{}'", itemName);
198 table = getTable(item);
201 long timerStart = System.currentTimeMillis();
202 List<HistoricItem> items = getHistItemFilterQuery(filter, conf.getNumberDecimalcount(), table, item);
204 logger.debug("JDBC::query: query for {} returned {} rows in {} ms", item.getName(), items.size(),
205 System.currentTimeMillis() - timerStart);
212 public void updateConfig(Map<Object, Object> configuration) {
213 logger.debug("JDBC::updateConfig");
215 conf = new JdbcConfiguration(configuration);
216 if (conf.valid && checkDBAccessability()) {
218 // connection has been established ... initialization completed!
224 logger.debug("JDBC::updateConfig: configuration complete for service={}.", getId());
228 public List<PersistenceStrategy> getDefaultStrategies() {
229 return List.of(PersistenceStrategy.Globals.CHANGE);