001 package dk.deepthought.sidious.ruleengine;
002 
003 import java.util.ArrayList;
004 import java.util.Collection;
005 import java.util.List;
006 
007 import org.apache.commons.logging.Log;
008 import org.apache.commons.logging.LogFactory;
009 
010 import dk.deepthought.sidious.explanation.Explanation;
011 import dk.deepthought.sidious.explanation.ExplanationEntry;
012 import dk.deepthought.sidious.goalhandler.Goal;
013 import dk.deepthought.sidious.rules.Rule;
014 import dk.deepthought.sidious.supportsystem.PlanRequester;
015 import dk.deepthought.sidious.supportsystem.Repository;
016 import dk.deepthought.sidious.supportsystem.State;
017 import dk.deepthought.sidious.supportsystem.Step;
018 import dk.deepthought.sidious.supportsystem.SuperLinkID;
019 
020 public class RuleEngineImpl implements RuleEngine {
021     
022     /**
023      * Logger for this class
024      */
025     private static final Log logger = LogFactory.getLog(RuleEngineImpl.class);
026 
027     /*
028      * (non-Javadoc)
029      
030      * @see dk.deepthought.sidious.ruleengine.RuleEngine#evaluate(dk.deepthought.sidious.supportsystem.SuperLinkID,
031      *      dk.deepthought.sidious.supportsystem.State, dk.deepthought.sidious.supportsystem.State)
032      */
033     public double evaluate(SuperLinkID requesterID, State current, State next,
034             Step step) {
035         if (requesterID == null || current == null || next == null
036                 || step == null) {
037             logger.error("evaluate(SuperLinkID requesterID=" + requesterID
038                     ", State current=" + current + ", State next=" + next
039                     ") - null not valid input");
040             throw new IllegalArgumentException("null not valid input");
041         }
042         PlanRequester requester = Repository.getBlackboard().getRequester(
043                 requesterID);
044         double evaluation = evaluateRules(requester.getRules(), current, next,
045                 step);
046         return evaluation;
047     }
048 
049     /**
050      * This method evaluates each of the input <code>rules</code> according to
051      * the input states (<code>current</code> and <code>next</code>), and
052      * returns a combined value.
053      
054      @param rules
055      *            the input collection of rules
056      @param current
057      *            the current state
058      @param next
059      *            the next state
060      @param step
061      *            the step
062      @return a combined evaluation, 0 if rules is empty
063      */
064     double evaluateRules(Collection<Rule> rules, State current, State next,
065             Step step) {
066         if (rules == null || current == null || next == null || step == null) {
067             logger.error("evaluateRules(Collection<Rule> rules=" + rules
068                     ", State current=" + current + ", State next=" + next
069                     ") - null not valid input");
070             throw new IllegalArgumentException("null not valid input");
071         }
072         double evaluation = 0;
073         List<ExplanationEntry> explanations;
074         ExplanationEntry entry;
075         explanations = new ArrayList<ExplanationEntry>();
076         for (Rule rule : rules) {
077             double desire = rule.desire(current, next, step);
078             evaluation += desire;
079             entry = new ExplanationEntry(rule.getExplanation(), desire);
080             explanations.add(entry);
081         }
082         step.setExplanation(new Explanation(explanations));
083         if (logger.isDebugEnabled()) {
084             logger.debug("evaluateRules(Collection<Rule> rules=" + rules
085                     ", State current=" + current + ", State next=" + next
086                     ") - combined evaluation=" + evaluation);
087         }
088         return evaluation;
089     }
090 
091     /*
092      * (non-Javadoc)
093      
094      * @see dk.deepthought.sidious.ruleengine.RuleEngine#extractGoals(dk.deepthought.sidious.supportsystem.SuperLinkID)
095      */
096     public Collection<Goal> extractGoals(SuperLinkID requesterID) {
097         PlanRequester requester = Repository.getBlackboard().getRequester(
098                 requesterID);
099         if (requester == null) {
100             logger.error("extractGoals(SuperLinkID requesterID=" + requesterID
101                     ") - requester does not exist - returning empty list");
102             return new ArrayList<Goal>();
103         }
104         Collection<Rule> rules = requester.getRules();
105         Collection<Goal> returnCollection = extractGoalsFromRules(rules);
106         if (logger.isDebugEnabled()) {
107             logger.debug("extractGoals(SuperLinkID requesterID=" + requesterID
108                     ") - returned goals=" + returnCollection);
109         }
110         return returnCollection;
111     }
112 
113     /**
114      * Method extracts and returns all goals from the input <code>rules</code>.
115      
116      @param rules
117      *            the rules the goals will be extracted from
118      @return the extracted goals
119      */
120     Collection<Goal> extractGoalsFromRules(Collection<Rule> rules) {
121         if (rules == null) {
122             logger
123                     .error("extractGoalsFromRules(Collection<Rule> rules=null) - null not valid");
124             throw new IllegalArgumentException("Null not valid");
125         }
126         Collection<Goal> goals = new ArrayList<Goal>();
127         for (Rule rule : rules) {
128             goals.addAll(rule.getGoals());
129         }
130         if (logger.isDebugEnabled()) {
131             logger.debug("extractGoalsFromRules(Collection<Rule> rules="
132                     + rules + ") - return value=" + goals);
133         }
134         return goals;
135     }
136     
137 }