/** * 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.owserver.internal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.openhab.binding.owserver.OWServerBindingProvider; import org.openhab.core.binding.BindingConfig; import org.openhab.core.items.Item; import org.openhab.core.library.types.StringType; import org.openhab.core.types.Command; import org.openhab.model.item.binding.AbstractGenericBindingProvider; import org.openhab.model.item.binding.BindingConfigParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * <p> * This class parses the EDS OWServer item binding data. It registers as a * {@link OWServerBindingProvider} service as well. * </p> * * <p> * Here are some examples for valid binding configuration strings: * <ul> * <li><code>{ owserver="<serverId:F90000012A608428:PrimaryValue:2000" }</code></li> * <li><code>{ owserver="<serverId:53000000224EA612:Temperature:10000" }</code></li> * <li><code>{ owserver="<serverId:5A0010000021D57E:DewPoint:10000" }</code></li> * <li><code>{ owserver="<serverId:FC00000310120B1D:Counter_B:10000" }</code></li> * </ul> * * The 'serverId' referenced in the binding string is configured in the openhab.cfg file -: * owserver.serverId.host = 192.168.2.1 * * 'serverId' can be any alphanumeric string as long as it is the same in the binding and * configuration file. <b>NOTE</b>: The parameter is case sensitive! * * @author Chris Jackson * @since 1.3.0 */ public class OWServerGenericBindingProvider extends AbstractGenericBindingProvider implements OWServerBindingProvider { static final Logger logger = LoggerFactory.getLogger(OWServerGenericBindingProvider.class); /** * Artificial command for the owserver-in configuration */ protected static final Command IN_BINDING_KEY = StringType.valueOf("IN_BINDING"); /** {@link Pattern} which matches a binding configuration part */ private static final Pattern BASE_CONFIG_PATTERN = Pattern .compile("(<|>)([0-9.a-zA-Z]+:[0-9.a-zA-Z]+:[0-9._a-zA-Z]+:[0-9]+)"); /** {@link Pattern} which matches an In-Binding */ private static final Pattern IN_BINDING_PATTERN = Pattern .compile("([0-9.a-zA-Z]+):([0-9.a-zA-Z]+):([0-9._a-zA-Z]+):([0-9]+)"); /** * {@inheritDoc} */ @Override public String getBindingType() { return "owserver"; } /** * @{inheritDoc} */ @Override public void validateItemType(Item item, String bindingConfig) throws BindingConfigParseException { } /** * {@inheritDoc} */ @Override public void processBindingConfiguration(String context, Item item, String bindingConfig) throws BindingConfigParseException { super.processBindingConfiguration(context, item, bindingConfig); if (bindingConfig != null) { OWServerBindingConfig config = parseBindingConfig(item, bindingConfig); addBindingConfig(item, config); } else { logger.warn("bindingConfig is NULL (item=" + item + ") -> process bindingConfig aborted!"); } } /** * Delegates parsing the <code>bindingConfig</code> with respect to the * first character (<code><</code> or <code>></code>) to the * specialized parsing methods * * @param item * @param bindingConfig * * @throws BindingConfigParseException */ protected OWServerBindingConfig parseBindingConfig(Item item, String bindingConfig) throws BindingConfigParseException { OWServerBindingConfig config = new OWServerBindingConfig(); config.itemType = item.getClass(); Matcher matcher = BASE_CONFIG_PATTERN.matcher(bindingConfig); if (!matcher.matches()) { throw new BindingConfigParseException( "bindingConfig '" + bindingConfig + "' doesn't contain a valid binding configuration"); } matcher.reset(); while (matcher.find()) { String direction = matcher.group(1); String bindingConfigPart = matcher.group(2); if (direction.equals("<")) { config = parseInBindingConfig(item, bindingConfigPart, config); } else if (direction.equals(">")) { // for future use } else { throw new BindingConfigParseException( "Unknown command given! Configuration must start with '<' or '>' "); } } return config; } /** * Parses a owserver-in configuration by using the regular expression * <code>([0-9.a-zA-Z]+:[0-9.a-zA-Z]+:[0-9._a-zA-Z]+:[0-9]+)</code>. Where the groups should * contain the following content: * <ul> * <li>1 - Server ID</li> * <li>2 - One Wire ROM ID</li> * <li>3 - Variable name</li> * <li>4 - Refresh Interval</li> * </ul> * * @param item * @param bindingConfig the config string to parse * @param config * * @return the filled {@link OWServerBindingConfig} * @throws BindingConfigParseException if the regular expression doesn't match * the given <code>bindingConfig</code> */ protected OWServerBindingConfig parseInBindingConfig(Item item, String bindingConfig, OWServerBindingConfig config) throws BindingConfigParseException { Matcher matcher = IN_BINDING_PATTERN.matcher(bindingConfig); if (!matcher.matches()) { throw new BindingConfigParseException("bindingConfig '" + bindingConfig + "' doesn't represent a valid in-binding-configuration. A valid configuration is matched by the RegExp '" + IN_BINDING_PATTERN + "'"); } matcher.reset(); OWServerBindingConfigElement configElement; while (matcher.find()) { configElement = new OWServerBindingConfigElement(); configElement.serverId = matcher.group(1); configElement.romId = matcher.group(2); configElement.name = matcher.group(3); configElement.refreshInterval = Integer.valueOf(matcher.group(4)).intValue(); logger.debug("OWSERVER: " + configElement); config.put(IN_BINDING_KEY, configElement); } return config; } /** * @{inheritDoc} */ @Override public Class<? extends Item> getItemType(String itemName) { OWServerBindingConfig config = (OWServerBindingConfig) bindingConfigs.get(itemName); return config != null ? config.itemType : null; } /** * {@inheritDoc} */ @Override public String getServerId(String itemName) { OWServerBindingConfig config = (OWServerBindingConfig) bindingConfigs.get(itemName); return config != null && config.get(IN_BINDING_KEY) != null ? config.get(IN_BINDING_KEY).serverId : null; } /** * {@inheritDoc} */ @Override public String getRomId(String itemName) { OWServerBindingConfig config = (OWServerBindingConfig) bindingConfigs.get(itemName); return config != null && config.get(IN_BINDING_KEY) != null ? config.get(IN_BINDING_KEY).romId : null; } /** * {@inheritDoc} */ @Override public String getName(String itemName) { OWServerBindingConfig config = (OWServerBindingConfig) bindingConfigs.get(itemName); return config != null && config.get(IN_BINDING_KEY) != null ? config.get(IN_BINDING_KEY).name : null; } /** * {@inheritDoc} */ @Override public int getRefreshInterval(String itemName) { OWServerBindingConfig config = (OWServerBindingConfig) bindingConfigs.get(itemName); return config != null && config.get(IN_BINDING_KEY) != null ? config.get(IN_BINDING_KEY).refreshInterval : 0; } /** * {@inheritDoc} */ @Override public List<String> getInBindingItemNames() { List<String> inBindings = new ArrayList<String>(); for (String itemName : bindingConfigs.keySet()) { OWServerBindingConfig httpConfig = (OWServerBindingConfig) bindingConfigs.get(itemName); if (httpConfig.containsKey(IN_BINDING_KEY)) { inBindings.add(itemName); } } return inBindings; } /** * This is an internal data structure to map commands to * {@link OWServerBindingConfigElement }. There will be map like * <code>ON->OWServerBindingConfigElement</code> */ static class OWServerBindingConfig extends HashMap<Command, OWServerBindingConfigElement>implements BindingConfig { private static final long serialVersionUID = 946984678609385662L; /** generated serialVersion UID */ Class<? extends Item> itemType; } /** * This is an internal data structure to store information from the binding * config strings and use it to answer the requests to the HTTP binding * provider. */ static class OWServerBindingConfigElement implements BindingConfig { public String serverId; public String romId; public String name; public int refreshInterval; @Override public String toString() { return "OWServerBindingConfigElement [serverId=" + serverId + ", romId=" + romId + ", name=" + name + ", refreshInterval=" + refreshInterval + "]"; } } }