]> git.basschouten.com Git - openhab-addons.git/blob
e80bc4c63940a3745d02fbef6ca65a4b937faa92
[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.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;
42
43 /**
44  * This is the implementation of the JDBC {@link PersistenceService}.
45  *
46  * @author Helmut Lehmeyer - Initial contribution
47  * @author Kai Kreuzer - Migration to 3.x
48  */
49 @NonNullByDefault
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 {
55
56     protected static final String CONFIG_URI = "persistence:jdbc";
57
58     private final Logger logger = LoggerFactory.getLogger(JdbcPersistenceService.class);
59
60     private final ItemRegistry itemRegistry;
61
62     @Activate
63     public JdbcPersistenceService(final @Reference ItemRegistry itemRegistry) {
64         this.itemRegistry = itemRegistry;
65     }
66
67     /**
68      * Called by the SCR to activate the component with its configuration read
69      * from CAS
70      *
71      * @param bundleContext
72      *            BundleContext of the Bundle that defines this component
73      * @param configuration
74      *            Configuration properties for this component obtained from the
75      *            ConfigAdmin service
76      */
77     @Activate
78     public void activate(BundleContext bundleContext, Map<Object, Object> configuration) {
79         logger.debug("JDBC::activate: persistence service activated");
80         updateConfig(configuration);
81     }
82
83     /**
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.
87      *
88      * @param reason
89      *            Reason code for the deactivation:<br>
90      *            <ul>
91      *            <li>0 – Unspecified
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
98      *            </ul>
99      */
100     @Deactivate
101     public void deactivate(final int reason) {
102         logger.debug("JDBC::deactivate:  persistence bundle stopping. Disconnecting from database. reason={}", reason);
103         // closeConnection();
104         initialized = false;
105     }
106
107     @Override
108     public String getId() {
109         logger.debug("JDBC::getName: returning name 'jdbc' for queryable persistence service.");
110         return "jdbc";
111     }
112
113     @Override
114     public String getLabel(@Nullable Locale locale) {
115         return "JDBC";
116     }
117
118     @Override
119     public void store(Item item) {
120         store(item, null);
121     }
122
123     /**
124      * @{inheritDoc
125      */
126     @Override
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());
131             return;
132         }
133         if (!checkDBAccessability()) {
134             logger.warn(
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());
137             return;
138         }
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);
143     }
144
145     @Override
146     public Set<PersistenceItemInfo> getItemInfo() {
147         return getItems();
148     }
149
150     /**
151      * Queries the {@link PersistenceService} for data with a given filter
152      * criteria
153      *
154      * @param filter
155      *            the filter to apply to the query
156      * @return a time series of items
157      */
158     @Override
159     public Iterable<HistoricItem> query(FilterCriteria filter) {
160         if (!checkDBAccessability()) {
161             logger.warn("JDBC::query: database not connected, query aborted for item '{}'", filter.getItemName());
162             return List.of();
163         }
164
165         // Get the item name from the filter
166         // Also get the Item object so we can determine the type
167         Item item = null;
168         String itemName = filter.getItemName();
169         logger.debug("JDBC::query: item is {}", itemName);
170         try {
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);
174             return List.of();
175         }
176
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);
181             if (item == null) {
182                 logger.debug("JDBC::query: BaseItem of GroupItem is null. Ignore and give up!");
183                 return List.of();
184             }
185             if (item instanceof GroupItem) {
186                 logger.debug("JDBC::query: BaseItem of GroupItem is a GroupItem too. Ignore and give up!");
187                 return List.of();
188             }
189         }
190
191         String table = sqlTables.get(itemName);
192         if (table == null) {
193             logger.warn(
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);
199         }
200
201         long timerStart = System.currentTimeMillis();
202         List<HistoricItem> items = getHistItemFilterQuery(filter, conf.getNumberDecimalcount(), table, item);
203
204         logger.debug("JDBC::query: query for {} returned {} rows in {} ms", item.getName(), items.size(),
205                 System.currentTimeMillis() - timerStart);
206
207         // Success
208         errCnt = 0;
209         return items;
210     }
211
212     public void updateConfig(Map<Object, Object> configuration) {
213         logger.debug("JDBC::updateConfig");
214
215         conf = new JdbcConfiguration(configuration);
216         if (conf.valid && checkDBAccessability()) {
217             checkDBSchema();
218             // connection has been established ... initialization completed!
219             initialized = true;
220         } else {
221             initialized = false;
222         }
223
224         logger.debug("JDBC::updateConfig: configuration complete for service={}.", getId());
225     }
226
227     @Override
228     public List<PersistenceStrategy> getDefaultStrategies() {
229         return List.of(PersistenceStrategy.Globals.CHANGE);
230     }
231 }