/** * 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.expire.internal; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.openhab.binding.expire.ExpireBindingProvider; import org.openhab.core.binding.BindingConfig; import org.openhab.core.items.Item; import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.openhab.core.types.TypeParser; import org.openhab.core.types.UnDefType; import org.openhab.model.item.binding.AbstractGenericBindingProvider; import org.openhab.model.item.binding.BindingConfigParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class is responsible for parsing the binding configuration. * * @author Michael Wyraz -- initial implementation * @author John Cocula -- added command support, tweaks * @since 1.9.0 */ public class ExpireGenericBindingProvider extends AbstractGenericBindingProvider implements ExpireBindingProvider { private static final Logger logger = LoggerFactory.getLogger(ExpireGenericBindingProvider.class); /** * {@inheritDoc} */ @Override public String getBindingType() { return "expire"; } /** * {@inheritDoc} */ @Override public void validateItemType(Item item, String bindingConfig) throws BindingConfigParseException { // valid for any item type } /** * {@inheritDoc} */ @Override public void processBindingConfiguration(String context, Item item, String bindingConfig) throws BindingConfigParseException { ExpireBindingConfig config = new ExpireBindingConfig(item, bindingConfig); logger.debug("Processed binding config for item {}: {}", item.getName(), config); super.processBindingConfiguration(context, item, bindingConfig); addBindingConfig(item, config); } @Override public long getDuration(String itemName) { return getItemConfig(itemName).duration; } @Override public String getDurationString(String itemName) { return getItemConfig(itemName).durationString; } @Override public State getExpireState(String itemName) { return getItemConfig(itemName).expireState; } @Override public Command getExpireCommand(String itemName) { return getItemConfig(itemName).expireCommand; } private ExpireBindingConfig getItemConfig(String itemName) { return (ExpireBindingConfig) bindingConfigs.get(itemName); } /** * This is a helper class holding binding specific configuration details * * @author Michael Wyraz * @since 1.9.0 */ private static class ExpireBindingConfig implements BindingConfig { protected static final Pattern durationPattern = Pattern .compile("(?:([0-9]+)H)?\\s*(?:([0-9]+)M)?\\s*(?:([0-9]+)S)?", Pattern.CASE_INSENSITIVE); protected static final String COMMAND_PREFIX = "command="; protected static final String STATE_PREFIX = "state="; /** * Human readable textual representation of duration (e.g. "13h 42m 12s") */ protected String durationString; /** * duration in ms */ protected long duration; /** * state to post if item is expired. */ protected State expireState; /** * command to post if item is expired. */ protected Command expireCommand; private long parseDuration(String duration) throws BindingConfigParseException { Matcher m = durationPattern.matcher(duration); if (!m.matches() || (m.group(1) == null && m.group(2) == null && m.group(3) == null)) { throw new BindingConfigParseException( "Invalid duration: " + duration + ". Expected something like: '1h 15m 30s'"); } long ms = 0; if (m.group(1) != null) { ms += Long.parseLong(m.group(1)) * 60 * 60 * 1000; } if (m.group(2) != null) { ms += Long.parseLong(m.group(2)) * 60 * 1000; } if (m.group(3) != null) { ms += Long.parseLong(m.group(3)) * 1000; } return ms; } /** * Construct an ExpireBindingConfig from the {@code bindingConfig} string. * * Valid syntax: * * {@code <duration>[,[state=|command=|]<stateOrCommand>]}<br> * if neither state= or command= is present, assume state * * @param item the item to which we are bound * @param bindingConfig the string that the user specified in the .items file * @throws BindingConfigParseException if it is ill-formatted */ ExpireBindingConfig(Item item, String bindingConfig) throws BindingConfigParseException { int commaPos = bindingConfig.indexOf(','); durationString = (commaPos >= 0) ? bindingConfig.substring(0, commaPos).trim() : bindingConfig.trim(); duration = parseDuration(durationString); String stateOrCommand = ((commaPos >= 0) && (bindingConfig.length() - 1) > commaPos) ? bindingConfig.substring(commaPos + 1).trim() : null; if ((stateOrCommand != null) && (stateOrCommand.length() > 0)) { if (stateOrCommand.startsWith(COMMAND_PREFIX)) { String commandString = stateOrCommand.substring(COMMAND_PREFIX.length()); expireCommand = TypeParser.parseCommand(item.getAcceptedCommandTypes(), commandString); if (expireCommand == null) { throw new BindingConfigParseException("The string '" + commandString + "' does not represent a valid command for item " + item.getName()); } } else { if (stateOrCommand.startsWith(STATE_PREFIX)) { stateOrCommand = stateOrCommand.substring(STATE_PREFIX.length()); } String stateString = stateOrCommand; expireState = TypeParser.parseState(item.getAcceptedDataTypes(), stateString); if (expireState == null) { throw new BindingConfigParseException("The string '" + stateString + "' does not represent a valid state for item " + item.getName()); } } } else { // default is to post Undefined state expireCommand = null; expireState = UnDefType.UNDEF; } } @Override public String toString() { return "duration='" + durationString + "', ms=" + duration + ", state='" + expireState + "', command='" + expireCommand + "'"; } } }