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