All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.freedomotic.core.BehaviorManager Maven / Gradle / Ivy

/**
 *
 * Copyright (c) 2009-2014 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
 * .
 */
package com.freedomotic.core;

import com.freedomotic.app.Freedomotic;
import com.freedomotic.bus.BusConsumer;
import com.freedomotic.bus.BusMessagesListener;
import com.freedomotic.bus.BusService;
import com.freedomotic.environment.EnvironmentLogic;
import com.freedomotic.environment.ZoneLogic;
import com.freedomotic.model.object.EnvObject;
import com.freedomotic.behaviors.BehaviorLogic;
import com.freedomotic.environment.EnvironmentRepository;
import com.freedomotic.things.EnvObjectLogic;
import com.freedomotic.things.ThingRepository;
import com.freedomotic.reactions.Command;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;

/**
 * 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'
 *
 * 

* 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.

* * @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"; private BusMessagesListener listener; // Dependencies private final BusService busService; private final ThingRepository thingsRepository; private final EnvironmentRepository environmentRepository; @Inject BehaviorManager(BusService busService, ThingRepository thingsRepository, EnvironmentRepository environmentRepository) { this.busService = busService; this.thingsRepository = thingsRepository; this.environmentRepository = environmentRepository; register(); } /** * Register one or more channels to listen to */ private void register() { listener = new BusMessagesListener(this, busService); 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 void applyToCategory(Command userLevelCommand) { // gets a reference to an EnvObject using the key 'object' in the user // level command List objNames = getObjectsNames(); // filter first tags, then class, then zone List affectedObjects = filterByZone(userLevelCommand, filterByObjClass(userLevelCommand, filterByTags(userLevelCommand, objNames))); //Execute the command on all affected objects for (String objName : affectedObjects) { userLevelCommand.setProperty(Command.PROPERTY_OBJECT, objName); applyToSingleObject(userLevelCommand); } } private List filterByTags(Command userLevelCommand, List origList) { String includeTags = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_INCLUDETAGS); String excludeTags = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_EXCLUDETAGS); if (includeTags != null || excludeTags != null) { List newList = new ArrayList(); // prepare includ set includeTags += ""; String tags[] = includeTags.split(","); Set includeSearch = new HashSet(); 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 excludeSearch = new HashSet(); for (String tag : tags) { if (!tag.isEmpty() && !includeSearch.contains(tag)) { excludeSearch.add(tag.trim()); } } Set testSet = new HashSet(); Set extestSet = new HashSet(); for (EnvObjectLogic object : thingsRepository.findAll()) { 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) { LOG.config("Filter by tag affects object " + pojo.getName()); newList.add(pojo.getName()); } } // Filter out the objects wich are not affected origList.retainAll(newList); } return origList; } private List filterByObjClass(Command userLevelCommand, List origList) { String objectClass = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_CLASS); if (objectClass != null) { List newList = new ArrayList(); String regex = "^" + objectClass.replace(".", "\\.") + ".*"; Pattern pattern = Pattern.compile(regex); for (EnvObjectLogic object : thingsRepository.findAll()) { final EnvObject pojo = object.getPojo(); final Matcher matcher = pattern.matcher(pojo.getType()); if (matcher.matches()) { LOG.config("Filter by class affects object " + pojo.getName()); newList.add(pojo.getName()); } } // Filter out the objects wich are not affected origList.retainAll(newList); } return origList; } private List filterByZone(Command userLevelCommand, List origList) { String zoneName = userLevelCommand.getProperty(Command.PROPERTY_OBJECT_ZONE); if (zoneName != null) { List newList = new ArrayList(); //Search for the 'object.zone' name in all environments for (EnvironmentLogic env : environmentRepository.findAll()) { if (zoneName != null) { ZoneLogic z = env.getZone(zoneName); for (EnvObject obj : z.getPojo().getObjects()) { LOG.config("Filter by zone affects object " + obj.getName()); newList.add(obj.getName()); } } } // Filter out the objects wich are not affected origList.retainAll(newList); } return origList; } private void applyToSingleObject(Command userLevelCommand) { // gets a reference to an EnvObject using the key 'object' in the user // level command List things = thingsRepository.findByName(userLevelCommand.getProperty(Command.PROPERTY_OBJECT)); // if the object exists if (!things.isEmpty()) { for (EnvObjectLogic thing : things) { // gets the behavior name in the user level command String behaviorName = userLevelCommand.getProperty(Command.PROPERTY_BEHAVIOR); BehaviorLogic behavior = thing.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(), thing.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, thing.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()}); } } /** * * @param userLevelCommand */ protected void parseCommand(Command userLevelCommand) { if (userLevelCommand.getProperty(Command.PROPERTY_BEHAVIOR) != null) { if (userLevelCommand.getProperty(Command.PROPERTY_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 (userLevelCommand.getProperty(Command.PROPERTY_OBJECT_CLASS) != null || userLevelCommand.getProperty(Command.PROPERTY_OBJECT_INCLUDETAGS) != null || userLevelCommand.getProperty(Command.PROPERTY_OBJECT_EXCLUDETAGS) != null || userLevelCommand.getProperty(Command.PROPERTY_OBJECT_ENVIRONMENT) != null || userLevelCommand.getProperty(Command.PROPERTY_OBJECT_ZONE) != 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) { LOG.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)); } } private List getObjectsNames() { List names = new ArrayList(); for (EnvObjectLogic thing : thingsRepository.findAll()) { names.add(thing.getPojo().getName()); } return names; } public static String getMessagingChannel() { return MESSAGING_CHANNEL; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy