org.openhab.binding.xbmc.internal.XbmcActiveBinding.java Source code

Java tutorial

Introduction

Here is the source code for org.openhab.binding.xbmc.internal.XbmcActiveBinding.java

Source

/**
 * Copyright (c) 2010-2019 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.xbmc.internal;

import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.openhab.binding.xbmc.XbmcBindingProvider;
import org.openhab.binding.xbmc.rpc.XbmcConnector;
import org.openhab.core.binding.AbstractActiveBinding;
import org.openhab.core.binding.BindingProvider;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This refresh service for the XBMC binding is used to periodically check to
 * ensure all XBMC web sockets are still open and alive.
 *
 * All item updates are received asynchronously via the web socket All item
 * commands are sent via the web socket
 *
 * @author tlan, Ben Jones, Plebs
 * @since 1.5.0
 */
public class XbmcActiveBinding extends AbstractActiveBinding<XbmcBindingProvider> implements ManagedService {

    private static final Logger logger = LoggerFactory.getLogger(XbmcActiveBinding.class);

    private Map<String, XbmcConnector> connectors = new HashMap<String, XbmcConnector>();
    private Map<String, XbmcHost> nameHostMapper = null;

    /**
     * the refresh interval which is used to check for lost connections
     * (optional, defaults to 60000ms)
     */
    private long refreshInterval = 60000L;

    @Override
    public void activate() {
        logger.debug(getName() + " activate()");
    }

    @Override
    public void deactivate() {
        logger.debug(getName() + " deactivate()");

        // close any open connections
        for (XbmcConnector connector : connectors.values()) {
            if (connector.isConnected()) {
                connector.close();
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected long getRefreshInterval() {
        return refreshInterval;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected String getName() {
        return "XBMC Refresh Service";
    }

    /**
     * @{inheritDoc
     */
    @Override
    public void bindingChanged(BindingProvider provider, String itemName) {
        if (provider instanceof XbmcBindingProvider) {
            XbmcBindingProvider xbmcProvider = (XbmcBindingProvider) provider;
            registerWatch(xbmcProvider, itemName);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void allBindingsChanged(BindingProvider provider) {
        if (provider instanceof XbmcBindingProvider) {
            XbmcBindingProvider xbmcProvider = (XbmcBindingProvider) provider;
            for (String itemName : xbmcProvider.getItemNames()) {
                registerWatch(xbmcProvider, itemName);
            }
        }
    }

    private void registerAllWatches() {
        for (BindingProvider provider : providers) {
            if (provider instanceof XbmcBindingProvider) {
                XbmcBindingProvider xbmcProvider = (XbmcBindingProvider) provider;
                for (String itemName : xbmcProvider.getItemNames()) {
                    registerWatch(xbmcProvider, itemName);
                }
            }
        }
    }

    private void registerWatch(XbmcBindingProvider xbmcProvider, String itemName) {
        // only interested in watching 'inbound' items
        if (!xbmcProvider.isInBound(itemName)) {
            return;
        }

        String xbmcInstance = xbmcProvider.getXbmcInstance(itemName);
        String property = xbmcProvider.getProperty(itemName);

        XbmcConnector connector = getXbmcConnector(xbmcInstance);
        if (connector != null) {
            // add the new 'watch'
            connector.addItem(itemName, property);

            // update the player status so any current value is initialised
            if (connector.isConnected()) {
                connector.updatePlayerStatus();
            }

            if (property.startsWith("Application")) {
                connector.requestApplicationUpdate();
            } else if (property.equals("System.State")) {
                connector.updateSystemStatus();
            }
        }
    }

    private String getXbmcInstance(String itemName) {
        for (BindingProvider provider : providers) {
            if (provider instanceof XbmcBindingProvider) {
                XbmcBindingProvider xbmcProvider = (XbmcBindingProvider) provider;
                if (xbmcProvider.getItemNames().contains(itemName)) {
                    return xbmcProvider.getXbmcInstance(itemName);
                }
            }
        }
        return null;
    }

    private String getProperty(String itemName) {
        for (BindingProvider provider : providers) {
            if (provider instanceof XbmcBindingProvider) {
                XbmcBindingProvider xbmcProvider = (XbmcBindingProvider) provider;
                if (xbmcProvider.getItemNames().contains(itemName)) {
                    return xbmcProvider.getProperty(itemName);
                }
            }
        }
        return null;
    }

    private boolean isInBound(String itemName) {
        for (BindingProvider provider : providers) {
            if (provider instanceof XbmcBindingProvider) {
                XbmcBindingProvider xbmcProvider = (XbmcBindingProvider) provider;
                if (xbmcProvider.getItemNames().contains(itemName)) {
                    return xbmcProvider.isInBound(itemName);
                }
            }
        }
        return false;
    }

    private boolean isOutBound(String itemName) {
        for (BindingProvider provider : providers) {
            if (provider instanceof XbmcBindingProvider) {
                XbmcBindingProvider xbmcProvider = (XbmcBindingProvider) provider;
                if (xbmcProvider.getItemNames().contains(itemName)) {
                    return xbmcProvider.isOutBound(itemName);
                }
            }
        }
        return false;
    }

    private XbmcConnector getXbmcConnector(String xbmcInstance) {
        // sanity check
        if (xbmcInstance == null) {
            return null;
        }

        // check if the connector for this instance already exists
        XbmcConnector connector = connectors.get(xbmcInstance);
        if (connector != null) {
            return connector;
        }

        XbmcHost xbmcHost;
        if (xbmcInstance.startsWith("#")) {
            // trim off the '#' identifier
            String instance = xbmcInstance.substring(1);

            // check if we have been initialised yet - can't process
            // named instances until we have read the binding config
            if (nameHostMapper == null) {
                logger.trace(
                        "Attempting to access the named instance '{}' before the binding config has been loaded",
                        instance);
                return null;
            }

            // check this instance name exists in our config
            if (!nameHostMapper.containsKey(instance)) {
                logger.error("Named instance '{}' does not exist in the binding config", instance);
                return null;
            }

            xbmcHost = nameHostMapper.get(instance);
        } else {
            xbmcHost = new XbmcHost();
            xbmcHost.setHostname(xbmcInstance);
        }

        // create a new connection handler
        logger.debug("Creating new XbmcConnector for '{}' on {}", xbmcInstance, xbmcHost.getHostname());
        connector = new XbmcConnector(xbmcHost, eventPublisher);
        connectors.put(xbmcInstance, connector);

        // attempt to open the connection straight away
        try {
            connector.open();
        } catch (Exception e) {
            logger.error("Connection failed for '{}' on {}", xbmcInstance, xbmcHost.getHostname());
        }

        return connector;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void execute() {
        for (Map.Entry<String, XbmcConnector> entry : connectors.entrySet()) {
            XbmcConnector connector = entry.getValue();
            if (connector.isConnected()) {
                // we are still connected but send a ping to make sure
                connector.ping();
                // refresh all players
                connector.updatePlayerStatus(true);
                // refresh screensaverupdate
                connector.requestScreenSaverStateUpdate();
            } else {
                // broken connection so attempt to reconnect
                logger.debug("Broken connection found for '{}', attempting to reconnect...", entry.getKey());
                try {
                    connector.open();
                } catch (Exception e) {
                    logger.debug("Reconnect failed for '{}', will retry in {}s", entry.getKey(),
                            refreshInterval / 1000);
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void internalReceiveCommand(String itemName, Command command) {
        // only interested in 'outbound' items
        if (!isOutBound(itemName)) {
            logger.warn("Received command ({}) for item {} which is configured as 'in-bound', ignoring",
                    command.toString(), itemName);
            return;
        }

        try {
            // lookup the XBMC instance name and property for this item
            String xbmcInstance = getXbmcInstance(itemName);
            String property = getProperty(itemName);

            XbmcConnector connector = getXbmcConnector(xbmcInstance);
            if (connector == null) {
                logger.warn("Received command ({}) for item {} but no XBMC connector found for {}, ignoring",
                        command.toString(), itemName, xbmcInstance);
                return;
            }
            if (!connector.isConnected()) {
                logger.warn(
                        "Received command ({}) for item {} but the connection to the XBMC instance {} is down, ignoring",
                        command.toString(), itemName, xbmcInstance);
                return;
            }

            // TODO: handle other commands
            if (property.equals("Player.PlayPause")) {
                connector.playerPlayPause();
            } else if (property.equals("Player.Open")) {
                connector.playerOpen(command.toString());
            } else if (property.equals("Player.Stop")) {
                connector.playerStop();
            } else if (property.equals("Input.ExecuteAction")) {
                connector.inputExecuteAction(command.toString());
            } else if (property.startsWith("Input.ExecuteAction.")) {
                connector.inputExecuteAction(property.substring(20).toLowerCase());
            } else if (property.equals("GUI.ShowNotification")) {
                connector.showNotification("openHAB", command.toString());
            } else if (property.equals("System.Shutdown") && command == OnOffType.OFF) {
                connector.systemShutdown();
            } else if (property.equals("System.Suspend") && command == OnOffType.OFF) {
                connector.systemSuspend();
            } else if (property.equals("System.Hibernate") && command == OnOffType.OFF) {
                connector.systemHibernate();
            } else if (property.equals("System.Reboot") && command == OnOffType.OFF) {
                connector.systemReboot();
            } else if (property.equals("Application.Volume")) {
                connector.applicationSetVolume(command.toString());
            } else if (property.equals("PVR.OpenTV")) {
                connector.playerOpenPVR(command.toString(), 2);
            } else if (property.equals("PVR.OpenRadio")) {
                connector.playerOpenPVR(command.toString(), 1);
            } else if (property.equals("Refresh")) {
                execute();
            }

        } catch (Exception e) {
            logger.error("Error handling command", e);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void internalReceiveUpdate(String itemName, State newState) {
        try {
            String property = getProperty(itemName);

            String xbmcInstance = getXbmcInstance(itemName);
            XbmcConnector connector = getXbmcConnector(xbmcInstance);

            if (connector == null) {
                logger.warn("Received update ({}) for item {} but no XBMC connector found for {}, ignoring",
                        newState.toString(), itemName, xbmcInstance);
                return;
            }
            if (!connector.isConnected()) {
                logger.warn(
                        "Received update ({}) for item {} but the connection to the XBMC instance {} is down, ignoring",
                        newState.toString(), itemName, xbmcInstance);
                return;
            }

            // TODO: handle other updates
            if (property.equals("GUI.ShowNotification")) {
                connector.showNotification("openHAB", newState.toString());
            } else if (property.equals("Player.Open")) {
                connector.playerOpen(newState.toString());
            } else if (property.equals("Application.SetVolume")) {
                connector.applicationSetVolume(newState.toString());
            }

        } catch (Exception e) {
            logger.error("Error handling update", e);
        }
    }

    protected void addBindingProvider(XbmcBindingProvider bindingProvider) {
        super.addBindingProvider(bindingProvider);
    }

    protected void removeBindingProvider(XbmcBindingProvider bindingProvider) {
        super.removeBindingProvider(bindingProvider);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void updated(Dictionary<String, ?> config) throws ConfigurationException {
        logger.debug(getName() + " updated()");

        Map<String, XbmcHost> hosts = new HashMap<String, XbmcHost>();

        if (config != null) {

            String refreshIntervalString = (String) config.get("refreshInterval");
            if (StringUtils.isNotBlank(refreshIntervalString)) {
                refreshInterval = Long.parseLong(refreshIntervalString);
            }

            Enumeration<String> keys = config.keys();

            while (keys.hasMoreElements()) {
                // Ignore "refreshInterval" key
                String key = keys.nextElement();
                if ("refreshInterval".equals(key)) {
                    continue;
                }

                if ("service.pid".equals(key)) {
                    continue;
                }

                String[] parts = key.split("\\.");
                String hostname = parts[0];

                XbmcHost host = hosts.get(hostname);
                if (host == null) {
                    host = new XbmcHost();
                }

                String value = ((String) config.get(key)).trim();

                if ("host".equals(parts[1])) {
                    host.setHostname(value);
                }
                if ("rsPort".equals(parts[1])) {
                    host.setRsPort(Integer.valueOf(value));
                }
                if ("wsPort".equals(parts[1])) {
                    host.setWsPort(Integer.valueOf(value));
                }
                if ("username".equals(parts[1])) {
                    host.setUsername(value);
                }
                if ("password".equals(parts[1])) {
                    host.setPassword(value);
                }
                hosts.put(hostname, host);
            }

            setProperlyConfigured(true);
            nameHostMapper = hosts;
            registerAllWatches();
        }
    }
}