/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.core.thing.events;
import java.util.List;
import org.eclipse.smarthome.core.events.AbstractEventFactory;
import org.eclipse.smarthome.core.events.Event;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatusInfo;
import org.eclipse.smarthome.core.thing.ThingUID;
import org.eclipse.smarthome.core.thing.dto.ThingDTO;
import org.eclipse.smarthome.core.thing.dto.ThingDTOMapper;
import org.eclipse.smarthome.core.types.Type;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* A {@link ThingEventFactory} is responsible for creating thing event instances, e.g. {@link ThingStatusInfoEvent}s.
*
* @author Stefan Bußweiler - Initial contribution
* @author Dennis Nobel - Added status changed event
*/
public class ThingEventFactory extends AbstractEventFactory {
private static final String THING_STATUS_INFO_EVENT_TOPIC = "smarthome/things/{thingUID}/status";
private static final String THING_STATUS_INFO_CHANGED_EVENT_TOPIC = "smarthome/things/{thingUID}/statuschanged";
private static final String THING_ADDED_EVENT_TOPIC = "smarthome/things/{thingUID}/added";
private static final String THING_REMOVED_EVENT_TOPIC = "smarthome/things/{thingUID}/removed";
private static final String THING_UPDATED_EVENT_TOPIC = "smarthome/things/{thingUID}/updated";
private static final String CHANNEL_TRIGGERED_EVENT_TOPIC = "smarthome/channels/{channelUID}/triggered";
/**
* Constructs a new ThingEventFactory.
*/
public ThingEventFactory() {
super(Sets.newHashSet(ThingStatusInfoEvent.TYPE, ThingStatusInfoChangedEvent.TYPE, ThingAddedEvent.TYPE,
ThingRemovedEvent.TYPE, ThingUpdatedEvent.TYPE, ChannelTriggeredEvent.TYPE));
}
@Override
protected Event createEventByType(String eventType, String topic, String payload, String source) throws Exception {
Event event = null;
if (eventType.equals(ThingStatusInfoEvent.TYPE)) {
event = createStatusInfoEvent(topic, payload);
} else if (eventType.equals(ThingStatusInfoChangedEvent.TYPE)) {
event = createStatusInfoChangedEvent(topic, payload);
} else if (eventType.equals(ThingAddedEvent.TYPE)) {
event = createAddedEvent(topic, payload);
} else if (eventType.equals(ThingRemovedEvent.TYPE)) {
event = createRemovedEvent(topic, payload);
} else if (eventType.equals(ThingUpdatedEvent.TYPE)) {
event = createUpdatedEvent(topic, payload);
} else if (eventType.equals(ChannelTriggeredEvent.TYPE)) {
event = createTriggerEvent(topic, payload, source);
}
return event;
}
/**
* This is a java bean that is used to serialize/deserialize trigger event payload.
*/
public static class TriggerEventPayloadBean {
private String event;
private String channel;
/**
* Default constructor for deserialization e.g. by Gson.
*/
protected TriggerEventPayloadBean() {
}
public TriggerEventPayloadBean(String event, String channel) {
this.event = event;
this.channel = channel;
}
public String getEvent() {
return event;
}
public String getChannel() {
return channel;
}
}
/**
* Creates a trigger event from a {@link Type}.
*
* @param event Event.
* @param channel Channel which triggered the event.
* @return Created trigger event.
*/
public static ChannelTriggeredEvent createTriggerEvent(String event, ChannelUID channel) {
TriggerEventPayloadBean bean = new TriggerEventPayloadBean(event, channel.getAsString());
String payload = serializePayload(bean);
String topic = buildTopic(CHANNEL_TRIGGERED_EVENT_TOPIC, channel);
return new ChannelTriggeredEvent(topic, payload, null, event, channel);
}
/**
* Creates a trigger event from a payload.
*
* @param topic Event topic
* @param source Event source
* @param payload Payload
* @return created trigger event
*/
public ChannelTriggeredEvent createTriggerEvent(String topic, String payload, String source) {
TriggerEventPayloadBean bean = deserializePayload(payload, TriggerEventPayloadBean.class);
ChannelUID channel = new ChannelUID(bean.getChannel());
return new ChannelTriggeredEvent(topic, payload, source, bean.getEvent(), channel);
}
private Event createStatusInfoEvent(String topic, String payload) throws Exception {
String[] topicElements = getTopicElements(topic);
if (topicElements.length != 4) {
throw new IllegalArgumentException("ThingStatusInfoEvent creation failed, invalid topic: " + topic);
}
ThingUID thingUID = new ThingUID(topicElements[2]);
ThingStatusInfo thingStatusInfo = deserializePayload(payload, ThingStatusInfo.class);
return new ThingStatusInfoEvent(topic, payload, thingUID, thingStatusInfo);
}
private Event createStatusInfoChangedEvent(String topic, String payload) throws Exception {
String[] topicElements = getTopicElements(topic);
if (topicElements.length != 4) {
throw new IllegalArgumentException("ThingStatusInfoChangedEvent creation failed, invalid topic: " + topic);
}
ThingUID thingUID = new ThingUID(topicElements[2]);
ThingStatusInfo[] thingStatusInfo = deserializePayload(payload, ThingStatusInfo[].class);
return new ThingStatusInfoChangedEvent(topic, payload, thingUID, thingStatusInfo[0], thingStatusInfo[1]);
}
private Event createAddedEvent(String topic, String payload) throws Exception {
ThingDTO thingDTO = deserializePayload(payload, ThingDTO.class);
return new ThingAddedEvent(topic, payload, thingDTO);
}
private Event createRemovedEvent(String topic, String payload) throws Exception {
ThingDTO thingDTO = deserializePayload(payload, ThingDTO.class);
return new ThingRemovedEvent(topic, payload, thingDTO);
}
private Event createUpdatedEvent(String topic, String payload) throws Exception {
ThingDTO[] thingDTO = deserializePayload(payload, ThingDTO[].class);
if (thingDTO.length != 2) {
throw new IllegalArgumentException("ThingUpdateEvent creation failed, invalid payload: " + payload);
}
return new ThingUpdatedEvent(topic, payload, thingDTO[0], thingDTO[1]);
}
/**
* Creates a new thing status info event based on a thing UID and a thing status info object.
*
* @param thingUID the thing UID
* @param thingStatusInfo the thing status info object
*
* @return the created thing status info event
*
* @throws IllegalArgumentException if thingUID or thingStatusInfo is null
*/
public static ThingStatusInfoEvent createStatusInfoEvent(ThingUID thingUID, ThingStatusInfo thingStatusInfo) {
Preconditions.checkArgument(thingUID != null, "The argument 'thingUID' must not be null.");
Preconditions.checkArgument(thingStatusInfo != null, "The argument 'thingStatusInfo' must not be null.");
String topic = buildTopic(THING_STATUS_INFO_EVENT_TOPIC, thingUID);
String payload = serializePayload(thingStatusInfo);
return new ThingStatusInfoEvent(topic, payload, thingUID, thingStatusInfo);
}
/**
* Creates a new thing status info changed event based on a thing UID, a thing status info and the old thing status
* info object.
*
* @param thingUID the thing UID
* @param thingStatusInfo the thing status info object
* @param oldThingStatusInfo the old thing status info object
*
* @return the created thing status info changed event
*
* @throws IllegalArgumentException if thingUID or thingStatusInfo is null
*/
public static ThingStatusInfoChangedEvent createStatusInfoChangedEvent(ThingUID thingUID,
ThingStatusInfo thingStatusInfo, ThingStatusInfo oldThingStatusInfo) {
Preconditions.checkArgument(thingUID != null, "The argument 'thingUID' must not be null.");
Preconditions.checkArgument(thingStatusInfo != null, "The argument 'thingStatusInfo' must not be null.");
Preconditions.checkArgument(oldThingStatusInfo != null, "The argument 'oldThingStatusInfo' must not be null.");
String topic = buildTopic(THING_STATUS_INFO_CHANGED_EVENT_TOPIC, thingUID);
String payload = serializePayload(new ThingStatusInfo[] { thingStatusInfo, oldThingStatusInfo });
return new ThingStatusInfoChangedEvent(topic, payload, thingUID, thingStatusInfo, oldThingStatusInfo);
}
/**
* Creates a thing added event.
*
* @param thing the thing
*
* @return the created thing added event
*
* @throws IllegalArgumentException if thing is null
*/
public static ThingAddedEvent createAddedEvent(Thing thing) {
assertValidArgument(thing);
String topic = buildTopic(THING_ADDED_EVENT_TOPIC, thing.getUID());
ThingDTO thingDTO = map(thing);
String payload = serializePayload(thingDTO);
return new ThingAddedEvent(topic, payload, thingDTO);
}
/**
* Creates a thing removed event.
*
* @param thing the thing
*
* @return the created thing removed event
*
* @throws IllegalArgumentException if thing is null
*/
public static ThingRemovedEvent createRemovedEvent(Thing thing) {
assertValidArgument(thing);
String topic = buildTopic(THING_REMOVED_EVENT_TOPIC, thing.getUID());
ThingDTO thingDTO = map(thing);
String payload = serializePayload(thingDTO);
return new ThingRemovedEvent(topic, payload, thingDTO);
}
/**
* Creates a thing updated event.
*
* @param thing the thing
* @param oldThing the old thing
*
* @return the created thing updated event
*
* @throws IllegalArgumentException if thing or oldThing is null
*/
public static ThingUpdatedEvent createUpdateEvent(Thing thing, Thing oldThing) {
assertValidArgument(thing);
assertValidArgument(oldThing);
String topic = buildTopic(THING_UPDATED_EVENT_TOPIC, thing.getUID());
ThingDTO thingDTO = map(thing);
ThingDTO oldThingDTO = map(oldThing);
List<ThingDTO> thingDTOs = Lists.newLinkedList();
thingDTOs.add(thingDTO);
thingDTOs.add(oldThingDTO);
String payload = serializePayload(thingDTOs);
return new ThingUpdatedEvent(topic, payload, thingDTO, oldThingDTO);
}
private static void assertValidArgument(Thing thing) {
Preconditions.checkArgument(thing != null, "The argument 'thing' must not be null.");
Preconditions.checkArgument(thing.getUID() != null, "The thingUID of a thing must not be null.");
}
private static String buildTopic(String topic, ThingUID thingUID) {
return topic.replace("{thingUID}", thingUID.getAsString());
}
private static String buildTopic(String topic, ChannelUID channelUID) {
return topic.replace("{channelUID}", channelUID.getAsString());
}
private static ThingDTO map(Thing thing) {
return ThingDTOMapper.map(thing);
}
}