/**
* Copyright (c) 2010-2016 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.openhab.binding.mqtt.internal;
import org.apache.commons.lang.StringUtils;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.io.transport.mqtt.MqttMessageProducer;
import org.openhab.io.transport.mqtt.MqttSenderChannel;
import org.openhab.model.item.binding.BindingConfigParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Message publisher configuration for items which send outbound MQTT messages.
*
* @author Davy Vanherbergen
* @since 1.3.0
*/
public class MqttMessagePublisher extends AbstractMqttMessagePubSub implements MqttMessageProducer {
private static final Logger logger = LoggerFactory.getLogger(MqttMessagePublisher.class);
private MqttSenderChannel senderChannel;
private String trigger;
/**
* Create new MqttMessagePublisher from config string.
*
* @param configuration
* config string
* @throws BindingConfigParseException
* if the config string is invalid
*/
public MqttMessagePublisher(String configuration) throws BindingConfigParseException {
String[] config = splitConfigurationString(configuration);
try {
if (config.length != 5) {
throw new BindingConfigParseException("Configuration requires 5 parameters separated by ':'");
}
if (StringUtils.isEmpty(config[0])) {
throw new BindingConfigParseException("Missing broker name.");
} else {
setBroker(config[0].trim());
}
if (StringUtils.isEmpty(config[1]) || config[1].indexOf('+') != -1 || config[1].indexOf('#') != -1) {
throw new BindingConfigParseException("Invalid topic.");
} else {
setTopic(config[1].trim());
}
if (StringUtils.isEmpty(config[2])) {
throw new BindingConfigParseException("Missing type.");
} else {
try {
MessageType t = MessageType.valueOf(config[2].trim().toUpperCase());
setMessageType(t);
} catch (IllegalArgumentException e) {
throw new BindingConfigParseException("Invalid type.");
}
}
if (StringUtils.isEmpty(config[3])) {
throw new BindingConfigParseException("Missing trigger.");
} else {
trigger = config[3].trim();
}
if (StringUtils.isEmpty(config[4])) {
throw new BindingConfigParseException("Missing transformation configuration.");
} else {
setTransformationRule(config[4].trim());
initTransformService();
}
} catch (BindingConfigParseException e) {
throw new BindingConfigParseException(
"Configuration '" + configuration + "' is not a valid outbound configuration: " + e.getMessage());
}
}
/**
* Check if this configuration supports processing of the given State.
*
* @param state
* for which to check if we can process.
* @return true if processing is supported.
*/
public boolean supportsState(State state) {
if (getMessageType().equals(MessageType.COMMAND)) {
return false;
}
if (getTrigger().equals("*")) {
return true;
}
return trigger.equalsIgnoreCase(state.toString());
}
/**
* Check if this configuration supports processing of the given Command.
*
* @param command
* for which to check if we can process.
* @return true if processing is supported.
*/
public boolean supportsCommand(Command command) {
if (getMessageType().equals(MessageType.STATE)) {
return false;
}
if (getTrigger().equals("*")) {
return true;
}
return trigger.equalsIgnoreCase(command.toString());
}
/**
* Compose the message to be sent. When a transformation is defined, this
* will be applied to the message content. After the transformation is
* performed, the default parameters are replaced in the content string.
*
* @param value
* command or state in string representation.
* @return message content.
* @throws Exception
*/
private byte[] createMessage(String value) throws Exception {
if (getTransformationServiceName() != null && getTransformationService() == null) {
logger.debug("Sending message before transformation service '{}' was initialized.");
initTransformService();
}
String content = value;
if (getTransformationService() != null) {
content = getTransformationService().transform(getTransformationServiceParam(), value);
} else if (getTransformationRule() != null && !getTransformationRule().equalsIgnoreCase("default")) {
content = getTransformationRule();
}
if (getMessageType().equals(MessageType.STATE)) {
content = StringUtils.replace(content, "${state}", value);
} else {
content = StringUtils.replace(content, "${command}", value);
}
content = StringUtils.replace(content, "${itemName}", getItemName());
return content.getBytes();
}
/**
* Publish a messge to the given topic.
*
* @param topic
* @param message
*/
public void publish(String topic, byte[] message) {
if (senderChannel == null) {
return;
}
try {
senderChannel.publish(topic, createMessage(new String(message)));
} catch (Exception e) {
logger.error("Error publishing...", e);
}
}
@Override
public void setSenderChannel(MqttSenderChannel channel) {
senderChannel = channel;
}
/**
* @return string representation of state or command which triggers the
* sending of a message.
*/
public String getTrigger() {
return trigger;
}
/**
* @return true if this publisher has been activated by the
* MqttBrokerConnection.
*/
public boolean isActivated() {
return senderChannel != null;
}
/**
* Get the topic and replace ${item} in the topic with the actual name.
*/
public String getTopic(String itemName) {
return StringUtils.replace(getTopic(), "${item}", itemName);
}
}