1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package zeus.rete;
25
26 import java.util.*;
27 import java.io.*;
28 import zeus.util.*;
29 import zeus.concepts.*;
30 import zeus.concepts.fn.*;
31 import zeus.actors.AgentContext;
32 import zeus.actors.ResourceDb;
33 import zeus.rete.action.*;
34
35
36 public class ConflictSet extends Thread {
37 protected ReteEngine engine = null;
38 protected AgentContext context = null;
39 protected OntologyDb db = null;
40 protected boolean running = true;
41 protected Hashtable writers = new Hashtable();
42 protected Hashtable readers = new Hashtable();
43 public int cleanUpInterval = 1000;
44
45 Queue queue = new Queue(Rule.MAX_SALIENCE+1);
46
47 ConflictSet(ReteEngine engine, OntologyDb db) {
48 this.engine = engine;
49 this.db = db;
50
51 createWriter("t",System.out);
52 createReader("t",System.in);
53 }
54
55
56 ConflictSet(AgentContext context) {
57 this.context = context;
58 this.engine = context.ReteEngine();
59
60 createWriter("t",System.out);
61 createReader("t",System.in);
62 }
63
64
65 /***
66 return the hashtable where the output writers are stored for the print
67 and println actions
68 */
69 public Hashtable getWriters() {
70 return this.writers;
71 }
72
73
74 /***
75 return the tables where the readers are stored for the read and readln
76 actions
77 */
78 public Hashtable getReaders() {
79 return this.readers;
80 }
81
82
83 /***
84 set the hashtable of readers for the rete actions - it is
85 unlikely that agent developers will need this method
86 */
87 public void setReaders(Hashtable readers) {
88 this.readers = readers;
89 }
90
91
92 /***
93 set the hashtable of writers for the rete actions - unlikely
94 to be of much use to agent developers
95 */
96 public void setWriters (Hashtable writers ) {
97 this.writers = writers;
98 }
99
100
101 /***
102 createWriter method is used by the ReteEngine to open a write stream
103 */
104 public void createWriter(String logicalName, OutputStream os) {
105 if ( writers.containsKey(logicalName) ) {
106 Core.USER_ERROR("Output writer with logical name \'" + logicalName +
107 " is already defined");
108 return;
109 }
110
111 PrintWriter out = new PrintWriter(os,true);
112 writers.put(logicalName,out);
113 }
114
115
116
117 /***
118 createWriter method is used by the ReteEngine to open a write stream
119 */
120 public void createWriter(String logicalName, String filename, boolean append) {
121 if ( writers.containsKey(logicalName) ) {
122 Core.USER_ERROR("Output writer with logical name \'" + logicalName +
123 " is already defined");
124 return;
125 }
126
127 try {
128 PrintWriter out = new PrintWriter(new FileWriter(filename,append),true);
129 writers.put(logicalName,out);
130 }
131 catch(IOException e) {
132 Core.USER_ERROR("Cannot create file " + filename);
133 }
134 }
135
136
137 /***
138 createReader method is used by the ReteEngine to open a read stream
139 */
140 public void createReader(String logicalName, String filename) {
141 if ( readers.containsKey(logicalName) ) {
142 Core.USER_ERROR("Input reader with logical name \'" + logicalName +
143 " is already defined");
144 return;
145 }
146
147 try {
148 DataReader r = new DataReader(new FileReader(filename));
149 readers.put(logicalName,r);
150 }
151 catch(FileNotFoundException e) {
152 Core.USER_ERROR("File not found: " + filename + ". Cannot create reader");
153 }
154 }
155
156
157 /***
158 createReader method is used by the ReteEngine to open a read stream
159 */
160 public void createReader(String logicalName, InputStream in) {
161 if ( readers.containsKey(logicalName) ) {
162 Core.USER_ERROR("Input reader with logical name \'" + logicalName +
163 " is already defined");
164 return;
165 }
166 DataReader r = new DataReader(new InputStreamReader(in));
167 readers.put(logicalName,r);
168 }
169
170 /***
171 superceeded by getOntologyDb()
172 */
173 OntologyDb ontology() {
174 return (context == null) ? db : context.OntologyDb();
175 }
176
177
178 void update(String path, int tag, Vector input,
179 Bindings bindings, ActionNode node) {
180 Info info;
181 String diagnostic;
182
183
184 switch(tag) {
185 case Node.ADD:
186
187 info = new Info();
188 info.path = path;
189 info.input = input;
190 info.bindings = bindings;
191 info.node = node;
192 diagnostic = "==> Activation: " + node.rule_name + ": " + getFactList(input);
193 engine.fireEvent(ReteEngine.RULE_ACTIVATED,node,diagnostic);
194 Core.DEBUG(3,diagnostic);
195
196 queue.enqueue(info,Rule.MAX_SALIENCE-node.salience);
197 break;
198
199 case Node.REMOVE:
200 Enumeration enum = queue.elements();
201 while( enum.hasMoreElements() ) {
202 info = (Info)enum.nextElement();
203 if ( info.path.equals(path) && info.node == node &&
204 sameInput(info.input,input) ) {
205 diagnostic = "<== Activation: " + node.rule_name + ": " + getFactList(input);
206 engine.fireEvent(ReteEngine.RULE_DEACTIVATED,node,diagnostic);
207 Core.DEBUG(3,diagnostic);
208
209 queue.remove(info);
210 }
211 }
212 break;
213 }
214 }
215
216
217 public void reset() {
218 queue.clear();
219 }
220
221
222 public void assertFact(Fact f1) {
223 if ( context == null )
224 engine.update(Node.ADD,f1);
225 else
226 context.ResourceDb().add(f1);
227 }
228
229
230 public void retract(Fact f1) {
231 if ( context == null )
232 engine.update(Node.REMOVE,f1);
233 else
234 context.ResourceDb().del(f1);
235 }
236
237
238 public void run() {
239 Action a;
240 Info info;
241 String diagnostic;
242
243 int count = 0;
244
245 while(running) {
246
247 Core.DEBUG(5,this);
248
249 info = (Info)queue.dequeue();
250
251
252
253 diagnostic = "FIRE [" + info.node.rule_name + "; " +
254 info.input.size() + " facts] " + getFactList(info.input);
255 engine.fireEvent(ReteEngine.RULE_FIRED,info.node,diagnostic);
256
257 Core.DEBUG(2,diagnostic);
258
259
260 for(int i = 0; i < info.node.actions.size(); i++ ) {
261 a = (Action)info.node.actions.elementAt(i);
262 executeAction(a,info);
263 }
264 yield();
265 if (count>cleanUpInterval) {
266 System.gc();
267 System.runFinalization();
268 count = 0;
269 }
270 count++;
271 }
272 }
273
274
275 /***
276 * executeAction is what causes a rule action to be executed when a rule has been
277 * matched to.
278 * This uses an AbstractFactory to get the action and then asks it to execute itself
279 *@author Simon Thompson
280 *.@since 1.2 (complete rewrite)
281 */
282 protected void executeAction(Action a, Info info) {
283 Fact f1;
284 boolean found;
285 ValueFunction var, type_var, value, value1;
286 ReteFact token;
287 String attribute, output, str;
288 Enumeration enum;
289 Action b;
290 PrintWriter out;
291 DataReader in;
292
293 AbstractActionFactory actionFact = new AbstractActionFactory();
294 ActionFactory factory = actionFact.getActionFactory ();
295 try {
296
297 BasicAction action = factory.getAction(a.type);
298 action.setActuators(this,context);
299
300 action.executeAction (a,info); }
301 catch (Exception e) {
302 e.printStackTrace(); }
303
304
305 }
306
307
308 private String getFactList(Vector input) {
309 String s = "";
310 Fact f;
311 for(int i = 0; i < input.size(); i++ ) {
312 f = (Fact)input.elementAt(i);
313 s += f.getId();
314 if ( i+1 < input.size() ) s += ", ";
315 }
316 return s;
317 }
318 /***
319 * store and input contain an ordered list of (ground) facts
320 * The method getIdString() of the Fact class can be used to
321 * compare the lists
322 */
323 private boolean sameInput(Vector store, Vector input) {
324 String s1 = getFactList(store);
325 String s2 = getFactList(input);
326 return s1.equals(s2);
327 }
328
329
330 public String toString() {
331 String s = "BEGIN CONFLICT SET\n";
332 Info info;
333 Enumeration enum = queue.elements();
334 while( enum.hasMoreElements() ) {
335 info = (Info)enum.nextElement();
336 s += info.node.rule_name + ": " + getFactList(info.input) + "\n";
337 }
338 s += "END CONFLICT SET";
339 return s;
340 }
341
342
343 }