001 package dk.deepthought.sidious.blackboard;
002 
003 import java.util.Collection;
004 
005 import org.apache.commons.logging.Log;
006 import org.apache.commons.logging.LogFactory;
007 
008 import dk.deepthought.sidious.goalhandler.Goal;
009 import dk.deepthought.sidious.planner.Plan;
010 import dk.deepthought.sidious.planner.PlannerEngine;
011 import dk.deepthought.sidious.supportsystem.Adjustable;
012 import dk.deepthought.sidious.supportsystem.PlanRequester;
013 import dk.deepthought.sidious.supportsystem.Repository;
014 import dk.deepthought.sidious.supportsystem.SuperLinkID;
015 import dk.deepthought.sidious.util.SidiousMap;
016 
017 /**
018  * This class acts as a blackboard. It facilitates the communication
019  * between the various components of the system.
020  <p>
021  * The class is implemented as a Singleton.
022  
023  @author Deepthought
024  
025  */
026 public class BlackBoardEngine implements BlackBoard {
027     
028     /**
029      * Logger for this class.
030      */
031     private static final Log logger = LogFactory.getLog(BlackBoardEngine.class);
032 
033     /**
034      * The instance of the blackboard; to facilitate singleton property.
035      */
036     private static final BlackBoard INSTANCE = new BlackBoardEngine();
037 
038     /**
039      * This maps the id of a plan requester to the actual reference.
040      */
041     private final SidiousMap requesterMapping;
042 
043     /**
044      * Private constructor; to facilitate singleton property.
045      */
046     private BlackBoardEngine() {
047         requesterMapping = new SidiousMap();
048         if (logger.isDebugEnabled()) {
049             logger.debug("BlackBoardEngine() - initialized");
050         }
051     }
052 
053     /**
054      * Returns a reference to the blackboard of the system.
055      <p>
056      * Note that the blackboard is implemented as a Singleton.
057      
058      @return a reference to the blackboard
059      */
060     public static BlackBoard getInstance() {
061         return INSTANCE;
062     }
063 
064     /**
065      * TESTING purposes ONLY!!
066      */
067     public void addToMapping(PlanRequester requester) {
068         SuperLinkID id = requester.getID();
069         synchronized (requesterMapping) {
070             PlanRequester put = requesterMapping.put(id, requester);
071             if (put != null) {
072                 logger.warn("requestPlan(PlanRequester requester=" + requester
073                         ") - requester already in map");
074             }
075         }
076     }
077 
078     /* (non-Javadoc)
079      * @see dk.deepthought.sidious.blackboard.BlackBoard#requestPlan(dk.deepthought.sidious.supportsystem.PlanRequester)
080      */
081     public void requestPlan(PlanRequester requester) {
082         if (requester == null) {
083             logger
084                     .error("requestPlan(PlanRequester requester=null) - requester was null");
085             throw new IllegalArgumentException("requester was null");
086         }
087         SuperLinkID id = requester.getID();
088         synchronized (requesterMapping) {
089             PlanRequester put = requesterMapping.put(id, requester);
090             if (put != null) {
091                 logger.warn("requestPlan(PlanRequester requester=" + requester
092                         ") - requester already in map");
093             }
094         }
095         
096         Repository.getGoalHandler().request(id);
097         if (logger.isDebugEnabled()) {
098             logger.debug("requestPlan(PlanRequester requester=" + requester
099                     ") - requested a plan");
100         }
101     }
102 
103     /**
104      * Returns a reference to the plan requester associated with the specified
105      <code>id</code>.
106      <p>
107      * If no requester is associated with the specified id, planning for the
108      * specified id is stopped in the PlannerEngine, and <code>null</code> is
109      * returned.
110      
111      @see PlannerEngine
112      
113      @param id
114      *            the id of the requested requester
115      @return a reference to the specified plan requester, or <code>null</code>
116      *         if requester does not exist
117      */
118     public PlanRequester getRequester(SuperLinkID id) {
119         if (id == null) {
120             logger.error("getRequester(SuperLinkID id=null) - not valid id");
121             throw new IllegalArgumentException("null not valid id");
122         }
123         PlanRequester returnPlanRequester = null;
124         synchronized (requesterMapping) {
125             returnPlanRequester = requesterMapping.get(id);
126         }
127         if (returnPlanRequester == null) {
128             logger.error("getRequester(SuperLinkID id=" + id
129                     ") - missing requester");
130             Repository.getPlanner().stop(id);
131             return null;
132         }
133         if (logger.isDebugEnabled()) {
134             logger.debug("getRequester(SuperLinkID id=" + id
135                     ") - return value=" + returnPlanRequester);
136         }
137         return returnPlanRequester;
138     }
139 
140     /*
141      * (non-Javadoc)
142      
143      * @see dk.deepthought.sidious.blackboard.BlackBoard#getAdjustableSetting(dk.deepthought.sidious.supportsystem.SuperLinkID,
144      *      dk.deepthought.sidious.supportsystem.SuperLinkID)
145      */
146     public double getAdjustableSetting(SuperLinkID requesterID,
147             SuperLinkID adjustableID) {
148         if (logger.isDebugEnabled()) {
149             logger.debug("getAdjustableSetting(SuperLinkID requesterID="
150                     + requesterID + ", SuperLinkID adjustableID="
151                     + adjustableID + ") - start");
152         }
153         if (adjustableID == null) {
154             logger
155                     .error("getAdjustableSetting(SuperLinkID requesterID="
156                             + requesterID
157                             ", SuperLinkID adjustableID=null) - not valid adjustableID");
158 
159             throw new IllegalArgumentException("null not valid adjustableID");
160 
161         }
162         PlanRequester requester = getRequester(requesterID);
163         if (requester == null) {
164             return 0;
165         }
166         Collection<Adjustable> adjustables = requester.getAdjustables();
167         double returnValue = 0;
168         for (Adjustable adjustable : adjustables) {
169             if (adjustable.getID().equals(adjustableID)) {
170                 returnValue = adjustable.getSetting();
171             }
172         }
173 
174         if (logger.isDebugEnabled()) {
175             logger.debug("getAdjustableSetting(SuperLinkID requesterID="
176                     + requesterID + ", SuperLinkID adjustableID="
177                     + adjustableID + ") - end - return value=" + returnValue);
178         }
179         return returnValue;
180     }
181 
182     /**
183      * Adds a goal to 
184      @param goal the goal to be added
185      */
186     public void addGoal(Goal goal) {
187         Repository.getPlanner().requestPlan(goal);
188     }
189 
190     /**
191      * Adds a plan to the blackboard.
192      <p>
193      * The requester of the plan is notified that the plan is ready; and is
194      * removed from the queue.
195      
196      @param plan
197      *            the devised plan
198      */
199     public void addPlan(Plan plan) {
200         SuperLinkID id = plan.getId();
201         synchronized (requesterMapping) {
202             PlanRequester requester = getRequester(id);
203             requester.setPlan(plan);
204             requesterMapping.remove(id);
205         }
206     }
207 
208     /* (non-Javadoc)
209      * @see dk.deepthought.sidious.blackboard.BlackBoard#deliverResult(java.lang.Object)
210      */
211     public void deliverResult(Object result) {
212         if (result instanceof Plan) {
213             Plan plan = (Planresult;
214             addPlan(plan);
215         else if (result instanceof Goal) {
216             Goal goal = (Goalresult;
217             addGoal(goal);
218         }
219     }
220 
221 }