1 | package dk.deepthought.sidious.blackboard; |
2 | |
3 | import java.util.Collection; |
4 | |
5 | import org.apache.commons.logging.Log; |
6 | import org.apache.commons.logging.LogFactory; |
7 | |
8 | import dk.deepthought.sidious.goalhandler.Goal; |
9 | import dk.deepthought.sidious.planner.Plan; |
10 | import dk.deepthought.sidious.planner.PlannerEngine; |
11 | import dk.deepthought.sidious.supportsystem.Adjustable; |
12 | import dk.deepthought.sidious.supportsystem.PlanRequester; |
13 | import dk.deepthought.sidious.supportsystem.Repository; |
14 | import dk.deepthought.sidious.supportsystem.SuperLinkID; |
15 | import dk.deepthought.sidious.util.SidiousMap; |
16 | |
17 | /** |
18 | * This class acts as a blackboard. It facilitates the communication |
19 | * between the various components of the system. |
20 | * <p> |
21 | * The class is implemented as a Singleton. |
22 | * |
23 | * @author Deepthought |
24 | * |
25 | */ |
26 | public class BlackBoardEngine implements BlackBoard { |
27 | |
28 | /** |
29 | * Logger for this class. |
30 | */ |
31 | private static final Log logger = LogFactory.getLog(BlackBoardEngine.class); |
32 | |
33 | /** |
34 | * The instance of the blackboard; to facilitate singleton property. |
35 | */ |
36 | private static final BlackBoard INSTANCE = new BlackBoardEngine(); |
37 | |
38 | /** |
39 | * This maps the id of a plan requester to the actual reference. |
40 | */ |
41 | private final SidiousMap requesterMapping; |
42 | |
43 | /** |
44 | * Private constructor; to facilitate singleton property. |
45 | */ |
46 | private BlackBoardEngine() { |
47 | requesterMapping = new SidiousMap(); |
48 | if (logger.isDebugEnabled()) { |
49 | logger.debug("BlackBoardEngine() - initialized"); |
50 | } |
51 | } |
52 | |
53 | /** |
54 | * Returns a reference to the blackboard of the system. |
55 | * <p> |
56 | * Note that the blackboard is implemented as a Singleton. |
57 | * |
58 | * @return a reference to the blackboard |
59 | */ |
60 | public static BlackBoard getInstance() { |
61 | return INSTANCE; |
62 | } |
63 | |
64 | /** |
65 | * TESTING purposes ONLY!! |
66 | */ |
67 | public void addToMapping(PlanRequester requester) { |
68 | SuperLinkID id = requester.getID(); |
69 | synchronized (requesterMapping) { |
70 | PlanRequester put = requesterMapping.put(id, requester); |
71 | if (put != null) { |
72 | logger.warn("requestPlan(PlanRequester requester=" + requester |
73 | + ") - requester already in map"); |
74 | } |
75 | } |
76 | } |
77 | |
78 | /* (non-Javadoc) |
79 | * @see dk.deepthought.sidious.blackboard.BlackBoard#requestPlan(dk.deepthought.sidious.supportsystem.PlanRequester) |
80 | */ |
81 | public void requestPlan(PlanRequester requester) { |
82 | if (requester == null) { |
83 | logger |
84 | .error("requestPlan(PlanRequester requester=null) - requester was null"); |
85 | throw new IllegalArgumentException("requester was null"); |
86 | } |
87 | SuperLinkID id = requester.getID(); |
88 | synchronized (requesterMapping) { |
89 | PlanRequester put = requesterMapping.put(id, requester); |
90 | if (put != null) { |
91 | logger.warn("requestPlan(PlanRequester requester=" + requester |
92 | + ") - requester already in map"); |
93 | } |
94 | } |
95 | |
96 | Repository.getGoalHandler().request(id); |
97 | if (logger.isDebugEnabled()) { |
98 | logger.debug("requestPlan(PlanRequester requester=" + requester |
99 | + ") - 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 = (Plan) result; |
214 | addPlan(plan); |
215 | } else if (result instanceof Goal) { |
216 | Goal goal = (Goal) result; |
217 | addGoal(goal); |
218 | } |
219 | } |
220 | |
221 | } |