View Javadoc

1   /*
2   * The contents of this file are subject to the BT "ZEUS" Open Source 
3   * Licence (L77741), Version 1.0 (the "Licence"); you may not use this file 
4   * except in compliance with the Licence. You may obtain a copy of the Licence
5   * from $ZEUS_INSTALL/licence.html or alternatively from
6   * http://www.labs.bt.com/projects/agents/zeus/licence.htm
7   * 
8   * Except as stated in Clause 7 of the Licence, software distributed under the
9   * Licence is distributed WITHOUT WARRANTY OF ANY KIND, either express or 
10  * implied. See the Licence for the specific language governing rights and 
11  * limitations under the Licence.
12  * 
13  * The Original Code is within the package zeus.*.
14  * The Initial Developer of the Original Code is British Telecommunications
15  * public limited company, whose registered office is at 81 Newgate Street, 
16  * London, EC1A 7AJ, England. Portions created by British Telecommunications 
17  * public limited company are Copyright 1996-9. All Rights Reserved.
18  * 
19  * THIS NOTICE MUST BE INCLUDED ON ANY COPY OF THIS FILE
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        //this.setPriority(NORM_PRIORITY+2);
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        //this.setPriority(NORM_PRIORITY+2);
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 //      Thread me = Thread.currentThread();
184       switch(tag) {
185          case Node.ADD:
186          //     System.out.println("in ConflictSet.update()... attempting to Q event for processing"); 
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 //            Core.DEBUG(3,diagnostic + " [" + me.getName() + "]");
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 //                  Core.DEBUG(3,diagnostic + " [" + me.getName() + "]");
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 ) // i.e. a local engine
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         // System.out.println("in ConflictSet.run()... waiting for next event to be enqueued"); 
249 	     info = (Info)queue.dequeue();
250 	    // System.out.println("in ConflictSet.run()... processing rule");
251 
252 //       Thread me = Thread.currentThread();
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 //       Core.DEBUG(2,diagnostic + " [" + me.getName() + "]");
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       //  System.out.println("generating action");
297         BasicAction action = factory.getAction(a.type);
298         action.setActuators(this,context);
299         //System.out.println("Action was : " + action.toString()); 
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 }