/** * 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.horizon.internal; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.naming.ConfigurationException; import org.openhab.binding.horizon.HorizonBindingProvider; import org.openhab.binding.horizon.internal.control.HorizonBox; import org.openhab.core.binding.AbstractBinding; import org.openhab.core.types.Command; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Implement this class if you are going create an actively polling service like * querying a Website/Device. * * @author Jurgen Kuijpers * @since 1.9.0 */ public class HorizonBinding extends AbstractBinding<HorizonBindingProvider> { private static final Logger logger = LoggerFactory.getLogger(HorizonBinding.class); private final static int DEFAULT_HORIZON_PORT = 5900; private static final Pattern EXTRACT_HORIZON_CONFIG_PATTERN = Pattern.compile("^(.*?)\\.(host)$"); protected Map<String, HorizonBox> deviceConfigCache = new HashMap<String, HorizonBox>(); public HorizonBinding() { } protected void addBindingProvider(HorizonBindingProvider provider) { super.addBindingProvider(provider); } protected void removeBindingProvider(HorizonBindingProvider provider) { super.removeBindingProvider(provider); } /** * Called by the SCR to activate the component with its configuration read * from CAS * * @param bundleContext * BundleContext of the Bundle that defines this component * @param configuration * Configuration properties for this component obtained from the * ConfigAdmin service * @throws ConfigurationException */ public void activate(final BundleContext bundleContext, final Map<String, Object> configuration) throws ConfigurationException { if (configuration != null) { updateConfiguration(configuration); } } /** * Called by the SCR when the configuration of a binding has been changed * through the ConfigAdmin service. * * @param configuration * Updated configuration properties * @throws ConfigurationException */ public void modified(final Map<String, Object> configuration) throws ConfigurationException { if (configuration != null) { updateConfiguration(configuration); } } /** * {@inheritDoc} */ @Override protected void internalReceiveCommand(String itemName, Command command) { logger.debug("internalReceiveCommand({},{}) is called!", itemName, command); HorizonBindingProvider horizonBindingProvider = findFirstMatchingBindingProvider(itemName, command); String horizonKeyWithHorizonId = horizonBindingProvider.getHorizonCommand(itemName, command.toString()); String[] horizonKeyWithHorizonIdSplit = horizonKeyWithHorizonId.split(":"); String horizonId = horizonKeyWithHorizonIdSplit[0]; String horizonKey = horizonKeyWithHorizonIdSplit[1]; HorizonBox horizonBox = deviceConfigCache.get(horizonId); if (horizonBox != null) { try { horizonBox.sendKey(Integer.valueOf(horizonKey)); } catch (Exception e) { logger.error("Error sending key to device with device id '{}'", horizonId, e); } } else { logger.warn("Cannot find connection details for device id '{}'", horizonId); } } private void updateConfiguration(final Map<String, Object> configuration) throws ConfigurationException { Set<String> keys = configuration.keySet(); Iterator<String> keysIt = keys.iterator(); while (keysIt.hasNext()) { String key = keysIt.next(); if ("service.pid".equals(key)) { continue; } Matcher matcher = EXTRACT_HORIZON_CONFIG_PATTERN.matcher(key); if (!matcher.matches()) { logger.debug("given config key '" + key + "' does not follow the expected pattern '<id>.<host>'"); continue; } matcher.reset(); matcher.find(); String deviceId = matcher.group(1); String host = null; String configKey = matcher.group(2); String value = (String) configuration.get(key); if ("host".equals(configKey)) { host = value; } else { throw new ConfigurationException("The given configKey '" + configKey + "' is unknown"); } HorizonBox horizonBox = new HorizonBox(host, DEFAULT_HORIZON_PORT); deviceConfigCache.put(deviceId, horizonBox); } } /** * Find the first matching {@link HorizonBindingProvider} according to * <code>itemName</code> and <code>command</code>. If no direct match is * found, a second match is issued with wilcard-command '*'. * * @param itemName * @param command * * @return the matching binding provider or <code>null</code> if no binding * provider could be found */ private HorizonBindingProvider findFirstMatchingBindingProvider(String itemName, Command command) { HorizonBindingProvider firstMatchingProvider = null; for (HorizonBindingProvider provider : this.providers) { String commandLine = provider.getHorizonCommand(itemName, command.toString()); if (commandLine != null) { firstMatchingProvider = provider; break; } } return firstMatchingProvider; } }