Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

[Core] Added item metadata infrastructure #4390

Merged
merged 26 commits into from
Apr 12, 2018
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ce584a8
added metadata infrastructure
kaikreuzer Aug 2, 2017
59864a6
Introduced AbstractUID
Mar 23, 2018
9f19a43
[metadata] turned MetadataKey into a AbstractUID
Mar 23, 2018
0d60100
[metadata] minor cleanups
Mar 26, 2018
f49460a
[metadata] Cleanup in MetadataRegistry based on ManagedItemProvider only
Mar 26, 2018
173e575
[metadata] implement equals/hashCode in Metadata
Mar 27, 2018
6d6b8e5
[metadata] fix metadata removal in GenericItemProvider
Mar 27, 2018
ba34419
[metadata] made GenericMetadataProvider thread-safe, fixed removal
Mar 27, 2018
a4bd749
added UoM to model.item.test launch config
Mar 27, 2018
107254d
[metadata] optional metadata configuration, immutable
Mar 27, 2018
ec38404
[metadata] handle update and exceptional cases in ItemResource
Mar 27, 2018
fc6a80e
[metadata] added tests for metadata
Mar 27, 2018
07e4b69
[metadata] added a section to the item concept documentation
Mar 28, 2018
2b7738f
[metadata] added missing log statements
Mar 28, 2018
eb742c3
protect AbstractUID segments from external tampering
Mar 28, 2018
4d23ff0
hide managed metadata provider implementation in internal package
Apr 6, 2018
cf8fcf0
allow filtering config descriptions for a specific scheme
Apr 6, 2018
4b365a2
[metadata] added missing @Nullable annotation for the namespace selector
Apr 6, 2018
f59c385
incorporated review feedback
Apr 9, 2018
5924264
[metadata] support config descriptions for meta-data
Apr 9, 2018
5a97015
[metadata] updated license headers
Apr 9, 2018
dbc48fc
[metadata] export config.items package
Apr 9, 2018
51dd700
[metadata] review feedback on config description API
Apr 12, 2018
d478139
fixed illegal list modification in GenericThingProvider
Apr 12, 2018
a37b32b
review feedback: renamed method in ChannelUID
Apr 12, 2018
4d13116
[metadata] pour some magic on items
Apr 12, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* Copyright (c) 2014,2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.internal.items;

import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;

import java.util.Collections;

import org.eclipse.smarthome.core.common.registry.ProviderChangeListener;
import org.eclipse.smarthome.core.items.Item;
import org.eclipse.smarthome.core.items.ManagedItemProvider;
import org.eclipse.smarthome.core.items.ManagedMetadataProvider;
import org.eclipse.smarthome.core.items.Metadata;
import org.eclipse.smarthome.core.items.MetadataKey;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;

/**
* @author Simon Kaufmann - initial contribution and API
*/
public class MetadataRegistryImplTest {

private static final String ITEM_NAME = "itemName";

@SuppressWarnings("rawtypes")
private @Mock ServiceReference managedProviderRef;
private @Mock BundleContext bundleContext;
private @Mock ManagedItemProvider itemProvider;
private @Mock ManagedMetadataProvider managedProvider;
private @Mock Item item;

private ServiceListener providerTracker;

private MetadataRegistryImpl registry;

private ProviderChangeListener<Item> providerChangeListener;

@Before
@SuppressWarnings("unchecked")
public void setup() throws Exception {
initMocks(this);

when(bundleContext.getService(same(managedProviderRef))).thenReturn(managedProvider);

when(item.getName()).thenReturn(ITEM_NAME);

registry = new MetadataRegistryImpl();

registry.setManagedItemProvider(itemProvider);
registry.setManagedProvider(managedProvider);
registry.activate(bundleContext);

ArgumentCaptor<ServiceListener> captor = ArgumentCaptor.forClass(ServiceListener.class);
verify(bundleContext).addServiceListener(captor.capture(), any());
providerTracker = captor.getValue();
providerTracker.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, managedProviderRef));

ArgumentCaptor<ProviderChangeListener<Item>> captorChangeListener = ArgumentCaptor
.forClass(ProviderChangeListener.class);
verify(itemProvider).addProviderChangeListener(captorChangeListener.capture());
providerChangeListener = captorChangeListener.getValue();
}

@Test
public void testManagedItemProviderChangeListenerRegistration() {
verify(itemProvider).addProviderChangeListener(any());
verifyNoMoreInteractions(itemProvider);

registry.unsetManagedItemProvider(itemProvider);
verify(itemProvider).removeProviderChangeListener(any());
verifyNoMoreInteractions(itemProvider);
}

@Test
public void testRemoved() {
providerChangeListener.removed(itemProvider, item);
verify(managedProvider).removeItemMetadata(eq(ITEM_NAME));
}

@Test
public void testGet_empty() throws Exception {
MetadataKey key = new MetadataKey("namespace", "itemName");

Metadata res = registry.get(key);
assertNull(res);
}

@Test
public void testGet() throws Exception {
MetadataKey key = new MetadataKey("namespace", "itemName");
registry.added(managedProvider, new Metadata(key, "value", Collections.emptyMap()));
registry.added(managedProvider,
new Metadata(new MetadataKey("other", "itemName"), "other", Collections.emptyMap()));
registry.added(managedProvider,
new Metadata(new MetadataKey("namespace", "other"), "other", Collections.emptyMap()));

Metadata res = registry.get(key);
assertNotNull(res);
assertEquals("value", res.getValue());
assertEquals("namespace", res.getUID().getNamespace());
assertEquals("itemName", res.getUID().getItemName());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright (c) 2014,2018 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.eclipse.smarthome.core.items;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

/**
* @author Simon Kaufmann - initial contribution and API
*/
public class MetadataKeyTest {

@Test
public void testGetNamespace() {
assertEquals("namespace", new MetadataKey("namespace", "itemName").getNamespace());
}

@Test
public void testGetItemName() {
assertEquals("itemName", new MetadataKey("namespace", "itemName").getItemName());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,14 @@ public void testTwoSegments() {
assertEquals("gaga", t.getId());
assertEquals("fake::gaga", t.getAsString());
}

@Test
public void testGetBridgeIds() {
ThingTypeUID thingType = new ThingTypeUID("fake", "type");
ThingUID t = new ThingUID(thingType, new ThingUID("fake", "something", "bridge"), "thing");

assertEquals("fake:type:bridge:thing", t.getAsString());
assertEquals(1, t.getBridgeIds().size());
assertEquals("bridge", t.getBridgeIds().get(0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
*/
package org.eclipse.smarthome.core.thing;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

/**
* {@link ChannelUID} represents a unique identifier for channels.
Expand All @@ -22,6 +27,7 @@
* @author Dennis Nobel - Added channel group id
* @author Kai Kreuzer - Changed creation of channels to not require a thing type
*/
@NonNullByDefault
public class ChannelUID extends UID {

private static final String CHANNEL_GROUP_SEPERATOR = "#";
Expand Down Expand Up @@ -98,17 +104,13 @@ public ChannelUID(String bindingId, String thingTypeId, String thingId, String g
super(bindingId, thingTypeId, thingId, getChannelId(groupId, id));
}

private static String[] getArray(ThingUID thingUID, String groupId, String id) {
String[] result = new String[thingUID.getSegments().length + 1];
for (int i = 0; i < thingUID.getSegments().length; i++) {
result[i] = thingUID.getSegments()[i];
}
result[result.length - 1] = getChannelId(groupId, id);

return result;
private static List<String> getArray(ThingUID thingUID, @Nullable String groupId, String id) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does getArray now return a List?
You might want to rename the method.

List<String> ret = new ArrayList<>(thingUID.getAllSegments());
ret.add(getChannelId(groupId, id));
return ret;
}

private static String getChannelId(String groupId, String id) {
private static String getChannelId(@Nullable String groupId, String id) {
return groupId != null ? groupId + CHANNEL_GROUP_SEPERATOR + id : id;
}

Expand All @@ -118,8 +120,8 @@ private static String getChannelId(String groupId, String id) {
* @return id
*/
public String getId() {
String[] segments = getSegments();
return segments[segments.length - 1];
List<String> segments = getAllSegments();
return segments.get(segments.size() - 1);
}

/**
Expand All @@ -128,27 +130,24 @@ public String getId() {
* @return id id without group id
*/
public String getIdWithoutGroup() {
String[] segments = getSegments();
if (!isInGroup()) {
return segments[segments.length - 1];
return getId();
} else {
return segments[segments.length - 1].split(CHANNEL_GROUP_SEPERATOR)[1];
return getId().split(CHANNEL_GROUP_SEPERATOR)[1];
}
}

public boolean isInGroup() {
String[] segments = getSegments();
return segments[segments.length - 1].contains(CHANNEL_GROUP_SEPERATOR);
return getId().contains(CHANNEL_GROUP_SEPERATOR);
}

/**
* Returns the group id.
*
* @return group id or null if channel is not in a group
*/
public String getGroupId() {
String[] segments = getSegments();
return isInGroup() ? segments[segments.length - 1].split(CHANNEL_GROUP_SEPERATOR)[0] : null;
public @Nullable String getGroupId() {
return isInGroup() ? getId().split(CHANNEL_GROUP_SEPERATOR)[0] : null;
}

@Override
Expand All @@ -174,7 +173,8 @@ protected void validateSegment(String segment, int index, int length) {
* @return the thing UID
*/
public ThingUID getThingUID() {
return new ThingUID(Arrays.copyOfRange(getSegments(), 0, getSegments().length - 1));
List<@NonNull String> allSegments = getAllSegments();
return new ThingUID(allSegments.subList(0, allSegments.size() - 1).toArray(new String[allSegments.size() - 1]));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,8 @@ public ThingTypeUID getThingTypeUID() {
* @return list of bridge ids
*/
public List<String> getBridgeIds() {
List<String> bridgeIds = new ArrayList<>();
String[] segments = getSegments();
for (int i = 2; i < segments.length - 1; i++) {
bridgeIds.add(segments[i]);
}
return bridgeIds;
List<String> allSegments = getAllSegments();
return allSegments.subList(2, allSegments.size() - 1);
}

/**
Expand All @@ -187,8 +183,8 @@ public List<String> getBridgeIds() {
* @return id the id
*/
public String getId() {
String[] segments = getSegments();
return segments[segments.length - 1];
List<String> segments = getAllSegments();
return segments.get(segments.size() - 1);
}

@Override
Expand Down
Loading