Package org.openhab.model.rule.internal.engine

Source Code of org.openhab.model.rule.internal.engine.RuleEngine

/**
* Copyright (c) 2010-2014, 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.model.rule.internal.engine;

import static org.openhab.core.events.EventConstants.TOPIC_PREFIX;
import static org.openhab.core.events.EventConstants.TOPIC_SEPERATOR;
import static org.openhab.model.rule.internal.engine.RuleTriggerManager.TriggerTypes.CHANGE;
import static org.openhab.model.rule.internal.engine.RuleTriggerManager.TriggerTypes.COMMAND;
import static org.openhab.model.rule.internal.engine.RuleTriggerManager.TriggerTypes.SHUTDOWN;
import static org.openhab.model.rule.internal.engine.RuleTriggerManager.TriggerTypes.STARTUP;
import static org.openhab.model.rule.internal.engine.RuleTriggerManager.TriggerTypes.UPDATE;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.naming.QualifiedName;
import org.openhab.core.items.GenericItem;
import org.openhab.core.items.Item;
import org.openhab.core.items.ItemNotFoundException;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.ItemRegistryChangeListener;
import org.openhab.core.items.StateChangeListener;
import org.openhab.core.scriptengine.Script;
import org.openhab.core.scriptengine.ScriptEngine;
import org.openhab.core.scriptengine.ScriptExecutionException;
import org.openhab.core.scriptengine.ScriptExecutionThread;
import org.openhab.core.types.Command;
import org.openhab.core.types.EventType;
import org.openhab.core.types.State;
import org.openhab.model.core.ModelRepository;
import org.openhab.model.core.ModelRepositoryChangeListener;
import org.openhab.model.rule.rules.Rule;
import org.openhab.model.rule.rules.RuleModel;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;


/**
* This class is the core of the openHAB rule engine.
* It listens to changes to the rules folder, evaluates the trigger conditions of the rules and
* schedules them for execution dependent on their triggering conditions.
*
* @author Kai Kreuzer
* @since 0.9.0
*
*/
@SuppressWarnings("restriction")
public class RuleEngine implements EventHandler, ItemRegistryChangeListener, StateChangeListener, ModelRepositoryChangeListener {

    static private final Logger logger = LoggerFactory.getLogger(RuleEngine.class);
   
    private ItemRegistry itemRegistry;
    private ModelRepository modelRepository;
    private ScriptEngine scriptEngine;

    private RuleTriggerManager triggerManager;
           
    public void activate() {
      triggerManager = new RuleTriggerManager();

      if(!isEnabled()) {
        logger.info("Rule engine is disabled.");
        return;
      }
     
      logger.debug("Started rule engine");   
     
      // read all rule files
      Iterable<String> ruleModelNames = modelRepository.getAllModelNamesOfType("rules");
      ArrayList<String> clonedList = Lists.newArrayList(ruleModelNames);
      for(String ruleModelName : clonedList) {
        EObject model = modelRepository.getModel(ruleModelName);
        if(model instanceof RuleModel) {
          RuleModel ruleModel = (RuleModel) model;
          triggerManager.addRuleModel(ruleModel);
        }
      }
     
      // register us on all items which are already available in the registry
      for(Item item : itemRegistry.getItems()) {
        internalItemAdded(item);
      }
      runStartupRules();
    }
   
    public void deactivate() {
      // execute all scripts that were registered for system shutdown
      executeRules(triggerManager.getRules(SHUTDOWN));
      triggerManager.clearAll();
      triggerManager = null;
    }
   
    public void setItemRegistry(ItemRegistry itemRegistry) {
      this.itemRegistry = itemRegistry;
      itemRegistry.addItemRegistryChangeListener(this);
    }
   
    public void unsetItemRegistry(ItemRegistry itemRegistry) {
      itemRegistry.removeItemRegistryChangeListener(this);
      this.itemRegistry = null;
    }
   
    public void setModelRepository(ModelRepository modelRepository) {
      this.modelRepository = modelRepository;
      modelRepository.addModelRepositoryChangeListener(this);
    }

    public void unsetModelRepository(ModelRepository modelRepository) {
      modelRepository.removeModelRepositoryChangeListener(this);
      this.modelRepository = null;
    }
   
    public void setScriptEngine(ScriptEngine scriptEngine) {
      this.scriptEngine = scriptEngine;
    }

    public void unsetScriptEngine(ScriptEngine scriptEngine) {
      this.scriptEngine = null;
    }

    /**
     * {@inheritDoc}
     */
    public void allItemsChanged(Collection<String> oldItemNames) {
      // add the current items again
      Collection<Item> items = itemRegistry.getItems();
      for(Item item : items) {
        internalItemAdded(item);
      }
      runStartupRules();
    }

    /**
     * {@inheritDoc}
     */
    public void itemAdded(Item item) {
      internalItemAdded(item);
      runStartupRules();
    }

    /**
     * {@inheritDoc}
     */
    public void itemRemoved(Item item) {
      if (item instanceof GenericItem) {
        GenericItem genericItem = (GenericItem) item;
        genericItem.removeStateChangeListener(this);
      }
    }

    /**
     * {@inheritDoc}
     */
    public void stateChanged(Item item, State oldState, State newState) {     
      if(triggerManager!=null) {
        Iterable<Rule> rules = triggerManager.getRules(CHANGE, item, oldState, newState);
        RuleEvaluationContext context = new RuleEvaluationContext();
        context.newValue(QualifiedName.create(RuleContextHelper.VAR_PREVIOUS_STATE), oldState);
        executeRules(rules, context);
      }
    }

    /**
     * {@inheritDoc}
     */
    public void stateUpdated(Item item, State state) {
      if(triggerManager!=null) {
        Iterable<Rule> rules = triggerManager.getRules(UPDATE, item, state);
        executeRules(rules);
      }
    }

    public void receiveCommand(String itemName, Command command) {
      if(triggerManager!=null && itemRegistry!=null) {
        try {
          Item item = itemRegistry.getItem(itemName);
          Iterable<Rule> rules = triggerManager.getRules(COMMAND, item, command);
          RuleEvaluationContext context = new RuleEvaluationContext();
          context.newValue(QualifiedName.create(RuleContextHelper.VAR_RECEIVED_COMMAND), command);
          executeRules(rules, context);
        } catch (ItemNotFoundException e) {
          // ignore commands for non-existent items
        }
      }
    }
   
    private void internalItemAdded(Item item) {
      if (item instanceof GenericItem) {
        GenericItem genericItem = (GenericItem) item;
        genericItem.addStateChangeListener(this);
      }
    }

    /**
     * {@inheritDoc}
     */
    public void handleEvent(Event event) { 
      String itemName = (String) event.getProperty("item");
     
      String topic = event.getTopic();
      String[] topicParts = topic.split(TOPIC_SEPERATOR);
     
      if(!(topicParts.length > 2) || !topicParts[0].equals(TOPIC_PREFIX)) {
        return; // we have received an event with an invalid topic
      }
      String operation = topicParts[1];
     
      if(operation.equals(EventType.COMMAND.toString())) {
        Command command = (Command) event.getProperty("command");
        if(command!=null) receiveCommand(itemName, command);
      }
    }

    public void modelChanged(String modelName, org.openhab.model.core.EventType type) {
      if (triggerManager != null) {
        if(isEnabled() && modelName.endsWith("rules")) {
          RuleModel model = (RuleModel) modelRepository.getModel(modelName);
 
          // remove the rules from the trigger sets
          if(type == org.openhab.model.core.EventType.REMOVED ||
              type == org.openhab.model.core.EventType.MODIFIED) {
            triggerManager.removeRuleModel(model);
          }
 
          // add new and modified rules to the trigger sets
          if(model!=null &&
              (type == org.openhab.model.core.EventType.ADDED
              || type == org.openhab.model.core.EventType.MODIFIED)) {
            triggerManager.addRuleModel(model);
            // now execute all rules that are meant to trigger at startup
            runStartupRules();
          }
        }
      }
    }

    private void runStartupRules() {
      if (triggerManager!=null) {
        Iterable<Rule> startupRules = triggerManager.getRules(STARTUP);
        List<Rule> executedRules = Lists.newArrayList();
       
        for(Rule rule : startupRules) {
          try {
            Script script = scriptEngine.newScriptFromXExpression(rule.getScript());           
            logger.debug("Executing startup rule '{}'", rule.getName());
            RuleEvaluationContext context = new RuleEvaluationContext();
            context.setGlobalContext(RuleContextHelper.getContext(rule));
            script.execute(context);
            executedRules.add(rule);
          } catch (ScriptExecutionException e) {
            if(e.getCause() instanceof ItemNotFoundException || e.getCause().getMessage().contains("cannot be resolved to an item or type")) {
              // we do not seem to have all required items in place yet
              // so we keep the rule in the list and try it again later
            } else {
              logger.error("Error during the execution of startup rule '{}': {}", new String[] { rule.getName(), e.getCause().getMessage() });
              executedRules.add(rule);
            }
          }
        }
        for(Rule rule : executedRules) {
          triggerManager.removeRule(STARTUP, rule);
        }
      }
    }

    protected synchronized void executeRule(Rule rule) {
      executeRule(rule, new RuleEvaluationContext());
    }
     
    protected synchronized void executeRule(Rule rule, RuleEvaluationContext context) {
      Script script = scriptEngine.newScriptFromXExpression(rule.getScript());
     
      logger.debug("Executing rule '{}'", rule.getName());
     
      context.setGlobalContext(RuleContextHelper.getContext(rule));
     
      ScriptExecutionThread thread = new ScriptExecutionThread(rule.getName(), script, context);
      thread.start();
    }

    protected synchronized void executeRules(Iterable<Rule> rules) {
      executeRules(rules, new RuleEvaluationContext());
    }
   
    protected synchronized void executeRules(Iterable<Rule> rules, RuleEvaluationContext context) {
      for(Rule rule : rules) {
        executeRule(rule, context);
      }
    }
       
    /**
     * we need to be able to deactivate the rule execution, otherwise the openHAB designer
     * would also execute the rules.
     *
     * @return true, if rules should be executed, false otherwise
     */
    private boolean isEnabled() {
      return !"true".equalsIgnoreCase(System.getProperty("noRules"));
    }
   
}
TOP

Related Classes of org.openhab.model.rule.internal.engine.RuleEngine

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.