Package org.openhab.binding.insteonplm.internal.device

Source Code of org.openhab.binding.insteonplm.internal.device.DeviceFeature

/**
* Copyright (c) 2010-2013, openHAB.org and others.
*
* 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.insteonplm.internal.device;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.openhab.binding.insteonplm.InsteonPLMBindingConfig;
import org.openhab.binding.insteonplm.internal.message.Msg;
import org.openhab.binding.insteonplm.internal.utils.Utils.ParsingException;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A DeviceFeature represents a certain feature (trait) of a given Insteon device, e.g. something
* operating under a given InsteonAddress that can be manipulated (relay) or read (sensor).
*
* The DeviceFeature does the processing of incoming messages, and handles commands for the
* particular feature it represents.
*
* It uses four mechanisms for that:
*
* 1) MessageDispatcher: makes high level decisions about an incoming message and then runs the
* 2) MessageHandler: further processes the message, updates state etc
* 3) CommandHandler: translates commands from the openhab bus into an Insteon message.
* 4) PollHandler: creates an Insteon message to query the DeviceFeature
*
* Lastly, DeviceFeatureListeners can register with the DeviceFeature to get notifications when
* the state of a feature has changed. In practice, a DeviceFeatureListener corresponds to an
* OpenHAB item.
*
* The character of a DeviceFeature is thus given by a set of message and command handlers.
* A FeatureTemplate captures exactly that: it says what set of handlers make up a DeviceFeature.
*
* DeviceFeatures are added to a new device by referencing a FeatureTemplate (defined in device_features.xml)
* from the Device definition file (device_types.xml).
*
* @author Daniel Pfrommer
* @author Bernd Pfrommer
* @since 1.5.0
*/

public class DeviceFeature {
  public static enum QueryStatus {
    NEVER_QUERIED,
    QUERY_PENDING,
    QUERY_ANSWERED
  }

  private static final Logger logger = LoggerFactory.getLogger(DeviceFeature.class);
 
  private static HashMap<String, FeatureTemplate> s_features = new HashMap<String, FeatureTemplate>();
 
  private InsteonDevice        m_device = null;
  private String            m_name   = "INVALID_FEATURE_NAME";
  private boolean            m_isStatus = false;
  private QueryStatus                  m_queryStatus = QueryStatus.NEVER_QUERIED;
 
  private MessageHandler        m_defaultMsgHandler = new MessageHandler.DefaultMsgHandler(this);
  private CommandHandler        m_defaultCommandHandler = new CommandHandler.WarnCommandHandler(this);
  private PollHandler          m_pollHandler = null;
  private   MessageDispatcher      m_dispatcher = null;

  private HashMap<Integer, MessageHandler> m_msgHandlers =
        new HashMap<Integer, MessageHandler>();
  private HashMap<Class<? extends Command>, CommandHandler> m_commandHandlers =
        new HashMap<Class<? extends Command>, CommandHandler>();
  private ArrayList<DeviceFeatureListener> m_listeners = new ArrayList<DeviceFeatureListener>();
 
  static {
    // read features from xml file and store them in a map
    try {
      InputStream input = DeviceFeature.class.getResourceAsStream("/device_features.xml");
      ArrayList<FeatureTemplate> features = FeatureTemplateLoader.s_readTemplates(input);
      for (FeatureTemplate f : features) {
        s_features.put(f.getName(), f);
      }
    } catch (IOException e) {
      logger.error("IOException while reading device features", e);
    } catch (ParsingException e) {
      logger.error("Parsing exception while reading device features", e);
    }
  }
 
  /**
   * Constructor
   * @param device Insteon device to which this feature belongs
   * @param name descriptive name for that feature
   */
  public DeviceFeature(InsteonDevice device, String name) {
    m_name = name;
    setDevice(device);
  }

  /**
   * Constructor
   * @param name descriptive name of the feature
   */
  public DeviceFeature(String name) {
    m_name = name;
  }

  // various simple getters
  public String     getName()      { return m_name; }
  public synchronized QueryStatus  getQueryStatus()  { return m_queryStatus; }
  public InsteonDevice getDevice()     { return m_device; }
  public boolean     hasListeners()     { return !m_listeners.isEmpty(); }
  public boolean    isStatusFeature()  { return m_isStatus; }
  public MessageHandler getDefaultMsgHandler() { return m_defaultMsgHandler; }
  public HashMap<Integer, MessageHandler> getMsgHandlers() {
    return this.m_msgHandlers;
  }
  // various simple setters
  public void setStatusFeature(boolean f)  { m_isStatus = f; }
  public void setPollHandler(PollHandler h)  { m_pollHandler = h; }
  public void setDevice(InsteonDevice d)    { m_device = d; }
  public void setMessageDispatcher(MessageDispatcher md) { m_dispatcher = md; }
  public void setDefaultCommandHandler(CommandHandler ch) { m_defaultCommandHandler = ch; }
  public void setDefaultMsgHandler(MessageHandler mh) { m_defaultMsgHandler = mh; }
  public synchronized void setQueryStatus(QueryStatus status)  {
    logger.trace("{} set query status to: {}", m_name, status);
    m_queryStatus = status;
  }
  /**
   * Add a listener (item) to a device feature
   * @param l the listener
   */
  public void addListener(DeviceFeatureListener l) {
    synchronized(m_listeners) {
      for (DeviceFeatureListener m : m_listeners) {
        if (m.getItemName().equals(l.getItemName())) {
          return;
        }
      }
      m_listeners.add(l);
    }
  }
  /**
   * removes a DeviceFeatureListener from this feature
   * @param aItemName name of the item to remove as listener
   * @return true if a listener was removed
   */
 
  public boolean removeListener(String aItemName) {
    boolean listenerRemoved = false;
    synchronized(m_listeners) {
      for (Iterator<DeviceFeatureListener> it = m_listeners.iterator(); it.hasNext(); ) {
        DeviceFeatureListener fl = it.next();
        if (fl.getItemName().equals(aItemName)) {
          it.remove();
          listenerRemoved = true;
        }
      }
    }
    return listenerRemoved;
  }
  /**
   * Called when message is incoming. Dispatches message according to message dispatcher
   * @param msg The message to dispatch
   * @param port the port from which the message came
   * @return true if dispatch successful
   */
  public boolean handleMessage(Msg msg, String port) {
    if (m_dispatcher == null) {
      logger.error("{} no dispatcher for msg {}", m_name, msg);
      return false;
    }
    return (m_dispatcher.dispatch(msg, port));
  }
  /**
   * Called when an openhab command arrives for this device feature
   * @param c the binding config of the item which sends the command
   * @param cmd the command to be exectued
   */
  public void handleCommand(InsteonPLMBindingConfig c, Command cmd) {
    Class<? extends Command> key = cmd.getClass();
    CommandHandler h = m_commandHandlers.containsKey(key) ? m_commandHandlers.get(key) : m_defaultCommandHandler;
    logger.trace("{} uses {} to handle command {} for {}", getName(), h.getClass().getSimpleName(),
        key.getSimpleName(), getDevice().getAddress());
    h.handleCommand(c, cmd, getDevice());
  }
  /**
   * Make a poll message using the configured poll message handler
   * @return the poll message
   */
  public Msg makePollMsg() {
    if (m_pollHandler == null) return null;
    logger.trace("{} making poll msg for {} using handler {}", getName(), getDevice().getAddress(),
        m_pollHandler.getClass().getSimpleName());
    Msg m = m_pollHandler.makeMsg(m_device);
    return m;
  }
 
  /**
   * Publish new state to all device feature listeners
   * @param newState state to be published
   */
  public void publishAll(State newState) {
    logger.debug("{}:{} publishing: {}", this.getDevice().getAddress(),
          getName(), newState);
    synchronized(m_listeners) {
      for (DeviceFeatureListener listener : m_listeners) {
        listener.stateChanged(newState);
      }
    }
  }
  /**
   * Publish new state to all device feature listeners that match
   * a given filter for the parameters
   * @param newState the state to be published
   * @param key the parameter key
   * @param val the (integer!) value that the parameter must match
   */
  public void publishFiltered(State newState, String key, int val) {
    logger.debug("{} publishing filtered: {} param {} == {}",
        getName(), newState, key, val);
    synchronized(m_listeners) {
      for (DeviceFeatureListener listener : m_listeners) {
        if (listener.hasParameter(key) && listener.getIntParameter(key) == val) {
          logger.debug("{} publishing to: {}", getName(), listener.getItemName());
          listener.stateChanged(newState);
        }
      }
    }
  }
  /**
   * Adds a message handler to this device feature.
   * @param cm1 The insteon cmd1 of the incoming message for which the handler should be used
   * @param handler the handler to invoke
   */
  public void addMessageHandler(int cm1, MessageHandler handler) {
    synchronized(m_msgHandlers) {
      m_msgHandlers.put(cm1, handler);
    }
  }
  /**
   * Adds a command handler to this device feature
   * @param c the command for which this handler is invoked
   * @param handler the handler to call
   */
  public void addCommandHandler(Class<? extends Command> c, CommandHandler handler) {
    synchronized(m_commandHandlers) {
      m_commandHandlers.put(c, handler);
    }
  }
  /**
   * Turn DeviceFeature into String
   */
  @Override
  public String toString() {
    return m_name + "(" + m_listeners.size()  +":" +m_commandHandlers.size() + ":" + m_msgHandlers.size() + ")";
  }
 
  /**
   * Factory method for creating DeviceFeatures.
   * @param s The name of the device feature to create.
   * @return The newly created DeviceFeature, or null if requested DeviceFeature does not exist.
   */
  public static DeviceFeature s_makeDeviceFeature(String s) {
    DeviceFeature f = null;
    if (s_features.containsKey(s)) {
      f = s_features.get(s).build();
    } else {
      logger.error("unimplemented feature requested: {}", s);
    }
    return f;
  }

}
TOP

Related Classes of org.openhab.binding.insteonplm.internal.device.DeviceFeature

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.