Added nullness annotations to Item events (#2384)
* Added nullness annotations to Item events * Added nullness annotations to tests Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>pull/2396/head
parent
a52bb42481
commit
8acaa8994f
|
@ -91,7 +91,11 @@ public class ScriptBusEvent {
|
|||
try {
|
||||
Item item = itemRegistry.getItem(itemName);
|
||||
Command command = TypeParser.parseCommand(item.getAcceptedCommandTypes(), commandString);
|
||||
eventPublisher.post(ItemEventFactory.createCommandEvent(itemName, command));
|
||||
if (command != null) {
|
||||
eventPublisher.post(ItemEventFactory.createCommandEvent(itemName, command));
|
||||
} else {
|
||||
LoggerFactory.getLogger(ScriptBusEvent.class).warn("Command '{}' cannot be parsed.", commandString);
|
||||
}
|
||||
} catch (ItemNotFoundException e) {
|
||||
LoggerFactory.getLogger(ScriptBusEvent.class).warn("Item '{}' does not exist.", itemName);
|
||||
}
|
||||
|
@ -151,7 +155,11 @@ public class ScriptBusEvent {
|
|||
try {
|
||||
Item item = itemRegistry.getItem(itemName);
|
||||
State state = TypeParser.parseState(item.getAcceptedDataTypes(), stateString);
|
||||
eventPublisher.post(ItemEventFactory.createStateEvent(itemName, state));
|
||||
if (state != null) {
|
||||
eventPublisher.post(ItemEventFactory.createStateEvent(itemName, state));
|
||||
} else {
|
||||
LoggerFactory.getLogger(ScriptBusEvent.class).warn("State '{}' cannot be parsed.", stateString);
|
||||
}
|
||||
} catch (ItemNotFoundException e) {
|
||||
LoggerFactory.getLogger(ScriptBusEvent.class).warn("Item '{}' does not exist.", itemName);
|
||||
}
|
||||
|
|
|
@ -12,17 +12,20 @@
|
|||
*/
|
||||
package org.openhab.core.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link EventPublisher} posts {@link Event}s through the openHAB event bus in an asynchronous way.
|
||||
* Posted events can be received by implementing the {@link EventSubscriber} callback interface.
|
||||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface EventPublisher {
|
||||
|
||||
/**
|
||||
* Posts an event through the event bus in an asynchronous way.
|
||||
*
|
||||
*
|
||||
* @param event the event posted through the event bus
|
||||
* @throws IllegalArgumentException if the event is null
|
||||
* @throws IllegalArgumentException if one of the event properties type, payload or topic is null
|
||||
|
|
|
@ -12,19 +12,22 @@
|
|||
*/
|
||||
package org.openhab.core.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link TopicEventFilter} is a default openHAB {@link EventFilter} implementation that ensures filtering
|
||||
* of events based on an event topic.
|
||||
*
|
||||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TopicEventFilter implements EventFilter {
|
||||
|
||||
private final String topicRegex;
|
||||
|
||||
/**
|
||||
* Constructs a new topic event filter.
|
||||
*
|
||||
*
|
||||
* @param topicRegex the regular expression of a topic
|
||||
* @see <a href="http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html">Java Regex</a>
|
||||
*/
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Hashtable;
|
|||
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventPublisher;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.event.EventAdmin;
|
||||
|
@ -36,17 +37,13 @@ import org.osgi.service.event.EventAdmin;
|
|||
@Component
|
||||
public class OSGiEventPublisher implements EventPublisher {
|
||||
|
||||
private EventAdmin osgiEventAdmin;
|
||||
private final EventAdmin osgiEventAdmin;
|
||||
|
||||
@Reference
|
||||
protected void setEventAdmin(EventAdmin eventAdmin) {
|
||||
@Activate
|
||||
public OSGiEventPublisher(final @Reference EventAdmin eventAdmin) {
|
||||
this.osgiEventAdmin = eventAdmin;
|
||||
}
|
||||
|
||||
protected void unsetEventAdmin(EventAdmin eventAdmin) {
|
||||
this.osgiEventAdmin = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post(final Event event) throws IllegalArgumentException, IllegalStateException {
|
||||
EventAdmin eventAdmin = this.osgiEventAdmin;
|
||||
|
@ -64,8 +61,9 @@ public class OSGiEventPublisher implements EventPublisher {
|
|||
properties.put("type", event.getType());
|
||||
properties.put("payload", event.getPayload());
|
||||
properties.put("topic", event.getTopic());
|
||||
if (event.getSource() != null) {
|
||||
properties.put("source", event.getSource());
|
||||
String source = event.getSource();
|
||||
if (source != null) {
|
||||
properties.put("source", source);
|
||||
}
|
||||
eventAdmin.postEvent(new org.osgi.service.event.Event("openhab", properties));
|
||||
return null;
|
||||
|
|
|
@ -14,6 +14,8 @@ package org.openhab.core.items.events;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventFilter;
|
||||
import org.openhab.core.events.EventSubscriber;
|
||||
|
@ -28,6 +30,7 @@ import org.openhab.core.events.EventSubscriber;
|
|||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractItemEventSubscriber implements EventSubscriber {
|
||||
|
||||
private final Set<String> subscribedEventTypes = Set.of(ItemStateEvent.TYPE, ItemCommandEvent.TYPE);
|
||||
|
@ -38,7 +41,7 @@ public abstract class AbstractItemEventSubscriber implements EventSubscriber {
|
|||
}
|
||||
|
||||
@Override
|
||||
public EventFilter getEventFilter() {
|
||||
public @Nullable EventFilter getEventFilter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
*/
|
||||
package org.openhab.core.items.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.AbstractEvent;
|
||||
import org.openhab.core.items.ItemRegistry;
|
||||
import org.openhab.core.items.dto.ItemDTO;
|
||||
|
@ -22,6 +24,7 @@ import org.openhab.core.items.dto.ItemDTO;
|
|||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractItemRegistryEvent extends AbstractEvent {
|
||||
|
||||
private final ItemDTO item;
|
||||
|
@ -31,17 +34,17 @@ public abstract class AbstractItemRegistryEvent extends AbstractEvent {
|
|||
*
|
||||
* @param topic the topic
|
||||
* @param payload the payload
|
||||
* @param source the source, can be null
|
||||
* @param source the source
|
||||
* @param item the item data transfer object
|
||||
*/
|
||||
protected AbstractItemRegistryEvent(String topic, String payload, String source, ItemDTO item) {
|
||||
protected AbstractItemRegistryEvent(String topic, String payload, @Nullable String source, ItemDTO item) {
|
||||
super(topic, payload, source);
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item.
|
||||
*
|
||||
*
|
||||
* @return the item
|
||||
*/
|
||||
public ItemDTO getItem() {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
package org.openhab.core.items.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.items.dto.ItemDTO;
|
||||
|
||||
/**
|
||||
|
@ -20,6 +21,7 @@ import org.openhab.core.items.dto.ItemDTO;
|
|||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ItemAddedEvent extends AbstractItemRegistryEvent {
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,9 +16,10 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.AbstractEventFactory;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventFactory;
|
||||
|
@ -39,8 +40,8 @@ import org.osgi.service.component.annotations.Component;
|
|||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@Component(immediate = true, service = EventFactory.class)
|
||||
@NonNullByDefault
|
||||
public class ItemEventFactory extends AbstractEventFactory {
|
||||
|
||||
private static final String TYPE_POSTFIX = "Type";
|
||||
|
||||
private static final String CORE_LIBRARY_PACKAGE = "org.openhab.core.library.types.";
|
||||
|
@ -65,13 +66,14 @@ public class ItemEventFactory extends AbstractEventFactory {
|
|||
* Constructs a new ItemEventFactory.
|
||||
*/
|
||||
public ItemEventFactory() {
|
||||
super(Stream.of(ItemCommandEvent.TYPE, ItemStateEvent.TYPE, ItemStatePredictedEvent.TYPE,
|
||||
super(Set.of(ItemCommandEvent.TYPE, ItemStateEvent.TYPE, ItemStatePredictedEvent.TYPE,
|
||||
ItemStateChangedEvent.TYPE, ItemAddedEvent.TYPE, ItemUpdatedEvent.TYPE, ItemRemovedEvent.TYPE,
|
||||
GroupItemStateChangedEvent.TYPE).collect(Collectors.toSet()));
|
||||
GroupItemStateChangedEvent.TYPE));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Event createEventByType(String eventType, String topic, String payload, String source) throws Exception {
|
||||
protected Event createEventByType(String eventType, String topic, String payload, @Nullable String source)
|
||||
throws Exception {
|
||||
if (ItemCommandEvent.TYPE.equals(eventType)) {
|
||||
return createCommandEvent(topic, payload, source);
|
||||
} else if (ItemStateEvent.TYPE.equals(eventType)) {
|
||||
|
@ -101,14 +103,14 @@ public class ItemEventFactory extends AbstractEventFactory {
|
|||
return new GroupItemStateChangedEvent(topic, payload, itemName, memberName, state, oldState);
|
||||
}
|
||||
|
||||
private Event createCommandEvent(String topic, String payload, String source) {
|
||||
private Event createCommandEvent(String topic, String payload, @Nullable String source) {
|
||||
String itemName = getItemName(topic);
|
||||
ItemEventPayloadBean bean = deserializePayload(payload, ItemEventPayloadBean.class);
|
||||
Command command = parseType(bean.getType(), bean.getValue(), Command.class);
|
||||
return new ItemCommandEvent(topic, payload, itemName, command, source);
|
||||
}
|
||||
|
||||
private Event createStateEvent(String topic, String payload, String source) {
|
||||
private Event createStateEvent(String topic, String payload, @Nullable String source) {
|
||||
String itemName = getItemName(topic);
|
||||
ItemEventPayloadBean bean = deserializePayload(payload, ItemEventPayloadBean.class);
|
||||
State state = getState(bean.getType(), bean.getValue());
|
||||
|
@ -165,7 +167,7 @@ public class ItemEventFactory extends AbstractEventFactory {
|
|||
return desiredClass.cast(parsedObject);
|
||||
}
|
||||
|
||||
private Object parseSimpleClassName(String simpleClassName, String valueToParse) {
|
||||
private @Nullable Object parseSimpleClassName(String simpleClassName, String valueToParse) {
|
||||
if (simpleClassName.equals(UnDefType.class.getSimpleName())) {
|
||||
return UnDefType.valueOf(valueToParse);
|
||||
}
|
||||
|
@ -176,7 +178,7 @@ public class ItemEventFactory extends AbstractEventFactory {
|
|||
try {
|
||||
Class<?> stateClass = Class.forName(CORE_LIBRARY_PACKAGE + simpleClassName);
|
||||
Method valueOfMethod = stateClass.getMethod("valueOf", String.class);
|
||||
return valueOfMethod.invoke(null, valueToParse);
|
||||
return valueOfMethod.invoke(stateClass, valueToParse);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException("Error getting class for simple name: '" + simpleClassName
|
||||
+ "' using package name '" + CORE_LIBRARY_PACKAGE + "'.", e);
|
||||
|
@ -217,7 +219,7 @@ public class ItemEventFactory extends AbstractEventFactory {
|
|||
* @return the created item command event
|
||||
* @throws IllegalArgumentException if itemName or command is null
|
||||
*/
|
||||
public static ItemCommandEvent createCommandEvent(String itemName, Command command, String source) {
|
||||
public static ItemCommandEvent createCommandEvent(String itemName, Command command, @Nullable String source) {
|
||||
assertValidArguments(itemName, command, "command");
|
||||
String topic = buildTopic(ITEM_COMAND_EVENT_TOPIC, itemName);
|
||||
ItemEventPayloadBean bean = new ItemEventPayloadBean(getCommandType(command), command.toString());
|
||||
|
@ -246,7 +248,7 @@ public class ItemEventFactory extends AbstractEventFactory {
|
|||
* @return the created item state event
|
||||
* @throws IllegalArgumentException if itemName or state is null
|
||||
*/
|
||||
public static ItemStateEvent createStateEvent(String itemName, State state, String source) {
|
||||
public static ItemStateEvent createStateEvent(String itemName, State state, @Nullable String source) {
|
||||
assertValidArguments(itemName, state, "state");
|
||||
String topic = buildTopic(ITEM_STATE_EVENT_TOPIC, itemName);
|
||||
ItemEventPayloadBean bean = new ItemEventPayloadBean(getStateType(state), state.toFullString());
|
||||
|
@ -415,8 +417,8 @@ public class ItemEventFactory extends AbstractEventFactory {
|
|||
* This is a java bean that is used to serialize/deserialize item event payload.
|
||||
*/
|
||||
private static class ItemEventPayloadBean {
|
||||
private String type;
|
||||
private String value;
|
||||
private @NonNullByDefault({}) String type;
|
||||
private @NonNullByDefault({}) String value;
|
||||
|
||||
/**
|
||||
* Default constructor for deserialization e.g. by Gson.
|
||||
|
@ -443,8 +445,8 @@ public class ItemEventFactory extends AbstractEventFactory {
|
|||
* This is a java bean that is used to serialize/deserialize item state changed event payload.
|
||||
*/
|
||||
private static class ItemStatePredictedEventPayloadBean {
|
||||
private String predictedType;
|
||||
private String predictedValue;
|
||||
private @NonNullByDefault({}) String predictedType;
|
||||
private @NonNullByDefault({}) String predictedValue;
|
||||
private boolean isConfirmation;
|
||||
|
||||
/**
|
||||
|
@ -477,10 +479,10 @@ public class ItemEventFactory extends AbstractEventFactory {
|
|||
* This is a java bean that is used to serialize/deserialize item state changed event payload.
|
||||
*/
|
||||
private static class ItemStateChangedEventPayloadBean {
|
||||
private String type;
|
||||
private String value;
|
||||
private String oldType;
|
||||
private String oldValue;
|
||||
private @NonNullByDefault({}) String type;
|
||||
private @NonNullByDefault({}) String value;
|
||||
private @NonNullByDefault({}) String oldType;
|
||||
private @NonNullByDefault({}) String oldValue;
|
||||
|
||||
/**
|
||||
* Default constructor for deserialization e.g. by Gson.
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
package org.openhab.core.items.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.items.dto.ItemDTO;
|
||||
|
||||
/**
|
||||
|
@ -20,6 +21,7 @@ import org.openhab.core.items.dto.ItemDTO;
|
|||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ItemRemovedEvent extends AbstractItemRegistryEvent {
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
package org.openhab.core.items.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.items.dto.ItemDTO;
|
||||
|
||||
/**
|
||||
|
@ -20,6 +21,7 @@ import org.openhab.core.items.dto.ItemDTO;
|
|||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ItemUpdatedEvent extends AbstractItemRegistryEvent {
|
||||
|
||||
private final ItemDTO oldItem;
|
||||
|
@ -49,7 +51,7 @@ public class ItemUpdatedEvent extends AbstractItemRegistryEvent {
|
|||
|
||||
/**
|
||||
* Gets the old item.
|
||||
*
|
||||
*
|
||||
* @return the oldItem
|
||||
*/
|
||||
public ItemDTO getOldItem() {
|
||||
|
|
|
@ -10,18 +10,20 @@
|
|||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.items.events;
|
||||
package org.openhab.core.events;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.events.AbstractEventFactory;
|
||||
import org.openhab.core.items.events.ItemEventFactory;
|
||||
|
||||
/**
|
||||
* {@link AbstractEventFactoryTests} tests the {@link AbstractEventFactory}.
|
||||
* {@link AbstractEventFactoryTests} tests the {@link org.openhab.core.events.AbstractEventFactory}.
|
||||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AbstractEventFactoryTest {
|
||||
private final ItemEventFactory factory = new ItemEventFactory();
|
||||
|
|
@ -16,6 +16,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.items.Item;
|
||||
|
@ -36,6 +37,7 @@ import com.google.gson.Gson;
|
|||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ItemEventFactoryTest {
|
||||
private final ItemEventFactory factory = new ItemEventFactory();
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ import org.openhab.core.library.types.OnOffType;
|
|||
import org.openhab.core.service.ReadyMarker;
|
||||
import org.openhab.core.test.java.JavaOSGiTest;
|
||||
import org.openhab.core.test.storage.VolatileStorageService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.TypeParser;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -417,8 +418,11 @@ public class RuntimeRuleTest extends JavaOSGiTest {
|
|||
final ItemRegistry itemRegistry = getService(ItemRegistry.class);
|
||||
final EventPublisher eventPublisher = getService(EventPublisher.class);
|
||||
final Item myMotionItem = itemRegistry.getItem("myMotionItem3");
|
||||
eventPublisher.post(ItemEventFactory.createCommandEvent("myMotionItem3",
|
||||
TypeParser.parseCommand(myMotionItem.getAcceptedCommandTypes(), "ON")));
|
||||
Command command = TypeParser.parseCommand(myMotionItem.getAcceptedCommandTypes(), "ON");
|
||||
assertNotNull(command);
|
||||
if (command != null) {
|
||||
eventPublisher.post(ItemEventFactory.createCommandEvent("myMotionItem3", command));
|
||||
}
|
||||
|
||||
waitForAssert(() -> {
|
||||
assertEquals(RuleStatusDetail.DISABLED, ruleEngine.getStatusInfo(firstRuleUID).getStatusDetail());
|
||||
|
@ -438,8 +442,11 @@ public class RuntimeRuleTest extends JavaOSGiTest {
|
|||
.build();
|
||||
ruleRegistry.add(rule2);
|
||||
|
||||
eventPublisher.post(ItemEventFactory.createCommandEvent("myMotionItem3",
|
||||
TypeParser.parseCommand(myMotionItem.getAcceptedCommandTypes(), "OFF")));
|
||||
command = TypeParser.parseCommand(myMotionItem.getAcceptedCommandTypes(), "OFF");
|
||||
assertNotNull(command);
|
||||
if (command != null) {
|
||||
eventPublisher.post(ItemEventFactory.createCommandEvent("myMotionItem3", command));
|
||||
}
|
||||
|
||||
waitForAssert(() -> {
|
||||
assertEquals(RuleStatus.IDLE, ruleEngine.getStatus(firstRuleUID));
|
||||
|
|
|
@ -180,16 +180,6 @@ public class OSGiEventManagerOSGiTest extends JavaOSGiTest {
|
|||
assertEventCount(subscriber4, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidationEvent() {
|
||||
try {
|
||||
eventPublisher.post(null);
|
||||
fail("IllegalArgumentException expected!");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("Argument 'event' must not be null.", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidationType() {
|
||||
Event event = createEvent(null, "{a: 'A', b: 'B'}", TOPIC);
|
||||
|
|
Loading…
Reference in New Issue