]> git.basschouten.com Git - openhab-addons.git/blob
def594b2117a7d97f72f4d2f537b4359a9a1a89f
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.persistence.jdbc.internal;
14
15 import java.util.List;
16 import java.util.Locale;
17 import java.util.Map;
18 import java.util.Set;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.core.items.GroupItem;
23 import org.openhab.core.items.Item;
24 import org.openhab.core.items.ItemNotFoundException;
25 import org.openhab.core.items.ItemRegistry;
26 import org.openhab.core.persistence.FilterCriteria;
27 import org.openhab.core.persistence.HistoricItem;
28 import org.openhab.core.persistence.PersistenceItemInfo;
29 import org.openhab.core.persistence.PersistenceService;
30 import org.openhab.core.persistence.QueryablePersistenceService;
31 import org.openhab.core.persistence.strategy.PersistenceStrategy;
32 import org.openhab.core.types.UnDefType;
33 import org.osgi.framework.BundleContext;
34 import org.osgi.service.component.annotations.Activate;
35 import org.osgi.service.component.annotations.Component;
36 import org.osgi.service.component.annotations.ConfigurationPolicy;
37 import org.osgi.service.component.annotations.Deactivate;
38 import org.osgi.service.component.annotations.Reference;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * This is the implementation of the JDBC {@link PersistenceService}.
44  *
45  * @author Helmut Lehmeyer - Initial contribution
46  * @author Kai Kreuzer - Migration to 3.x
47  */
48 @NonNullByDefault
49 @Component(service = { PersistenceService.class,
50         QueryablePersistenceService.class }, configurationPid = "org.openhab.jdbc", configurationPolicy = ConfigurationPolicy.REQUIRE)
51 public class JdbcPersistenceService extends JdbcMapper implements QueryablePersistenceService {
52
53     private final Logger logger = LoggerFactory.getLogger(JdbcPersistenceService.class);
54
55     private final ItemRegistry itemRegistry;
56
57     @Activate
58     public JdbcPersistenceService(final @Reference ItemRegistry itemRegistry) {
59         this.itemRegistry = itemRegistry;
60     }
61
62     /**
63      * Called by the SCR to activate the component with its configuration read
64      * from CAS
65      *
66      * @param bundleContext
67      *            BundleContext of the Bundle that defines this component
68      * @param configuration
69      *            Configuration properties for this component obtained from the
70      *            ConfigAdmin service
71      */
72     @Activate
73     public void activate(BundleContext bundleContext, Map<Object, Object> configuration) {
74         logger.debug("JDBC::activate: persistence service activated");
75         updateConfig(configuration);
76     }
77
78     /**
79      * Called by the SCR to deactivate the component when either the
80      * configuration is removed or mandatory references are no longer satisfied
81      * or the component has simply been stopped.
82      *
83      * @param reason
84      *            Reason code for the deactivation:<br>
85      *            <ul>
86      *            <li>0 – Unspecified
87      *            <li>1 – The component was disabled
88      *            <li>2 – A reference became unsatisfied
89      *            <li>3 – A configuration was changed
90      *            <li>4 – A configuration was deleted
91      *            <li>5 – The component was disposed
92      *            <li>6 – The bundle was stopped
93      *            </ul>
94      */
95     @Deactivate
96     public void deactivate(final int reason) {
97         logger.debug("JDBC::deactivate:  persistence bundle stopping. Disconnecting from database. reason={}", reason);
98         // closeConnection();
99         initialized = false;
100     }
101
102     @Override
103     public String getId() {
104         logger.debug("JDBC::getName: returning name 'jdbc' for queryable persistence service.");
105         return "jdbc";
106     }
107
108     @Override
109     public String getLabel(@Nullable Locale locale) {
110         return "JDBC";
111     }
112
113     @Override
114     public void store(Item item) {
115         store(item, null);
116     }
117
118     /**
119      * @{inheritDoc
120      */
121     @Override
122     public void store(Item item, @Nullable String alias) {
123         // Don not store undefined/uninitialised data
124         if (item.getState() instanceof UnDefType) {
125             logger.debug("JDBC::store: ignore Item '{}' because it is UnDefType", item.getName());
126             return;
127         }
128         if (!checkDBAccessability()) {
129             logger.warn(
130                     "JDBC::store:  No connection to database. Cannot persist item '{}'! Will retry connecting to database when error count:{} equals errReconnectThreshold:{}",
131                     item, errCnt, conf.getErrReconnectThreshold());
132             return;
133         }
134         long timerStart = System.currentTimeMillis();
135         storeItemValue(item);
136         logger.debug("JDBC: Stored item '{}' as '{}' in SQL database at {} in {} ms.", item.getName(),
137                 item.getState().toString(), (new java.util.Date()).toString(), System.currentTimeMillis() - timerStart);
138     }
139
140     @Override
141     public Set<PersistenceItemInfo> getItemInfo() {
142         return getItems();
143     }
144
145     /**
146      * Queries the {@link PersistenceService} for data with a given filter
147      * criteria
148      *
149      * @param filter
150      *            the filter to apply to the query
151      * @return a time series of items
152      */
153     @Override
154     public Iterable<HistoricItem> query(FilterCriteria filter) {
155         if (!checkDBAccessability()) {
156             logger.warn("JDBC::query: database not connected, query aborted for item '{}'", filter.getItemName());
157             return List.of();
158         }
159
160         // Get the item name from the filter
161         // Also get the Item object so we can determine the type
162         Item item = null;
163         String itemName = filter.getItemName();
164         logger.debug("JDBC::query: item is {}", itemName);
165         try {
166             item = itemRegistry.getItem(itemName);
167         } catch (ItemNotFoundException e1) {
168             logger.error("JDBC::query: unable to get item for itemName: '{}'. Ignore and give up!", itemName);
169             return List.of();
170         }
171
172         if (item instanceof GroupItem) {
173             // For Group Item is BaseItem needed to get correct Type of Value.
174             item = GroupItem.class.cast(item).getBaseItem();
175             logger.debug("JDBC::query: item is instanceof GroupItem '{}'", itemName);
176             if (item == null) {
177                 logger.debug("JDBC::query: BaseItem of GroupItem is null. Ignore and give up!");
178                 return List.of();
179             }
180             if (item instanceof GroupItem) {
181                 logger.debug("JDBC::query: BaseItem of GroupItem is a GroupItem too. Ignore and give up!");
182                 return List.of();
183             }
184         }
185
186         String table = sqlTables.get(itemName);
187         if (table == null) {
188             logger.warn(
189                     "JDBC::query: unable to find table for query, no data in database for item '{}'. Current number of tables in the database: {}",
190                     itemName, sqlTables.size());
191             // if enabled, table will be created immediately
192             logger.warn("JDBC::query: try to generate the table for item '{}'", itemName);
193             table = getTable(item);
194         }
195
196         long timerStart = System.currentTimeMillis();
197         List<HistoricItem> items = getHistItemFilterQuery(filter, conf.getNumberDecimalcount(), table, item);
198
199         logger.debug("JDBC::query: query for {} returned {} rows in {} ms", item.getName(), items.size(),
200                 System.currentTimeMillis() - timerStart);
201
202         // Success
203         errCnt = 0;
204         return items;
205     }
206
207     public void updateConfig(Map<Object, Object> configuration) {
208         logger.debug("JDBC::updateConfig");
209
210         conf = new JdbcConfiguration(configuration);
211         if (conf.valid && checkDBAccessability()) {
212             checkDBSchema();
213             // connection has been established ... initialization completed!
214             initialized = true;
215         } else {
216             initialized = false;
217         }
218
219         logger.debug("JDBC::updateConfig: configuration complete for service={}.", getId());
220     }
221
222     @Override
223     public List<PersistenceStrategy> getDefaultStrategies() {
224         return List.of(PersistenceStrategy.Globals.CHANGE);
225     }
226 }