Use ThingStorageEntity instead of ThingImpl/BridgeImpl for storage (#2914)

Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
J-N-K 2022-06-18 14:31:45 +02:00 committed by GitHub
parent 2b4e5af21e
commit d74277f798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 775 additions and 8 deletions

View File

@ -25,6 +25,8 @@ import org.openhab.core.OpenHAB;
import org.openhab.core.config.core.ConfigurableService;
import org.openhab.core.storage.Storage;
import org.openhab.core.storage.StorageService;
import org.openhab.core.storage.json.internal.migration.BridgeImplTypeMigrator;
import org.openhab.core.storage.json.internal.migration.ThingImplTypeMigrator;
import org.openhab.core.storage.json.internal.migration.TypeMigrator;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Activate;
@ -51,7 +53,8 @@ public class JsonStorageService implements StorageService {
/**
* Contains a map of needed migrations, key is the storage name
*/
private static final Map<String, List<TypeMigrator>> MIGRATORS = Map.of();
private static final Map<String, List<TypeMigrator>> MIGRATORS = Map.of( //
"org.openhab.core.thing.Thing", List.of(new BridgeImplTypeMigrator(), new ThingImplTypeMigrator()));
private final Logger logger = LoggerFactory.getLogger(JsonStorageService.class);

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.storage.json.internal.migration;
import org.eclipse.jdt.annotation.NonNullByDefault;
import com.google.gson.JsonElement;
/**
* The {@link BridgeImplTypeMigrator} implements a {@link TypeMigrator} for stored bridges
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class BridgeImplTypeMigrator extends ThingImplTypeMigrator {
@Override
public String getOldType() {
return "org.openhab.core.thing.internal.BridgeImpl";
}
@Override
public String getNewType() {
return "org.openhab.core.thing.internal.ThingStorageEntity";
}
@Override
public JsonElement migrate(JsonElement oldValue) throws TypeMigrationException {
JsonElement newValue = super.migrate(oldValue);
newValue.getAsJsonObject().addProperty("isBridge", true);
return newValue;
}
}

View File

@ -0,0 +1,77 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.storage.json.internal.migration;
import java.util.Spliterator;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.eclipse.jdt.annotation.NonNullByDefault;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* The {@link ThingImplTypeMigrator} implements a {@link TypeMigrator} for stored things
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class ThingImplTypeMigrator implements TypeMigrator {
@Override
public String getOldType() {
return "org.openhab.core.thing.internal.ThingImpl";
}
@Override
public String getNewType() {
return "org.openhab.core.thing.internal.ThingStorageEntity";
}
@Override
public JsonElement migrate(JsonElement oldValue) throws TypeMigrationException {
JsonObject newValue = oldValue.deepCopy().getAsJsonObject();
segmentUidToStringUid(newValue, "uid", "UID");
segmentUidToStringUid(newValue, "bridgeUID");
segmentUidToStringUid(newValue, "thingTypeUID");
for (JsonElement jsonElement : newValue.get("channels").getAsJsonArray()) {
JsonObject channel = jsonElement.getAsJsonObject();
channel.add("itemType", channel.remove("acceptedItemType"));
channel.add("configuration", channel.remove("configuration").getAsJsonObject().get("properties"));
segmentUidToStringUid(channel, "uid");
segmentUidToStringUid(channel, "channelTypeUID");
}
newValue.add("configuration", newValue.remove("configuration").getAsJsonObject().get("properties"));
newValue.addProperty("isBridge", false);
return newValue;
}
private void segmentUidToStringUid(JsonObject object, String name) {
segmentUidToStringUid(object, name, name);
}
private void segmentUidToStringUid(JsonObject object, String oldName, String newName) {
JsonElement element = object.remove(oldName);
if (element != null) {
Spliterator<JsonElement> segments = element.getAsJsonObject().get("segments").getAsJsonArray()
.spliterator();
String uid = StreamSupport.stream(segments, false).map(JsonElement::getAsString)
.collect(Collectors.joining(":"));
object.addProperty(newName, uid);
}
}
}

View File

@ -0,0 +1,105 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.storage.json.internal;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.nio.file.Path;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.openhab.core.config.core.OrderingMapSerializer;
import org.openhab.core.config.core.OrderingSetSerializer;
import org.openhab.core.storage.json.internal.migration.BridgeImplTypeMigrator;
import org.openhab.core.storage.json.internal.migration.ThingImplTypeMigrator;
import org.openhab.core.storage.json.internal.migration.TypeMigrationException;
import org.openhab.core.storage.json.internal.migration.TypeMigrator;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
/**
* The {@link ThingStorageEntityMigratorTest} contains tests for the ThingImpl and BridgeImpl migrators
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class ThingStorageEntityMigratorTest {
private final Gson internalMapper = new GsonBuilder() //
.registerTypeHierarchyAdapter(Map.class, new OrderingMapSerializer())//
.registerTypeHierarchyAdapter(Set.class, new OrderingSetSerializer())//
.registerTypeHierarchyAdapter(Map.class, new StorageEntryMapDeserializer()) //
.setPrettyPrinting() //
.create();
private @NonNullByDefault({}) Map<String, StorageEntry> inputMap;
private @NonNullByDefault({}) Map<String, StorageEntry> resultMap;
@BeforeEach
public void setup() throws FileNotFoundException {
inputMap = readDatabase(Path.of("src/test/resources/thingMigration-input.json"));
resultMap = readDatabase(Path.of("src/test/resources/thingMigration-result.json"));
assertThat(inputMap.size(), is(2));
assertThat(resultMap.size(), is(2));
}
private static Stream<Arguments> typeMigrationsSource() {
return Stream.of(Arguments.of("deconz:deconz:00313E041ED0", new BridgeImplTypeMigrator(), true),
Arguments.of("http:url:0a500ec3d8", new ThingImplTypeMigrator(), false));
}
@ParameterizedTest
@MethodSource("typeMigrationsSource")
public void typeMigration(String thingUid, TypeMigrator migrator, boolean isBridge) throws TypeMigrationException {
StorageEntry inputEntry = inputMap.get(thingUid);
StorageEntry resultEntry = resultMap.get(thingUid);
assertThat(inputEntry.getEntityClassName(), is(migrator.getOldType()));
JsonElement entityValue = (JsonElement) inputEntry.getValue();
assertThat(entityValue.getAsJsonObject().get("isBridge"), nullValue());
JsonElement newEntityValue = migrator.migrate(entityValue);
assertThat(newEntityValue.getAsJsonObject().get("isBridge").getAsBoolean(), is(isBridge));
assertThat(newEntityValue, is(resultEntry.getValue()));
}
@SuppressWarnings("unchecked")
private Map<String, StorageEntry> readDatabase(Path path) throws FileNotFoundException {
final Map<String, StorageEntry> map = new ConcurrentHashMap<>();
FileReader reader = new FileReader(path.toFile());
Map<String, StorageEntry> loadedMap = internalMapper.fromJson(reader, map.getClass());
if (loadedMap != null && !loadedMap.isEmpty()) {
map.putAll(loadedMap);
}
return map;
}
}

View File

@ -0,0 +1,130 @@
{
"deconz:deconz:00313E041ED0": {
"class": "org.openhab.core.thing.internal.BridgeImpl",
"value": {
"label": "Phoscon (192.168.1.100:80)",
"channels": [],
"configuration": {
"properties": {
"host": "192.168.1.100",
"httpPort": 80,
"timeout": 2000,
"websocketTimeout": 120
}
},
"properties": {
"UDN": "56071c34-1111-4b08-bba8-d3f29e6d43d8"
},
"uid": {
"segments": [
"deconz",
"deconz",
"00313E041ED0"
],
"uid": "deconz:deconz:00313E041ED0"
},
"thingTypeUID": {
"segments": [
"deconz",
"deconz"
],
"uid": ""
}
}
},
"http:url:0a500ec3d8": {
"class": "org.openhab.core.thing.internal.ThingImpl",
"value": {
"label": "HTTP URL Thing",
"channels": [
{
"acceptedItemType": "DateTime",
"kind": "STATE",
"uid": {
"segments": [
"http",
"url",
"0a500ec3d8",
"lastFailure"
],
"uid": "http:url:0a500ec3d8:lastFailure"
},
"channelTypeUID": {
"segments": [
"http",
"requestDateTime"
],
"uid": "http:requestDateTime"
},
"label": "Last Failure",
"configuration": {
"properties": {
"stateTransformation": "abcd"
}
},
"properties": {},
"defaultTags": [],
"autoUpdatePolicy": "DEFAULT"
},
{
"acceptedItemType": "DateTime",
"kind": "STATE",
"uid": {
"segments": [
"http",
"url",
"0a500ec3d8",
"lastSuccess"
],
"uid": "http:url:0a500ec3d8:lastSuccess"
},
"channelTypeUID": {
"segments": [
"http",
"requestDateTime"
],
"uid": "http:requestDateTime"
},
"label": "Last Success",
"configuration": {
"properties": {}
},
"properties": {},
"defaultTags": [],
"autoUpdatePolicy": "DEFAULT"
}
],
"configuration": {
"properties": {
"authMode": "BASIC",
"baseURL": "https://localhost:8443",
"bufferSize": 2048,
"commandMethod": "GET",
"delay": 0,
"ignoreSSLErrors": true,
"refresh": 30,
"stateMethod": "GET",
"timeout": 3000
}
},
"properties": {
"thingTypeVersion": "1"
},
"uid": {
"segments": [
"http",
"url",
"0a500ec3d8"
],
"uid": "http:url:0a500ec3d8"
},
"thingTypeUID": {
"segments": [
"http",
"url"
],
"uid": ""
}
}
}
}

View File

@ -0,0 +1,70 @@
{
"deconz:deconz:00313E041ED0": {
"class": "org.openhab.core.thing.internal.ThingStorageEntity",
"value": {
"label": "Phoscon (192.168.1.100:80)",
"channels": [],
"properties": {
"UDN": "56071c34-1111-4b08-bba8-d3f29e6d43d8"
},
"UID": "deconz:deconz:00313E041ED0",
"thingTypeUID": "deconz:deconz",
"configuration": {
"host": "192.168.1.100",
"httpPort": 80,
"timeout": 2000,
"websocketTimeout": 120
},
"isBridge": true
}
},
"http:url:0a500ec3d8": {
"class": "org.openhab.core.thing.internal.ThingStorageEntity",
"value": {
"label": "HTTP URL Thing",
"channels": [
{
"kind": "STATE",
"label": "Last Failure",
"configuration": {
"stateTransformation": "abcd"
},
"properties": {},
"defaultTags": [],
"autoUpdatePolicy": "DEFAULT",
"itemType": "DateTime",
"uid": "http:url:0a500ec3d8:lastFailure",
"channelTypeUID": "http:requestDateTime"
},
{
"kind": "STATE",
"label": "Last Success",
"configuration": {},
"properties": {},
"defaultTags": [],
"autoUpdatePolicy": "DEFAULT",
"itemType": "DateTime",
"uid": "http:url:0a500ec3d8:lastSuccess",
"channelTypeUID": "http:requestDateTime"
}
],
"configuration": {
"authMode": "BASIC",
"baseURL": "https://localhost:8443",
"bufferSize": 2048,
"commandMethod": "GET",
"delay": 0,
"ignoreSSLErrors": true,
"refresh": 30,
"stateMethod": "GET",
"timeout": 3000
},
"properties": {
"thingTypeVersion": "1"
},
"UID": "http:url:0a500ec3d8",
"thingTypeUID": "http:url",
"isBridge": false
}
}
}

View File

@ -13,8 +13,12 @@
package org.openhab.core.thing;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.common.registry.DefaultAbstractManagedProvider;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.common.registry.AbstractManagedProvider;
import org.openhab.core.storage.StorageService;
import org.openhab.core.thing.dto.ThingDTOMapper;
import org.openhab.core.thing.internal.BridgeImpl;
import org.openhab.core.thing.internal.ThingStorageEntity;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
@ -31,7 +35,8 @@ import org.osgi.service.component.annotations.Reference;
*/
@NonNullByDefault
@Component(immediate = true, service = { ThingProvider.class, ManagedThingProvider.class })
public class ManagedThingProvider extends DefaultAbstractManagedProvider<Thing, ThingUID> implements ThingProvider {
public class ManagedThingProvider extends AbstractManagedProvider<Thing, ThingUID, ThingStorageEntity>
implements ThingProvider {
@Activate
public ManagedThingProvider(final @Reference StorageService storageService) {
@ -47,4 +52,14 @@ public class ManagedThingProvider extends DefaultAbstractManagedProvider<Thing,
protected String keyToString(ThingUID key) {
return key.toString();
}
@Override
protected @Nullable Thing toElement(String key, ThingStorageEntity persistableElement) {
return ThingDTOMapper.map(persistableElement, persistableElement.isBridge);
}
@Override
protected ThingStorageEntity toPersistableElement(Thing element) {
return new ThingStorageEntity(ThingDTOMapper.map(element), element instanceof BridgeImpl);
}
}

View File

@ -0,0 +1,34 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.thing.internal;
import org.openhab.core.thing.dto.ThingDTO;
/**
* The {@link ThingStorageEntity} is an entity for Thing storage
*
* @author Jan N. Klug - Initial contribution
*/
public class ThingStorageEntity extends ThingDTO {
public boolean isBridge = false;
ThingStorageEntity() {
// do not remove, needed by GSON for deserialization
}
public ThingStorageEntity(ThingDTO thingDTO, boolean isBridge) {
super(thingDTO.thingTypeUID, thingDTO.UID, thingDTO.label, thingDTO.bridgeUID, thingDTO.channels,
thingDTO.configuration, thingDTO.properties, thingDTO.location);
this.isBridge = isBridge;
}
}

View File

@ -0,0 +1,76 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.thing;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.openhab.core.library.CoreItemFactory;
import org.openhab.core.storage.StorageService;
import org.openhab.core.thing.binding.builder.BridgeBuilder;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.internal.ThingStorageEntity;
/**
* The {@link ManagedThingProviderTest} contains tests for the {@link ManagedThingProvider}
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class ManagedThingProviderTest {
private static final ThingTypeUID THING_TYPE_UID = new ThingTypeUID("test", "test");
private static final ThingUID THING_UID = new ThingUID(THING_TYPE_UID, "test");
private static final String FIRST_CHANNEL_ID = "firstgroup#channel1";
private static final ChannelUID FIRST_CHANNEL_UID = new ChannelUID(THING_UID, FIRST_CHANNEL_ID);
private @Mock @NonNullByDefault({}) StorageService storageService;
@Test
public void testThingImplConversion() {
Thing thing = ThingBuilder.create(THING_TYPE_UID, THING_UID)
.withChannel(ChannelBuilder.create(FIRST_CHANNEL_UID, CoreItemFactory.STRING).build()).build();
ManagedThingProvider managedThingProvider = new ManagedThingProvider(storageService);
ThingStorageEntity persistableElement = managedThingProvider.toPersistableElement(thing);
assertThat(persistableElement.isBridge, is(false));
Thing thing1 = managedThingProvider.toElement("", persistableElement);
assertThat(thing1, is(thing));
}
@Test
public void testBridgeImplConversion() {
Bridge thing = BridgeBuilder.create(THING_TYPE_UID, THING_UID)
.withChannel(ChannelBuilder.create(FIRST_CHANNEL_UID, CoreItemFactory.STRING).build()).build();
ManagedThingProvider managedThingProvider = new ManagedThingProvider(storageService);
ThingStorageEntity persistableElement = managedThingProvider.toPersistableElement(thing);
assertThat(persistableElement.isBridge, is(true));
Thing thing1 = managedThingProvider.toElement("", persistableElement);
assertThat(thing1, is(thing));
}
}

View File

@ -51,4 +51,6 @@ Fragment-Host: org.openhab.core.storage.json
org.ops4j.pax.logging.pax-logging-api;version='[2.0.16,2.0.17)',\
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
biz.aQute.tester.junit-platform;version='[6.3.0,6.3.1)'
org.openhab.core.io.console;version='[3.3.0,3.3.1)',\
org.openhab.core.thing;version='[3.3.0,3.3.1)',\
biz.aQute.tester.junit-platform;version='[6.3.0,6.3.1)

View File

@ -0,0 +1,73 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.storage.json.internal;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.Test;
import org.openhab.core.OpenHAB;
import org.openhab.core.storage.Storage;
import org.openhab.core.storage.StorageService;
import org.openhab.core.test.java.JavaOSGiTest;
import org.openhab.core.thing.ManagedThingProvider;
import org.openhab.core.thing.Thing;
/**
* The {@link ThingMigrationOSGiTest} is a test for thing migrations
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class ThingMigrationOSGiTest extends JavaOSGiTest {
private static final Path DB_DIR = Path.of(OpenHAB.getUserDataFolder(), "jsondb");
private static final String DB_NAME = "org.openhab.core.thing.Thing";
private static final String DB_OLD_NAME = "org.openhab.core.thing.Thing-old";
@Test
public void migrationParsable() throws IOException {
Files.createDirectories(DB_DIR);
StorageService storageService = getService(StorageService.class);
assertThat(storageService, is(notNullValue()));
// prepare storage
Files.copy(bundleContext.getBundle().getResource(DB_NAME + ".json").openStream(),
DB_DIR.resolve(DB_NAME + ".json"));
// we need to go over a ManagedThingProvider because the ThingStorageEntity is an internal package
ManagedThingProvider managedThingProvider = new ManagedThingProvider(storageService);
Collection<Thing> things = managedThingProvider.getAll();
assertThat(things.size(), is(2));
// remove this block when ThingImpl/BridgeImpl changes
Files.copy(bundleContext.getBundle().getResource(DB_NAME + ".json").openStream(),
DB_DIR.resolve(DB_OLD_NAME + ".json"));
Storage<Thing> oldStorage = storageService.getStorage(DB_OLD_NAME, Thing.class.getClassLoader());
Collection<@Nullable Thing> oldThings = oldStorage.getValues();
assertThat(oldThings.size(), is(things.size()));
assertThat(things, hasItems(oldThings.toArray(Thing[]::new)));
unregisterService(storageService);
}
}

View File

@ -0,0 +1,130 @@
{
"deconz:deconz:00313E041ED0": {
"class": "org.openhab.core.thing.internal.BridgeImpl",
"value": {
"label": "Phoscon (192.168.1.100:80)",
"channels": [],
"configuration": {
"properties": {
"host": "192.168.1.100",
"httpPort": 80,
"timeout": 2000,
"websocketTimeout": 120
}
},
"properties": {
"UDN": "56071c34-1111-4b08-bba8-d3f29e6d43d8"
},
"uid": {
"segments": [
"deconz",
"deconz",
"00313E041ED0"
],
"uid": "deconz:deconz:00313E041ED0"
},
"thingTypeUID": {
"segments": [
"deconz",
"deconz"
],
"uid": ""
}
}
},
"http:url:0a500ec3d8": {
"class": "org.openhab.core.thing.internal.ThingImpl",
"value": {
"label": "HTTP URL Thing",
"channels": [
{
"acceptedItemType": "DateTime",
"kind": "STATE",
"uid": {
"segments": [
"http",
"url",
"0a500ec3d8",
"lastFailure"
],
"uid": "http:url:0a500ec3d8:lastFailure"
},
"channelTypeUID": {
"segments": [
"http",
"requestDateTime"
],
"uid": "http:requestDateTime"
},
"label": "Last Failure",
"configuration": {
"properties": {
"stateTransformation": "abcd"
}
},
"properties": {},
"defaultTags": [],
"autoUpdatePolicy": "DEFAULT"
},
{
"acceptedItemType": "DateTime",
"kind": "STATE",
"uid": {
"segments": [
"http",
"url",
"0a500ec3d8",
"lastSuccess"
],
"uid": "http:url:0a500ec3d8:lastSuccess"
},
"channelTypeUID": {
"segments": [
"http",
"requestDateTime"
],
"uid": "http:requestDateTime"
},
"label": "Last Success",
"configuration": {
"properties": {}
},
"properties": {},
"defaultTags": [],
"autoUpdatePolicy": "DEFAULT"
}
],
"configuration": {
"properties": {
"authMode": "BASIC",
"baseURL": "https://localhost:8443",
"bufferSize": 2048,
"commandMethod": "GET",
"delay": 0,
"ignoreSSLErrors": true,
"refresh": 30,
"stateMethod": "GET",
"timeout": 3000
}
},
"properties": {
"thingTypeVersion": "1"
},
"uid": {
"segments": [
"http",
"url",
"0a500ec3d8"
],
"uid": "http:url:0a500ec3d8"
},
"thingTypeUID": {
"segments": [
"http",
"url"
],
"uid": ""
}
}
}
}

View File

@ -24,6 +24,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@ -44,9 +45,12 @@ import org.openhab.core.test.java.JavaOSGiTest;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ManagedThingProvider;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingRegistry;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.dto.ThingDTOMapper;
import org.openhab.core.thing.internal.ThingStorageEntity;
import org.openhab.core.thing.link.ItemChannelLink;
import org.openhab.core.thing.link.ManagedItemChannelLinkProvider;
import org.openhab.core.thing.type.ChannelDefinition;
@ -104,6 +108,7 @@ public class ChangeThingTypeOSGiTest extends JavaOSGiTest {
private @NonNullByDefault({}) ManagedThingProvider managedThingProvider;
private @NonNullByDefault({}) ManagedItemProvider managedItemProvider;
private @NonNullByDefault({}) SampleThingHandlerFactory thingHandlerFactory;
private @NonNullByDefault({}) ThingRegistry thingRegistry;
private @NonNullByDefault({}) ThingType thingTypeGeneric;
private @NonNullByDefault({}) ThingType thingTypeSpecific;
@ -116,6 +121,9 @@ public class ChangeThingTypeOSGiTest extends JavaOSGiTest {
@BeforeEach
public void setup() throws URISyntaxException {
thingRegistry = getService(ThingRegistry.class);
assertThat(thingRegistry, is(notNullValue()));
registerVolatileStorageService();
managedThingProvider = getService(ManagedThingProvider.class);
assertThat(managedThingProvider, is(notNullValue()));
@ -324,7 +332,8 @@ public class ChangeThingTypeOSGiTest extends JavaOSGiTest {
Thing persistedThing = ThingFactory.createThing(thingTypeSpecific,
new ThingUID("testBinding", "persistedThing"), new Configuration(properties), null, null);
persistedThing.setProperty("universal", "survives");
storage.getStorage(Thing.class.getName()).put("testBinding::persistedThing", persistedThing);
storage.getStorage(Thing.class.getName()).put("testBinding::persistedThing",
new ThingStorageEntity(ThingDTOMapper.map(persistedThing), false));
selfChanging = true;
unregisterService(storage);
@ -335,7 +344,7 @@ public class ChangeThingTypeOSGiTest extends JavaOSGiTest {
managedThingProvider = getService(ManagedThingProvider.class);
assertThat(managedThingProvider, is(notNullValue()));
Collection<Thing> res = managedThingProvider.getAll();
Collection<Thing> res = thingRegistry.getAll();
assertThat(res.size(), is(1));
Thing thing = res.iterator().next();
@ -400,8 +409,8 @@ public class ChangeThingTypeOSGiTest extends JavaOSGiTest {
assertThat(thing.getStatus(), is(ThingStatus.ONLINE));
// Ensure the new thing type has been persisted into the database
Storage<Thing> storage = getService(StorageService.class).getStorage(Thing.class.getName());
Thing persistedThing = storage.get("testBinding::testThing");
Storage<ThingStorageEntity> storage = getService(StorageService.class).getStorage(Thing.class.getName());
Thing persistedThing = ThingDTOMapper.map(Objects.requireNonNull(storage.get("testBinding::testThing")), false);
assertThat(persistedThing.getThingTypeUID().getAsString(), is("testBinding:specific"));
}