Skip to content

Commit

Permalink
#16308 Added backwardcompatibility for the old way of writting the da…
Browse files Browse the repository at this point in the history
…ta where possible

Signed-off-by: René Ulbricht <rene_ulbricht@outlook.com>
  • Loading branch information
ulbi committed Jan 28, 2024
1 parent e9b9e29 commit a29b43e
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@
package org.openhab.persistence.mongodb.internal;

import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.util.LinkedHashMap;
import java.util.Date;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;

import javax.measure.Unit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.bson.Document;
import org.bson.types.Binary;
Expand All @@ -39,6 +43,8 @@
* @author René Ulbricht - Initial contribution
*/
public class MongoDBTypeConversions {

private static final Logger logger = LoggerFactory.getLogger(MongoDBPersistenceService.class);
/**
* A map of converters that convert openHAB states to MongoDB compatible types.
* Each converter is a function that takes an openHAB state and returns an object that can be stored in MongoDB.
Expand Down Expand Up @@ -78,38 +84,77 @@ public static Object convertValue(State state) {
ITEM_STATE_CONVERTERS.put(NumberItem.class, (item, doc) -> {
NumberItem numberItem = (NumberItem) item;
Unit<?> unit = numberItem.getUnit();
Object value = doc.get(MongoDBFields.FIELD_VALUE);
if (value instanceof String) {
return new QuantityType<>(value.toString());
}
if (unit != null) {
return new QuantityType<>(doc.getDouble(MongoDBFields.FIELD_VALUE), unit);
return new QuantityType<>(((Number)value).doubleValue(), unit);
} else {
return new DecimalType(doc.getDouble(MongoDBFields.FIELD_VALUE));
return new DecimalType(((Number)value).doubleValue());
}
});
ITEM_STATE_CONVERTERS.put(ColorItem.class,
(item, doc) -> new HSBType(doc.getString(MongoDBFields.FIELD_VALUE)));
ITEM_STATE_CONVERTERS.put(DimmerItem.class,
(item, doc) -> new PercentType(doc.getInteger(MongoDBFields.FIELD_VALUE)));
ITEM_STATE_CONVERTERS.put(ColorItem.class, (item, doc) -> {
Object value = doc.get(MongoDBFields.FIELD_VALUE);
if (value instanceof String) {
return new HSBType(value.toString());
}
else {
logger.warn("HSBType ({}) value is not a valid string: {}", doc.getString(MongoDBFields.FIELD_REALNAME), value);
return new HSBType("0,0,0");
}
});
ITEM_STATE_CONVERTERS.put(DimmerItem.class, (item, doc) -> {
Object value = doc.get(MongoDBFields.FIELD_VALUE);
if (value instanceof Integer) {
return new PercentType((Integer)value);
} else {
return new PercentType(((Number)value).intValue());
}
});
ITEM_STATE_CONVERTERS.put(SwitchItem.class,
(item, doc) -> OnOffType.valueOf(doc.getString(MongoDBFields.FIELD_VALUE)));
ITEM_STATE_CONVERTERS.put(ContactItem.class,
(item, doc) -> OpenClosedType.valueOf(doc.getString(MongoDBFields.FIELD_VALUE)));
ITEM_STATE_CONVERTERS.put(RollershutterItem.class,
(item, doc) -> new PercentType(doc.getInteger(MongoDBFields.FIELD_VALUE)));
ITEM_STATE_CONVERTERS.put(DateTimeItem.class,
(item, doc) -> new DateTimeType(ZonedDateTime.parse(doc.getString(MongoDBFields.FIELD_VALUE))));
ITEM_STATE_CONVERTERS.put(RollershutterItem.class, (item, doc) -> {
Object value = doc.get(MongoDBFields.FIELD_VALUE);
if (value instanceof Integer) {
return new PercentType((Integer)value);
} else {
return new PercentType(((Number)value).intValue());
}
});
ITEM_STATE_CONVERTERS.put(DateTimeItem.class, (item, doc) -> {
Object value = doc.get(MongoDBFields.FIELD_VALUE);
if (value instanceof String) {
return new DateTimeType(ZonedDateTime.parse(doc.getString(MongoDBFields.FIELD_VALUE)));
}
else {
return new DateTimeType(ZonedDateTime.ofInstant(((Date)value).toInstant(), ZoneId.systemDefault()));
}
});
ITEM_STATE_CONVERTERS.put(LocationItem.class,
(item, doc) -> new PointType(doc.getString(MongoDBFields.FIELD_VALUE)));
ITEM_STATE_CONVERTERS.put(PlayerItem.class,
(item, doc) -> PlayPauseType.valueOf(doc.getString(MongoDBFields.FIELD_VALUE)));
ITEM_STATE_CONVERTERS.put(CallItem.class,
(item, doc) -> new StringListType(doc.getString(MongoDBFields.FIELD_VALUE)));
ITEM_STATE_CONVERTERS.put(ImageItem.class, (item, doc) -> {
Document fieldValue = (Document) doc.get(MongoDBFields.FIELD_VALUE);
String type = fieldValue.getString(MongoDBFields.FIELD_VALUE_TYPE);
Binary data = fieldValue.get(MongoDBFields.FIELD_VALUE_DATA, Binary.class);
return new RawType(data.getData(), type);
Object value = doc.get(MongoDBFields.FIELD_VALUE);
if (value instanceof Document) {
Document fieldValue = (Document) value;
String type = fieldValue.getString(MongoDBFields.FIELD_VALUE_TYPE);
Binary data = fieldValue.get(MongoDBFields.FIELD_VALUE_DATA, Binary.class);
return new RawType(data.getData(), type);
}
else {
logger.warn("ImageItem ({}) value is not a Document: {}", doc.getString(MongoDBFields.FIELD_REALNAME), value);
return new RawType(new byte[0], "application/octet-stream");
}
});
ITEM_STATE_CONVERTERS.put(GenericItem.class,
(item, doc) -> new StringType(doc.getString(MongoDBFields.FIELD_VALUE)));

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
import static org.mockito.Mockito.*;

import java.time.LocalDate;

import java.time.ZonedDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
Expand All @@ -39,6 +41,9 @@
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import org.bson.types.ObjectId;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
Expand Down Expand Up @@ -266,4 +271,34 @@ public static ListAppender<ILoggingEvent> setupLogger(Class<?> loggerClass, Leve
logger.setLevel(level); // Set log level
return listAppender;
}

private static Object convertValue(State state) {
Object value;
if (state instanceof PercentType) {
PercentType type = (PercentType) state;
value = type.toBigDecimal().doubleValue();
} else if (state instanceof DateTimeType) {
DateTimeType type = (DateTimeType) state;
value = Date.from(type.getZonedDateTime().toInstant());
} else if (state instanceof DecimalType) {
DecimalType type = (DecimalType) state;
value = type.toBigDecimal().doubleValue();
} else {
value = state.toString();
}
return value;
}

public static void storeOldData(MongoCollection<Document> collection, String realItemName, State state) {
// use the old way to store data
Object value = convertValue(state);

Document obj = new Document();
obj.put(MongoDBFields.FIELD_ID, new ObjectId());
obj.put(MongoDBFields.FIELD_ITEM, realItemName);
obj.put(MongoDBFields.FIELD_REALNAME, realItemName);
obj.put(MongoDBFields.FIELD_TIMESTAMP, new Date());
obj.put(MongoDBFields.FIELD_VALUE, value);
collection.insertOne(obj);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

Expand All @@ -28,9 +30,8 @@
import org.mockito.Mockito;
import org.openhab.core.items.GenericItem;
import org.openhab.core.items.ItemNotFoundException;
import org.openhab.core.library.items.NumberItem;
import org.openhab.core.library.items.StringItem;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.items.*;
import org.openhab.core.library.types.*;
import org.openhab.core.persistence.FilterCriteria;
import org.openhab.core.persistence.HistoricItem;
import org.osgi.framework.BundleContext;
Expand Down Expand Up @@ -637,4 +638,52 @@ public void testQueryAllOpenhabItemTypesSingleCollection(GenericItem item) {
dbContainer.stop();
}
}

/**
* Tests the old way of storing data and query method of the MongoDBPersistenceService with all types of openHAB items.
* Each item is queried with the type from one collection in the MongoDB database.
*
* @param item The item to store in the database.
*/
@ParameterizedTest
@MethodSource("org.openhab.persistence.mongodb.internal.DataCreationHelper#provideOpenhabItemTypes")
public void testOldDataQueryAllOpenhabItemTypesSingleCollection(GenericItem item) {
// Preparation
DatabaseTestContainer dbContainer = new DatabaseTestContainer(new MemoryBackend());
try {
SetupResult setupResult = DataCreationHelper.setupMongoDB("testCollection", dbContainer);
MongoDBPersistenceService service = setupResult.service;
MongoDatabase database = setupResult.database;

service.activate(setupResult.bundleContext, setupResult.config);
try {
Mockito.when(setupResult.itemRegistry.getItem(item.getName())).thenReturn(item);
} catch (ItemNotFoundException e) {
}
MongoCollection<Document> collection = database.getCollection("testCollection");
DataCreationHelper.storeOldData(collection, item.getName(), item.getState());
// after storing, we have to adjust the expected values for ImageItems, ColorItems as well as DateTimeItems
if (item instanceof ImageItem) {
item.setState(new RawType(new byte[0], "application/octet-stream"));
} else if (item instanceof ColorItem) {
item.setState(new HSBType("0,0,0"));
}

// Execution
FilterCriteria filter = DataCreationHelper.createFilterCriteria(item.getName());
Iterable<HistoricItem> result = service.query(filter);
// Verification

if (item instanceof DateTimeItem) {
// verify just the date part
assertEquals(((DateTimeType)item.getState()).getZonedDateTime().toLocalDate(),
((DateTimeType)result.iterator().next().getState()).getZonedDateTime().toLocalDate());
}
else {
VerificationHelper.verifyQueryResult(result, item.getState());
}
} finally {
dbContainer.stop();
}
}
}

0 comments on commit a29b43e

Please sign in to comment.