Package it.freedomotic.core

Source Code of it.freedomotic.core.BehaviorManager

/**
*
* Copyright (c) 2009-2013 Freedomotic team http://freedomotic.com
*
* This file is part of Freedomotic
*
* This Program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2, or (at your option) any later version.
*
* This Program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* Freedomotic; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
package it.freedomotic.core;

import it.freedomotic.app.Freedomotic;
import it.freedomotic.bus.BusConsumer;
import it.freedomotic.bus.BusService;
import it.freedomotic.bus.BusMessagesListener;
import it.freedomotic.model.object.EnvObject;
import it.freedomotic.objects.BehaviorLogic;
import it.freedomotic.objects.EnvObjectLogic;
import it.freedomotic.objects.EnvObjectPersistence;
import it.freedomotic.reactions.Command;

import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;

import com.google.inject.Inject;
import java.util.HashSet;
import java.util.Set;

/**
* Translates a generic request like 'turn on light 1' into a series of hardware
* commands like 'send to serial COM1 the string A01AON' using the mapping
* between abstract action -to-> concrete action defined in every environment
* object, for lights it can be something like 'turn on' -> 'turn on X10 light'
*
* <p> This class is listening on channels:
* app.events.sensors.behavior.request.objects If a command (eg: 'turn on
* light1' or 'turn on all lights') is received on this channel the requested
* behavior is applied to the single object or all objects of the same type as
* described by the command parameters. </p>
*
* @author Enrico
*/
public final class BehaviorManager
        implements BusConsumer {

    private static final Logger LOG = Logger.getLogger(BehaviorManager.class.getName());
    private static final String MESSAGING_CHANNEL = "app.events.sensors.behavior.request.objects";
    public static final String PROPERTY_BEHAVIOR = "behavior";
    public static final String PROPERTY_OBJECT_CLASS = "object.class";
    public static final String PROPERTY_OBJECT_ADDRESS = "object.address";
    public static final String PROPERTY_OBJECT_NAME = "object.name";
    public static final String PROPERTY_OBJECT_PROTOCOL = "object.protocol";
    public static final String PROPERTY_OBJECT = "object";
    private static BusMessagesListener listener;
    private BusService busService;

    static String getMessagingChannel() {
        return MESSAGING_CHANNEL;
    }

    public BehaviorManager() {
        this.busService = Freedomotic.INJECTOR.getInstance(BusService.class);
        register();
    }

    /**
     * Register one or more channels to listen to
     */
    private void register() {
        listener = new BusMessagesListener(this);
        listener.consumeCommandFrom(getMessagingChannel());
    }

    @Override
    public final void onMessage(final ObjectMessage message) {

        // TODO LCG Boiler plate code, move this idiom to an abstract superclass.
        Object jmsObject = null;
        try {
            jmsObject = message.getObject();
        } catch (JMSException ex) {
            LOG.log(Level.SEVERE, null, ex);
        }

        if (jmsObject instanceof Command) {

            Command command = (Command) jmsObject;

            parseCommand(command);

            // reply to the command to notify that is received it can be
            // something like "turn on light 1"
            sendReply(message, command);
        }
    }

    private static void applyToCategory(Command userLevelCommand) {

        // gets a reference to an EnvObject using the key 'object' in the user
        // level command

        String objectClass = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_CLASS);
        if (objectClass != null) {
            String regex = "^" + objectClass.replace(".", "\\.") + ".*";
            Pattern pattern = Pattern.compile(regex);

            // TODO this should be in the collection
            final Collection<EnvObjectLogic> objectList = EnvObjectPersistence
                    .getObjectList();

            for (EnvObjectLogic object : objectList) {

                final EnvObject pojo = object.getPojo();
                final Matcher matcher = pattern.matcher(pojo.getType());

                if (matcher.matches()) {
                    // TODO Look at this setProperty later
                    userLevelCommand.setProperty(Command.PROPERTY_OBJECT, pojo.getName());
                    applyToSingleObject(userLevelCommand);
                }
            }
        }

        String includeTags = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_INCLUDETAGS);
        String excludeTags = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_EXCLUDETAGS);
        if (includeTags != null || excludeTags != null) {
            // prepare includ set
            includeTags += "";
            String tags[] = includeTags.split(",");
            Set<String> includeSearch = new HashSet<String>();
            for (String tag : tags) {
                if (!tag.isEmpty()) {
                    includeSearch.add(tag.trim());
                }
            }
            //prepare exclude set (remove tags listed in include set too)
            excludeTags += "";
            tags = excludeTags.split(",");
            Set<String> excludeSearch = new HashSet<String>();
            for (String tag : tags) {
                if (!tag.isEmpty() && !includeSearch.contains(tag)) {
                    excludeSearch.add(tag.trim());
                }
            }

            Set<String> testSet = new HashSet<String>();
            Set<String> extestSet = new HashSet<String>();

            for (EnvObjectLogic object : EnvObjectPersistence.getObjectList()) {
                final EnvObject pojo = object.getPojo();
                boolean apply;
                testSet.clear();
                extestSet.clear();

                // applies to objects that do not contain any exclused tag
                testSet.addAll(excludeSearch);
                testSet.retainAll(pojo.getTagsList());
                // if object contains forbidden tags, testSet is not empty
                apply = testSet.isEmpty();
                // if above is false, skip check for admitted tags.
                if (apply && !includeSearch.isEmpty()) {
                    // AND operation between searchSet and object's tag list
                    testSet.addAll(includeSearch);
                    testSet.retainAll(pojo.getTagsList());
                    // if object contains ANY of admitted tags, tastSet is populated
                    apply = !testSet.isEmpty();
                }

                if (apply) {

                    // TODO Look at this setProperty later
                    userLevelCommand.setProperty(Command.PROPERTY_OBJECT, pojo.getName());
                    applyToSingleObject(userLevelCommand);
                }
            }
        }
    }

    private static void applyToSingleObject(Command userLevelCommand) {

        // gets a reference to an EnvObject using the key 'object' in the user
        // level command
        EnvObjectLogic obj = EnvObjectPersistence
                .getObjectByName(userLevelCommand.getProperty(Command.PROPERTY_OBJECT));

        // if the object exists
        if (obj != null) {

            // gets the behavior name in the user level command
            String behaviorName = userLevelCommand.getProperty(Command.PROPERTY_BEHAVIOR);
            BehaviorLogic behavior = obj.getBehavior(behaviorName);

            // if this behavior exists in object obj
            if (behavior != null) {

                LOG.log(Level.CONFIG,
                        "User level command ''{0}'' request changing behavior {1} of object ''{2}'' "
                        + "from value ''{3}'' to value ''{4}''",
                        new Object[]{userLevelCommand.getName(), behavior.getName(), obj.getPojo().getName(), behavior.getValueAsString(), userLevelCommand.getProperties().getProperty("value")});

                // true means a command must be fired
                behavior.filterParams(userLevelCommand.getProperties(), true);

            } else {
                LOG.log(Level.WARNING,
                        "Behavior ''{0}'' is not a valid behavior for object ''{1}''. "
                        + "Please check ''behavior'' parameter spelling in command {2}",
                        new Object[]{behaviorName, obj.getPojo().getName(), userLevelCommand.getName()});
            }
        } else {
            LOG.log(Level.WARNING,"Object ''{0}"
                    + "'' don''t exist in this environment. "
                    + "Please check ''object'' parameter spelling in command {1}",
                    new Object[]{userLevelCommand.getProperty(Command.PROPERTY_OBJECT), userLevelCommand.getName()});
        }
    }

    protected static void parseCommand(Command userLevelCommand) {

        String object = userLevelCommand.getProperty(Command.PROPERTY_OBJECT);
        String objectClass = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_CLASS);
        String objectincludeTags = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_INCLUDETAGS);
        String objectexcludeTags = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_EXCLUDETAGS);
        String behavior = userLevelCommand.getProperty(Command.PROPERTY_BEHAVIOR);

        if (behavior != null) {

            if (object != null) {
                /*
                 * if we have the object name and the behavior it means the
                 * behavior must be applied only to the given object name.
                 */
                applyToSingleObject(userLevelCommand);
            } else {

                if (objectClass != null || objectincludeTags != null || objectexcludeTags != null) {
                    try {
                        /*
                         * if we have the category and the behavior (and not the
                         * object name) it means the behavior must be applied to all
                         * object belonging to the given category. eg: all lights on
                         */
                        Command clonedOne = userLevelCommand.clone();
                        applyToCategory(clonedOne);
                    } catch (CloneNotSupportedException ex) {
                        Logger.getLogger(BehaviorManager.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
    }

    /**
     * @param message
     * @param command
     */
    public void sendReply(final ObjectMessage message, Command command) {

        try {

            Destination jmsReplyTo = message.getJMSReplyTo();
            if (jmsReplyTo != null) {

                final String jmsCorrelationID = message.getJMSCorrelationID();
                busService.reply(command, jmsReplyTo, jmsCorrelationID);
            }

        } catch (JMSException ex) {
            LOG.severe(Freedomotic.getStackTraceInfo(ex));
        }
    }
}
TOP

Related Classes of it.freedomotic.core.BehaviorManager

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.