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  /*
25   * @(#)OntologyDb.java 1.0
26   */
27  
28  package zeus.concepts;
29  
30  import java.io.*;
31  import java.util.*;
32  import javax.swing.event.*;
33  
34  import zeus.util.*;
35  import zeus.concepts.fn.*;
36  //import zeus.ontology.DAMLWriter;
37  //import zeus.ontology.DAMLReader;
38  
39  /***
40   * This implements the Ontology Database component, which has two main roles:
41   * <ul>
42   * <li> database - to store the conceptual descriptions that make up an ontology
43   * <li> factory - to create new {@link Fact} objects from the stored fact descriptions
44   * </ul> <p>
45   *
46   * Aside from the fact creation and query methods, developers are unlikely to
47   * need the other methods of this class.
48   * Change Log
49   * 26/06/01 introduced allAncestors method which returns an interator containing all 
50   * ancestors of a type - Simon Thompson
51   */
52  
53  
54  public class OntologyDb extends Tree {
55    /*** OntologyDbChangeEvent types */
56  
57    public static final int RELOAD               = 0;
58    public static final int FACT_ADDED           = 1;
59    public static final int FACT_REMOVED         = 2;
60    public static final int FACT_RENAMED         = 3;
61    public static final int ATTRIBUTES_CHANGED   = 4;
62    public static final int RESTRICTION_ADDED    = 5;
63    public static final int RESTRICTION_REMOVED  = 6;
64    public static final int RESTRICTION_CHANGED  = 7;
65  
66    /*
67      Note: methods prefixed with __ are used by the parser
68    */
69  
70    public static final String ROOT     = "ZeusFact";
71    public static final String ABSTRACT = "Abstract";
72    public static final String ENTITY   = "Entity";
73    public static final String MESSAGE  = "Message";
74    public static final String MONEY    = "Money";
75  
76    public static final String AMOUNT    = "amount";
77    public static final String NUMBER    = "number";
78    public static final String COST      = "unit_cost";
79    public static final String GOAL_FACT = "fact";
80  
81    public static final int WARNING_MASK = 1;
82    public static final int ERROR_MASK   = 2;
83  
84    static final String BEGIN_ONTOLOGY         = "BEGIN_ONTOLOGY";
85    static final String BEGIN_PREAMBLE         = "BEGIN_PREAMBLE";
86    static final String BEGIN_RESTRICTIONS     = "BEGIN_RESTRICTIONS";
87    static final String BEGIN_RESTRICTION_ITEM = "BEGIN_RESTRICTION_ITEM";
88    static final String BEGIN_FACTS            = "BEGIN_FACTS";
89    static final String BEGIN_FACT_ITEM        = "BEGIN_FACT_ITEM";
90    static final String BEGIN_ATTRIBUTE_LIST   = "BEGIN_ATTRIBUTE_LIST";
91    static final String BEGIN_ATTRIBUTE_ITEM   = "BEGIN_ATTRIBUTE_ITEM";
92  
93    static final String END_PREAMBLE           = "END_PREAMBLE";
94    static final String END_RESTRICTION_ITEM   = "END_RESTRICTION_ITEM";
95    static final String END_RESTRICTIONS       = "END_RESTRICTIONS";
96    static final String END_ATTRIBUTE_ITEM     = "END_ATTRIBUTE_ITEM";
97    static final String END_ATTRIBUTE_LIST     = "END_ATTRIBUTE_LIST";
98    static final String END_FACT_ITEM          = "END_FACT_ITEM";
99    static final String END_FACTS              = "END_FACTS";
100   static final String END_ONTOLOGY           = "END_ONTOLOGY";
101 
102   static final String SYSTEM_NAME            = "ZEUS-Ontology-Editor";
103 
104   static final String SYSTEM                 = ":system";
105   static final String VERSION                = ":version";
106   static final String NAME_TAG               = ":name";
107   static final String PARENT_TAG             = ":parent";
108   static final String TYPE_TAG               = ":type";
109   static final String VALUE_TAG              = ":value";
110   static final String REST_TAG               = ":restriction";
111   static final String DEFA_TAG               = ":default";
112   static final String QUOTE                  = "\"";
113 
114   static final int NAME        = 0;
115   static final int TYPE        = 1;
116   static final int RESTRICTION = 2;
117   static final int DEFAULT     = 3;
118 
119   protected static final String FACT_STR = "Fact";
120   protected static final String NAME_STR = "name";
121   protected static final String CSEP = "$";
122   protected static final String TFILE = "oetf22";
123 
124   public static final String STRING  = "String";
125   public static final String INTEGER = "Integer";
126   public static final String REAL    = "Real";
127   public static final String BOOLEAN = "Boolean";
128   public static final String DATE    = "Date";
129   public static final String TIME    = "Time";
130   public static final String LIST    = "List";
131 
132   public static final String OBJECT_TYPE = "JavaObject";
133 
134   public static final String[] BASIC_TYPES = {
135      STRING, INTEGER, REAL, BOOLEAN, DATE, TIME, LIST
136   };
137 
138   static final String[] PREDEFINED_FACTS = {
139      ROOT, MONEY, ABSTRACT, MESSAGE, ENTITY
140   };
141 
142   public static final String[] GOAL_ATTRIBUTES = {
143      GOAL_FACT, "end_time", "cost", "confirm_time"
144   };
145 
146 
147   protected EventListenerList changeListeners = new EventListenerList();
148   protected Hashtable factIndex;
149   protected OrderedHashtable restrictions;
150   protected int editableLimit;
151 
152   protected boolean save_needed = false;
153   protected String  error = null;
154   protected String  warning = null;
155   protected String  filename = null;
156   protected String ontologyName = null; 
157   protected GenSym  genSym = null;
158 
159   public OntologyDb () {
160    super (new FactDescription (ROOT));
161   }
162 
163   public OntologyDb(GenSym genSym) {
164      super(new FactDescription(ROOT));
165 
166      Assert.notNull(genSym);
167      this.genSym = genSym;
168 
169      factIndex = new Hashtable();
170      restrictions = new OrderedHashtable();
171      clear();
172   }
173 
174   public GenSym GenSym() { return genSym; }
175   
176   
177   /***
178    *return the actual user defined name of the ontology
179    */
180   public String getOntologyName () {
181     return ontologyName;
182   }
183   
184 
185 
186   public void clear() {
187      factIndex.clear();
188      restrictions.clear();
189 
190      root = new TreeNode(new FactDescription(ROOT));
191      factIndex.put(ROOT,root);
192 
193      TreeNode node, leaf;
194      node = root.addChild(new FactDescription(ABSTRACT));
195      factIndex.put(ABSTRACT,node);
196 
197      leaf = node.addChild(new FactDescription(MONEY));
198      factIndex.put(MONEY,leaf);
199      __addNewAttributeRow(MONEY, AMOUNT, REAL, "", "0");
200 
201      leaf = node.addChild(new FactDescription(MESSAGE));
202      factIndex.put(MESSAGE,leaf);
203      for(int i = 0; i < Performative.ATTRIBUTE_TYPES.length; i++ )
204      __addNewAttributeRow(MESSAGE, Performative.ATTRIBUTE_TYPES[i], STRING, "", "");
205 
206      node = root.addChild(new FactDescription(ENTITY));
207      factIndex.put(ENTITY,node);
208      __addNewAttributeRow(ENTITY, NUMBER, INTEGER, "", "1");
209      __addNewAttributeRow(ENTITY, COST, REAL, "", "0");
210 
211      editableLimit = 0;
212 
213      error = null;
214      warning = null;
215      filename = null;
216      fireChanged(RELOAD,null);
217      save_needed = false;
218   }
219 
220   // -- FILE MANAGEMENT OPERATIONS ---------------------------------
221 
222   public boolean isSaveNeeded() { return save_needed; }
223   public String  getError()     { return error; }
224   public String  getWarning()   { return warning; }
225   public String  getFilename()  { return filename;  }
226 
227   public void __setWarning(String info) {
228      if ( warning == null )
229         warning = info;
230      else
231         warning += "\n" + info;
232   }
233 
234   public int saveDAML(File file) {
235     
236     // not in this version.
237       return (0); 
238   }
239 
240 
241 //----------------------------G.Owusu 18.6.99-------------------------------
242   static final String HEADER = "<?xml version=\"1.0\">";
243   static final String ELEMENT_TAG = "!ELEMENT";
244   static final String ATTRIBUTE_TAG = "!ATTLIST";
245   static final String LT = "<";
246   static final String GT = ">";
247   static final String SPACE = " ";
248   static final String OPEN_BRACKET = "(";
249   static final String CLOSE_BRACKET = ")";
250   static final String COMMA = ",";
251   static final String PCDATA = "#PCDATA";
252   static final String CDATA = "CDATA";
253 
254   public int saveXML(File file) 
255   {
256     Assert.notNull(file);
257     int status = 0;
258     int num = 0;
259     error = null;
260     String dir, temp, fsep;
261     Enumeration enum;
262     FactDescription desc;
263     TreeNode node;
264     String name, output, default_info, restriction_info;
265     String[][] attributes;
266     Vector elementNodes;
267 
268     try {
269       dir = file.getParent();
270       temp = (dir != null) ? dir + File.separator + TFILE : TFILE;
271       File f1 = new File(temp);
272 
273       while( f1.exists() )
274         f1 = new File(temp + (num++));
275 
276       String filename = file.getName();
277       int index = filename.indexOf('.');
278       String documentName = (index == -1) ? filename : filename.substring(0,index);
279 
280       PrettyPrintWriter out = new PrettyPrintWriter(f1);
281       out.pprint(0,HEADER);
282       out.pprint(0,"<!DOCTYPE" + SPACE + documentName + SPACE + "[");
283 
284       enum = this.nodes();
285       while( enum.hasMoreElements() ) {
286          node = (TreeNode)enum.nextElement();
287          desc = (FactDescription)node.getValue();
288          name = desc.getName();
289          if ( !Misc.member(name,PREDEFINED_FACTS) ) {
290             attributes = desc.getAttributes();
291 
292             /* First, write ELEMENT info */
293             output = LT + ELEMENT_TAG + SPACE + name + SPACE + OPEN_BRACKET;
294 
295             elementNodes = getElementNodes(desc);
296 
297             if ( !elementNodes.isEmpty() ) {
298                for(int i = 0; i < elementNodes.size(); i++ ) {
299                   output += elementNodes.elementAt(i);
300                   if ( i < elementNodes.size() - 1 )
301                      output += COMMA;
302                }
303             }
304             else {
305                output += PCDATA;
306             }
307             output += CLOSE_BRACKET + GT;
308             out.pprint(2,output);
309 
310             /* Next, write ATTLIST info */
311             if ( hasBasicAttributes(desc) ) {
312                out.pprint(2, LT + ATTRIBUTE_TAG + SPACE + name);
313                for(int i = 0; i < attributes.length; i++ ) {
314                   if ( !elementNodes.contains(attributes[i][NAME]) ) {
315                    
316                      restriction_info = default_info = "";
317                      if (attributes[i][RESTRICTION] != null )
318                         restriction_info = attributes[i][RESTRICTION].trim();
319    
320                if (attributes[i][DEFAULT] != null )
321                          default_info = attributes[i][DEFAULT].trim();
322    
323                      if ( restriction_info.indexOf('|') == -1 ||
324                           restriction_info.indexOf('(') != -1 )
325                   output = SPACE + CDATA;
326                      else
327                         output = SPACE + OPEN_BRACKET + restriction_info + CLOSE_BRACKET;
328                  
329                      if ( default_info.length() > 0 )
330                         output += SPACE + "\"" + default_info + "\"";
331    
332                      out.pprint(4, attributes[i][NAME] + output);
333                   }
334                }
335                out.pprint(2,GT);
336             }
337             out.println();
338          }
339       }
340       out.pprint(0,"]>");
341 
342       out.flush();
343       out.close();
344 
345       if ( file.exists() ) file.delete();
346       f1.renameTo(file);
347     }
348     catch(Exception e) {
349       error = e.toString();
350       status |= ERROR_MASK;
351     }
352     return status;
353 
354   }
355 
356   protected Vector getElementNodes(FactDescription desc) {
357     String[][] attributes = desc.getAttributes();
358     Vector output = new Vector();
359     for(int i = 0; i < attributes.length; i++ ) {
360        if ( factIndex.containsKey(attributes[i][TYPE]) )
361           output.addElement(attributes[i][NAME]);
362     }
363     return output;
364   }
365 
366   protected boolean hasBasicAttributes(FactDescription desc) {
367     String[][] attributes = desc.getAttributes();
368     Vector output = new Vector();
369     for(int i = 0; i < attributes.length; i++ ) {
370        if ( Misc.member(attributes[i][TYPE],BASIC_TYPES) )
371           return true;
372     }
373     return false;
374   }
375 
376 
377 
378 //--------------------------------------------------------------------------
379   public int saveFile(File file)
380   {
381     Assert.notNull(file);
382 
383     String dir, temp, fsep;
384     int status = 0;
385     error = null;
386     warning = null;
387     int num = 0;
388 
389     dir = file.getParent();
390     temp = (dir != null) ? dir + File.separator + TFILE : TFILE;
391     File f1 = new File(temp);
392 
393     while( f1.exists() )
394        f1 = new File(temp + (num++));
395 
396     try 
397     {
398       String[][] attributes;
399       String[] entry;
400       String value;
401       Enumeration enum;
402       TreeNode node, parent;
403       FactDescription desc, parent_desc;
404       PrettyPrintWriter out = new PrettyPrintWriter(f1);
405 
406       out.pprint(0,BEGIN_ONTOLOGY);
407       out.pprint(1,BEGIN_PREAMBLE);
408       out.pprint(2,SYSTEM  + " " + SYSTEM_NAME);
409       out.pprint(2,VERSION + " \"" + SystemProps.getProperty("version.id") + "\"");
410       out.pprint(1,END_PREAMBLE);
411 
412       enum = restrictions.elements();
413       if ( enum.hasMoreElements() ) 
414       {
415          out.pprint(1,BEGIN_RESTRICTIONS);
416          while( enum.hasMoreElements() ) 
417          {
418             out.pprint(2,BEGIN_RESTRICTION_ITEM);
419             entry = (String[])enum.nextElement();
420             value = (entry[2] != null) ? entry[2] : "";
421             out.pprint(3,NAME_TAG  + " " + entry[0]);
422             out.pprint(3,TYPE_TAG  + " " + entry[1]);
423             out.pprint(3,VALUE_TAG + " " + QUOTE + value + QUOTE);
424             out.pprint(2,END_RESTRICTION_ITEM);
425          }
426          out.pprint(1,END_RESTRICTIONS);
427       }
428 
429       enum = this.nodes();
430       if ( enum.hasMoreElements() ) 
431       {
432         out.pprint(1,BEGIN_FACTS);
433         while( enum.hasMoreElements() )
434         {
435           node = (TreeNode)enum.nextElement();
436           desc = (FactDescription)node.getValue();
437 
438           if ( !Misc.member(desc.getName(),PREDEFINED_FACTS) )
439           {
440             out.pprint(2,BEGIN_FACT_ITEM);
441             out.pprint(3,NAME_TAG + " " + desc.getName());
442             parent = node.getParent();
443             parent_desc = (FactDescription)parent.getValue();
444             out.pprint(3,PARENT_TAG + " " + parent_desc.getName());
445 
446             attributes = desc.getAttributes();
447             if ( attributes.length > 0 )
448             {
449               out.pprint(3,BEGIN_ATTRIBUTE_LIST);
450               for(int i = 0; i < attributes.length; i++ )
451               {
452                 for(int j = 0; j < attributes[i].length; j++ )
453                   if ( attributes[i][j] == null ) attributes[i][j] = "";
454 
455                 attributes[i][RESTRICTION] = QUOTE + attributes[i][RESTRICTION] + QUOTE;
456                 attributes[i][DEFAULT] = QUOTE + attributes[i][DEFAULT] + QUOTE;
457 
458                 out.pprint(4,BEGIN_ATTRIBUTE_ITEM);
459                 out.pprint(5,NAME_TAG + " " + attributes[i][NAME]);
460                 out.pprint(5,TYPE_TAG + " " + attributes[i][TYPE]);
461                 out.pprint(5,REST_TAG + " " + attributes[i][RESTRICTION]);
462                 out.pprint(5,DEFA_TAG + " " + attributes[i][DEFAULT]);
463                 out.pprint(4,END_ATTRIBUTE_ITEM);
464               }
465               out.pprint(3,END_ATTRIBUTE_LIST);
466             }
467             out.pprint(2,END_FACT_ITEM);
468           }
469         }
470         out.pprint(1,END_FACTS);
471       }
472 
473       out.pprint(0,END_ONTOLOGY);
474       out.flush();
475       out.close();
476 
477       if ( file.exists() ) file.delete();
478       f1.renameTo(file);
479       save_needed = false;
480     }
481     catch(Exception e) {
482       error = e.toString();
483       status |= ERROR_MASK;
484     }
485     setFilename(file);
486     return status;
487   }
488 
489   public int openFile(File file) {
490 
491     Assert.notNull(file);
492     int status = 0;
493     clear();
494 
495     try {
496        OntologyParser parser = new OntologyParser(new FileInputStream(file));
497        parser.parse(this);
498     }
499     catch(TokenMgrError t) {
500       //If it's not in the Zeus format, hope it's DAML
501         // but not in this version.
502         clear();
503       error = t.toString();
504       status |= ERROR_MASK;
505     }
506     catch(Exception e) {
507       clear();
508       error = e.toString();
509       status |= ERROR_MASK;
510     }
511     if ( warning != null ) status |= WARNING_MASK;
512     setFilename(file);
513     fireChanged(RELOAD,file.getName());
514     save_needed = false;
515     return status;
516   }
517 
518   private void setFilename(File file) {
519     try {
520        ontologyName = file.getName(); 
521        filename = file.getCanonicalPath();
522     }
523     catch(IOException e) {
524        ontologyName = file.getName(); 
525        filename = file.getAbsolutePath();
526     }
527   }
528 
529   // -- FACT QUERY METHODS -----------------------------------------
530   public boolean isAncestorOf(String name, String parent) {
531      FactDescription fd;
532      TreeNode node = (TreeNode)factIndex.get(name);
533      while( node != null ) {
534         fd = (FactDescription)node.getValue();
535         if ( fd.getName().equals(parent) ) return true;
536         node = node.getParent();
537      }
538      return false;
539   }
540   
541   
542   /*** 
543     *  get a list of the ancestors of a type 
544     *@since 1.2.2
545     *@author Simon Thompson
546     */
547   public Iterator allAncestors (String name) { 
548      ArrayList list = new ArrayList ();       
549      FactDescription fd;
550      TreeNode node = (TreeNode)factIndex.get(name);
551      while( node != null ) {
552         fd = (FactDescription)node.getValue();
553         list.add(fd.getName()); 
554         node = node.getParent();
555      }
556      return list.iterator(); 
557   }
558   
559 
560   public TreeNode addChildFact(TreeNode parent) {
561      String name = genSym.plainId(FACT_STR);
562      while( factIndex.containsKey(name) )
563         name = genSym.plainId(FACT_STR);
564      TreeNode node =  parent.addChild(new FactDescription(name));
565      factIndex.put(name, node);
566      fireChanged(FACT_ADDED,name);
567      return node;
568   }
569 
570   /***
571    * New method added by Jaron to allow named facts to be added through an
572    * API call rather than the FactTable GUI
573    */
574   public boolean addNamedChildFact(TreeNode parent, String name)
575   {
576     if (factIndex.containsKey(name))
577       return false;
578     TreeNode node = parent.addChild(new FactDescription(name));
579     factIndex.put(name, node);
580     fireChanged(OntologyDb.RELOAD, name);
581     return true;
582   }
583 
584   public void __addChildFact(String parent, String name) {
585      TreeNode parentNode = (TreeNode)factIndex.get(parent);
586      TreeNode node =  parentNode.addChild(new FactDescription(name));
587      factIndex.put(name, node);
588   }
589 
590   public Object renameFact(String previous, String current) {
591      if ( factIndex.containsKey(current) ) return null;
592      if ( Misc.member(previous,PREDEFINED_FACTS) ) return null;
593 
594      TreeNode node = (TreeNode)factIndex.remove(previous);
595      Assert.notNull(node);
596      FactDescription desc = (FactDescription)node.getValue();
597      desc.setName(current);
598      factIndex.put(current,node);
599      fireChanged(FACT_RENAMED,current);
600      // REM propagate changes to all other facts (embedded attributes) ?
601      return node;
602   }
603 
604   public boolean isFactEditable(String name) {
605      return !Misc.member(name,PREDEFINED_FACTS);
606   }
607 
608   public void removeFact(TreeNode node) {
609      // excise branch from tree
610      TreeNode parent = node.getParent();
611      parent.removeChild(node);
612 
613      // remove entries from factIndex table
614      FactDescription desc;
615      Enumeration enum = node.values();
616      while(enum.hasMoreElements()) {
617         desc = (FactDescription)enum.nextElement();
618         factIndex.remove(desc.getName());
619      }
620      desc = (FactDescription)node.getValue();
621      fireChanged(FACT_REMOVED,desc.getName());
622   }
623 
624   public TreeNode copyFactTree(TreeNode node) {
625      FactDescription desc1 = (FactDescription)node.getValue();
626      FactDescription desc2 = new FactDescription(desc1);
627      TreeNode top_node = new TreeNode(desc2);
628      copyFactTree1(top_node,node);
629      return top_node;
630   }
631 
632   protected void copyFactTree1(TreeNode top_node, TreeNode node) {
633      FactDescription desc1, desc2;
634      Vector children = node.getChildren();
635      TreeNode lhs_node, rhs_node;
636      for(int i = 0; i < children.size(); i++ ) {
637         rhs_node = (TreeNode)children.elementAt(i);
638         desc1 = (FactDescription)rhs_node.getValue();
639         desc2 = new FactDescription(desc1);
640         lhs_node = new TreeNode(desc2);
641         top_node.addChild(lhs_node);
642         copyFactTree1(lhs_node,rhs_node);
643      }
644   }
645 
646   public TreeNode pasteFactTree(TreeNode parent, TreeNode node) {
647      TreeNode copy = copyFactTree(node);
648      TreeNode a_node;
649      FactDescription desc;
650      String name;
651      Enumeration enum = copy.nodes();
652      while(enum.hasMoreElements()) {
653         a_node = (TreeNode)enum.nextElement();
654         desc = (FactDescription)a_node.getValue();
655         name = desc.getName();
656         while( factIndex.containsKey(name) )
657            name = genSym.plainId(desc.getName() + CSEP);
658         desc.setName(name);
659         factIndex.put(name,a_node);
660      }
661      parent.addChild(copy);
662      desc = (FactDescription)copy.getValue();
663      fireChanged(FACT_ADDED,desc.getName());
664      return copy;
665   }
666 
667   public boolean hasFact(String fact) { return factIndex.containsKey(fact); }
668 
669 
670   /***
671    * This method is used to create a new Fact from its ontology description
672    */
673   public Fact getFact(boolean is_variable, String type) {
674      if ( !factIndex.containsKey(type) ) {
675         Core.USER_ERROR("Fact type: " + type +
676                         " does not exist in current ontology");
677         return null;
678      }
679      ValueFunction fn;
680      Fact f1 = new Fact(is_variable,type,this,genSym);
681      AttributeList attrList = new AttributeList();
682      String[][] entry = getNetAttributeEntriesFor(type);
683      String value;
684      for(int i = 0; i < entry.length; i++ ) {
685         value = entry[i][1];
686         if (  is_variable || value == null || value.equals("") )
687            value = Fact.newVar(genSym);
688         fn = ZeusParser.Expression(this,value);
689         attrList.put(entry[i][0],fn);
690      }
691      f1.setAttributeList(attrList);
692      return f1;
693   }
694 
695   // -- ATTRIBUTE QUERY METHODS --------------------------------------
696 
697   public String[][] getAttributeEntriesFor(String fact) {
698      if ( fact == null || fact.equals("") ) return new String[0][4];
699 
700      TreeNode node = (TreeNode)factIndex.get(fact);
701      FactDescription desc = (FactDescription)node.getValue();
702      String[][] result = desc.getAttributes();
703 
704      editableLimit = Misc.member(fact,PREDEFINED_FACTS)
705                      ? result.length : 0;
706 
707      return result;
708   }
709   public String[][] getAllAttributeEntriesFor(String fact) {
710      if ( fact == null || fact.equals("") ) return new String[0][4];
711 
712      // first collect all attributes: node --> parent --> grandparent --> etc
713      // and while doing so, count attributes
714 
715      FactDescription desc;
716      Vector temp = new Vector();
717      int sum = 0;
718      String[][] attributes;
719      TreeNode node = (TreeNode)factIndex.get(fact);
720      while( node != null ) {
721         desc = (FactDescription)node.getValue();
722         attributes = desc.getAttributes();
723         sum += attributes.length;
724         temp.addElement(attributes);
725         node = node.getParent();
726      }
727      // next concatenate
728      String[][] result = new String[sum][4];
729      int k = 0;
730      for(int i = temp.size() - 1; i >= 0; i-- ) {
731         attributes = (String[][])temp.elementAt(i);
732         for(int j = 0; j < attributes.length; j++ )
733            result[k++] = attributes[j];
734      }
735 
736      if ( Misc.member(fact,PREDEFINED_FACTS) )
737         editableLimit = result.length;
738      else
739         editableLimit = result.length -
740                         ((String[][])temp.elementAt(0)).length;
741 
742      return result;
743   }
744   public int getEditableLimit() {
745      return editableLimit;
746   }
747 
748   String[][] getNetAttributeEntriesFor(String fact) {
749      if ( fact == null || fact.equals("") ) return new String[0][2];
750 
751      //  collect all attributes: node --> parent --> grandparent --> etc
752      FactDescription desc;
753      Hashtable temp = new Hashtable();
754      TreeNode node = (TreeNode)factIndex.get(fact);
755      String[][] attributes;
756      String default_value;
757      while( node != null ) {
758         desc = (FactDescription)node.getValue();
759         attributes = desc.getAttributes();
760         for(int j = 0; j < attributes.length; j++ ) {
761            if ( attributes[j][DEFAULT] == null )
762               attributes[j][DEFAULT] = "";
763            default_value = (String)temp.get(attributes[j][NAME]);
764            if ( default_value == null || default_value.equals("") )
765               default_value = attributes[j][DEFAULT];
766            temp.put(attributes[j][NAME],default_value);
767         }
768         node = node.getParent();
769      }
770 
771      String[][] result = new String[temp.size()][2];
772      Enumeration enum = temp.keys();
773      for(int i = 0; enum.hasMoreElements(); i++ ) {
774         result[i][0] = (String)enum.nextElement();
775         result[i][1] = (String)temp.get(result[i][0]);
776      }
777      return result;
778   }
779 
780   String[] getNetAttributesOnlyFor(String fact) {
781      if ( fact == null || fact.equals("") ) return new String[0];
782 
783      //  collect all attributes: node --> parent --> grandparent --> etc
784      FactDescription desc;
785      HSet temp = new HSet();
786      TreeNode node = (TreeNode)factIndex.get(fact);
787      String[][] attributes;
788      while( node != null ) {
789         desc = (FactDescription)node.getValue();
790         attributes = desc.getAttributes();
791         for(int j = 0; j < attributes.length; j++ )
792            temp.add(attributes[j][NAME]);
793         node = node.getParent();
794      }
795 
796      String[] result = new String[temp.size()];
797      Enumeration enum = temp.elements();
798      for(int i = 0; enum.hasMoreElements(); i++ )
799         result[i] = (String)enum.nextElement();
800      return result;
801   }
802 
803   public String setAttribute(String fact, String attribute,
804                              int column, String value) {
805      TreeNode node = (TreeNode)factIndex.get(fact);
806      FactDescription desc = (FactDescription)node.getValue();
807      String[] entry = desc.removeAttributeEntry(attribute);
808      switch(column) {
809         case NAME:
810              String value1 = value;
811              while( desc.containsAttribute(value1) )
812                 value1 = genSym.plainId(value + CSEP);
813              entry[NAME] = value1;
814              desc.setAttributeEntry(entry);
815              break;
816 
817         case TYPE:
818         case RESTRICTION:
819         case DEFAULT:
820              entry[column] = value;
821              desc.setAttributeEntry(entry);
822              break;
823 
824         default:
825              Core.FAIL("Unknown type in OntologyDb.setAttribute()");
826      }
827      fireChanged(ATTRIBUTES_CHANGED,fact);
828      return value;
829   }
830 
831   public void addNewAttributeRow(String fact) 
832   {
833     TreeNode node = (TreeNode)factIndex.get(fact);
834     FactDescription desc = (FactDescription)node.getValue();
835 
836     String name = genSym.plainId(NAME_STR);
837     while( desc.containsAttribute(name) )
838       name = genSym.plainId(NAME_STR);
839 
840     String[] entry = { name, STRING, "", "" };
841     desc.setAttributeEntry(entry);
842     fireChanged(ATTRIBUTES_CHANGED,fact);
843   }
844 
845   public void addNewAttribute(String fact, String name, String type)
846   {
847     TreeNode node = (TreeNode)factIndex.get(fact);
848     FactDescription desc = (FactDescription)node.getValue();
849     String[] entry = { name, type, "", "" };
850     desc.setAttributeEntry(entry);
851   }
852 
853 
854   public void __addNewAttributeRow(String fact, String name, String type,
855                             String restriction, String default_value) {
856      TreeNode node = (TreeNode)factIndex.get(fact);
857      FactDescription desc = (FactDescription)node.getValue();
858      String[] entry = { name, type, restriction, default_value };
859      desc.setAttributeEntry(entry);
860   }
861 
862   public void deleteAttributes(String fact, String[] attributes) {
863      TreeNode node = (TreeNode)factIndex.get(fact);
864      FactDescription desc = (FactDescription)node.getValue();
865      for(int i = 0; i < attributes.length; i++ )
866         desc.removeAttributeEntry((String)attributes[i]);
867      fireChanged(ATTRIBUTES_CHANGED,fact);
868   }
869 
870   public void addAttributeRows(String fact, String[][] input) {
871      TreeNode node = (TreeNode)factIndex.get(fact);
872      FactDescription desc = (FactDescription)node.getValue();
873      for(int i = 0; i < input.length; i++) {
874         String name = input[i][NAME];
875         while( desc.containsAttribute(name) )
876            name = genSym.plainId(input[i][NAME] + CSEP);
877         input[i][NAME] = name;
878         desc.setAttributeEntry(input[i]);
879      }
880      fireChanged(ATTRIBUTES_CHANGED,fact);
881   }
882 
883   public TreeNode createAttributeTree(String fact, String name) {
884      Core.ERROR(factIndex.containsKey(fact),1,this);
885      TreeNode node = new TreeNode(name);
886      createAttributeTreeNodes(fact,node);
887      return node;
888   }
889 
890   protected void createAttributeTreeNodes(String fact, TreeNode base) {
891      // first collect all attributes: node --> parent --> grandparent --> etc
892      FactDescription desc;
893      Vector temp = new Vector();
894      TreeNode node = (TreeNode)factIndex.get(fact);
895      String[][] attributes;
896      while( node != null ) {
897         desc = (FactDescription)node.getValue();
898         attributes = desc.getAttributes();
899         temp.addElement(attributes);
900         node = node.getParent();
901      }
902 
903      // next concatenate
904      OrderedHashtable temp2 = new OrderedHashtable();
905      for(int i = 0; i < temp.size(); i++ ) {
906         attributes = (String[][])temp.elementAt(i);
907         for(int j = 0; j < attributes.length; j++ )
908      temp2.put(attributes[j][NAME],attributes[j][TYPE]);
909      }
910 
911      String name, type;
912      TreeNode child;
913      Enumeration enum = temp2.keys();
914      for(int i = 0; enum.hasMoreElements(); i++ ) {
915         name = (String)enum.nextElement();
916         child = base.addChild(name);
917 
918         type = (String)temp2.get(name);
919         if ( factIndex.containsKey(type) )
920            createAttributeTreeNodes(type,child);
921      }
922   }
923 
924   // -- RESTRICTIONS QUERY METHODS -----------------------------------
925 
926   public String[][] getAllRestrictions() {
927      String[][] data = new String[restrictions.size()][3];
928      Enumeration elements = restrictions.elements();
929      for(int i = 0; i < data.length; i++ )
930         data[i] = (String[])elements.nextElement();
931      return data;
932   }
933   public String[] getAllRestrictionNames() {
934      String[] data = new String[restrictions.size()];
935      String[] temp;
936      Enumeration elements = restrictions.elements();
937      for(int i = 0; i < data.length; i++ ) {
938         temp = (String[])elements.nextElement();
939         data[i] = temp[NAME];
940      }
941      return data;
942   }
943   public String setRestrictionData(String name, int column, Object aValue) {
944      String[] entry = null;
945      String value = (String)aValue;
946      switch(column) {
947         case NAME:
948              while( restrictions.containsKey(value) )
949                 value = genSym.plainId((String)aValue + CSEP);
950              entry = (String[])restrictions.get(name);
951              String previousKey = entry[NAME];
952              entry[column] = value;
953              restrictions.reKey(previousKey,entry[NAME],entry);
954              // REM propagate changes to all other restrictions and all facts?
955              break;
956 
957         case TYPE:
958         case RESTRICTION:
959              entry = (String[])restrictions.get(name);
960              entry[column] = value;
961              break;
962      }
963      fireChanged(RESTRICTION_CHANGED,entry[NAME]);
964      return entry[column];
965   }
966   public void addNewRestriction() {
967      String name = genSym.plainId(NAME_STR);
968      while( restrictions.containsKey(name) )
969         name = genSym.plainId(NAME_STR);
970      String[] entry = { name, STRING, "" };
971      restrictions.put(entry[NAME],entry);
972      fireChanged(RESTRICTION_ADDED,name);
973   }
974   public void deleteRestrictions(String[] names) {
975      for(int i = 0; i < names.length; i++ ) {
976         restrictions.remove(names[i]);
977         fireChanged(RESTRICTION_REMOVED,names);
978      }
979   }
980   public void addRestrictions(String[][] input) {
981      for(int i = 0; i < input.length; i++) {
982         String name = input[i][NAME];
983         while( restrictions.containsKey(name) )
984            name = genSym.plainId(input[i][NAME] + CSEP);
985         input[i][NAME] = name;
986         restrictions.put(input[i][NAME],input[i]);
987         fireChanged(RESTRICTION_ADDED,input[i][NAME]);
988      }
989   }
990   public void __addRestriction(String name, String type, String value) {
991      String[] input = { name, type, value };
992      restrictions.put(input[NAME],input);
993   }
994 
995   // --------- Validity Checking ----------------------------------
996 
997   public boolean[] validateFact(Fact f1) {
998      String[] attributes    = f1.listAttributes();
999      ValueFunction[] values = f1.listValues();
1000      boolean[] result = new boolean[values.length];
1001 
1002      for(int i = 0; i < result.length; i++ )
1003         result[i] = validate(f1.getType(),attributes[i],values[i]);
1004      return result;
1005   }
1006 
1007   boolean validate(String fact, String attribute, ValueFunction value) {
1008 // System.err.println("validate " + fact + " " + attribute + " " + value);
1009      TreeNode node = (TreeNode)factIndex.get(fact);
1010      if ( node == null )  {
1011 // System.err.println("Return false 1");
1012         return false;
1013      }
1014 
1015      FactDescription desc = (FactDescription)node.getValue();
1016      while( !desc.containsAttribute(attribute) && node != null &&
1017             (node = node.getParent()) != null ) {
1018         desc = (FactDescription)node.getValue();
1019      }
1020 
1021      if ( node == null ) {
1022 // System.err.println("Return false 2");
1023         return false;
1024      }
1025 
1026      String[] entry = desc.getAttributeEntry(attribute);
1027      String type = entry[TYPE];
1028      String b_type = getBasicType(type);
1029      ValueFunction v0 = null;
1030 
1031      String restriction = entry[RESTRICTION];
1032      if ( Misc.member(b_type,BASIC_TYPES) ) {
1033         v0 = checkRestrictionEntry(b_type,restriction);
1034         if ( v0 != null && !Misc.member(type,BASIC_TYPES) )
1035            v0 = checkRestriction(v0,type);
1036 // System.err.println("v0 = " + v0);
1037         if ( v0 == null ) {
1038 // System.err.println("Return false 4");
1039            return false;
1040         }
1041      }
1042      else {
1043         if ( !restriction.equals("") )  {
1044 // System.err.println("Return false 5");
1045            return false;
1046         }
1047         v0 = new VarFn(Fact.newVar(genSym));
1048 // System.err.println("v0 = " + v0);
1049      }
1050 
1051      value = value.unifiesWith(v0,new Bindings());
1052 // System.err.println("value = " + value);
1053 // System.err.println();
1054 
1055      return (value != null);
1056   }
1057 
1058   public boolean[][] getAllRestrictionValidityInfo() {
1059      boolean[][] output = new boolean[restrictions.size()][3];
1060      String name;
1061      Enumeration keys = restrictions.keys();
1062      for(int i = 0; i < output.length; i++ ) {
1063         name = (String)keys.nextElement();
1064         output[i] = isRestrictionValid(name);
1065      }
1066      return output;
1067   }
1068   public boolean[] isRestrictionValid(String name) {
1069      boolean[] output = new boolean[3];
1070      for(int i = 0; i < output.length; i++ )
1071         output[i] = true;
1072 
1073      if ( !restrictions.containsKey(name) )
1074         return output; // swing bug?
1075 
1076      output[RESTRICTION] = checkRestriction(null,name) != null;
1077      return output;
1078   }
1079 
1080   protected ValueFunction checkRestriction(ValueFunction child, String name) {
1081      String[] entry = (String[])restrictions.get(name);
1082      String basic_type = getRestrictionBasicType(name);
1083      ValueFunction v0 = checkRestrictionEntry(basic_type,entry[RESTRICTION]);
1084 
1085      if ( v0 != null && child != null )
1086         v0 = v0.unifiesWith(child,new Bindings());
1087 
1088      if ( basic_type.equals(entry[TYPE]) || (v0 == null) )
1089         return v0;
1090 
1091      return checkRestriction(v0,entry[TYPE]);
1092   }
1093 
1094   protected ValueFunction checkDefaultValue(String type, String value) {
1095      value = value.trim();
1096      if ( value.equals("") )
1097         return new VarFn(Fact.newVar(genSym));
1098 
1099      try {
1100         RestrictionParser parser;
1101         parser = new RestrictionParser(
1102            new ByteArrayInputStream(value.getBytes())
1103         );
1104 
1105         switch( Misc.whichPosition(type,BASIC_TYPES) ) {
1106            case 0: // STRING
1107               return parser.StringLiteral();
1108            case 1: // INTEGER
1109               return parser.IntegerExpression();
1110            case 2: // REAL
1111               return parser.RealExpression();
1112            case 3: // BOOLEAN
1113               return parser.BooleanLiteral();
1114            case 4: // DATE
1115               return parser.DateLiteral();
1116            case 5: // TIME
1117               return parser.TimeLiteral();
1118            case 6: // LIST
1119               return parser.VectorLiteral();
1120            default:
1121               return null;
1122         }
1123      }
1124      catch(Exception e) {
1125         return null;
1126      }
1127   }
1128   protected ValueFunction checkRestrictionEntry(String type, String value) {
1129      value = value.trim();
1130      if ( value.equals("") )
1131         return new VarFn(Fact.newVar(genSym));
1132 
1133      try {
1134         RestrictionParser parser;
1135         parser = new RestrictionParser(
1136            new ByteArrayInputStream(value.getBytes())
1137         );
1138 
1139         switch( Misc.whichPosition(type,BASIC_TYPES) ) {
1140            case 0: // STRING
1141               return parser.StringExpression();
1142            case 1: // INTEGER
1143               return parser.IntegerExpression();
1144            case 2: // REAL
1145               return parser.RealExpression();
1146            case 3: // BOOLEAN
1147               return parser.BooleanLiteral();
1148            case 4: // DATE
1149               return parser.DateExpression();
1150            case 5: // TIME
1151               return parser.TimeExpression();
1152            case 6: // LIST
1153               return parser.VectorLiteral();
1154            default:
1155               return null;
1156         }
1157      }
1158      catch(Exception e) {
1159         return null;
1160      }
1161   }
1162 
1163   protected String getRestrictionBasicType(String restriction) {
1164      String[] entry = (String[])restrictions.get(restriction);
1165      String type = entry[TYPE];
1166      if ( Misc.member(type,BASIC_TYPES) )
1167         return type;
1168      else
1169         return getRestrictionBasicType(type);
1170   }
1171 
1172   protected String getBasicType(String type) {
1173      if ( Misc.member(type,BASIC_TYPES) )
1174         return type;
1175      else if ( type.equals(OBJECT_TYPE) )
1176         return type;
1177      else if ( restrictions.containsKey(type) )
1178         return getRestrictionBasicType(type);
1179      else // isa fact
1180         return type;
1181   }
1182 
1183   public boolean[] isAttributeValid(String fact, String name) {
1184      boolean output[] = new boolean[4];
1185      for(int i = 0; i < output.length; i++ )
1186         output[i] = true;
1187 
1188      if ( fact == null || fact.equals("") ) return output;
1189 
1190 
1191      TreeNode node = (TreeNode)factIndex.get(fact);
1192      FactDescription desc = (FactDescription)node.getValue();
1193      String[] entry = desc.getAttributeEntry(name);
1194      String type = entry[TYPE];
1195      String inherited_type = getInheritedTypeFor(fact,name);
1196 
1197      String b_type = getBasicType(type);
1198      String b_inherited_type = getBasicType(inherited_type);
1199 
1200      ValueFunction v0 = null;
1201      ValueFunction v1 = null;
1202 
1203      // TYPE check
1204      if ( !b_type.equals(b_inherited_type) && !hasFact(b_type) &&
1205           !isAncestorOf(type,b_inherited_type) )
1206        output[TYPE] = false;
1207 
1208      String restriction = entry[RESTRICTION];
1209      if ( Misc.member(b_type,BASIC_TYPES) ) {
1210           v0 = checkRestrictionEntry(b_type,restriction);
1211           if ( v0 != null && !Misc.member(type,BASIC_TYPES) )
1212              v0 = checkRestriction(v0,type);
1213           output[RESTRICTION] = (v0 != null);
1214      }
1215      else {
1216         output[RESTRICTION] = restriction.equals("");
1217      }
1218 
1219      String value = entry[DEFAULT];
1220      if ( Misc.member(b_type,BASIC_TYPES) ) {
1221         v1 = checkDefaultValue(b_type,value);
1222         if ( v1 != null && v0 != null )
1223            v1 = v1.unifiesWith(v0,new Bindings());
1224         output[DEFAULT] = (v1 != null);
1225      }
1226      else {
1227         output[DEFAULT] = value.equals("");
1228      }
1229 
1230      return output;
1231   }
1232 
1233   protected String getInheritedTypeFor(String fact, String name) 
1234   {
1235     FactDescription desc;
1236     String type = null;
1237     String[] entry;
1238     TreeNode node = (TreeNode)factIndex.get(fact);
1239     while( node != null )
1240     {
1241       desc = (FactDescription)node.getValue();
1242       if ( !desc.containsAttribute(name) )
1243         return type;
1244       entry = desc.getAttributeEntry(name);
1245       type = entry[TYPE];
1246       node = node.getParent();
1247     }
1248     return type;
1249   }
1250 
1251   public boolean[][] getValidityInfoFor(String fact) {
1252      if ( fact == null || fact.equals("") ) return new boolean[0][4];
1253 
1254      TreeNode node = (TreeNode)factIndex.get(fact);
1255      FactDescription desc = (FactDescription)node.getValue();
1256      String[][] data = desc.getAttributes();
1257      boolean[][] output = new boolean[data.length][];
1258      for(int i = 0; i < output.length; i++ )
1259         output[i] = isAttributeValid(fact,data[i][NAME]);
1260      return output;
1261   }
1262 
1263   public boolean[][] getAllValidityInfoFor(String fact) {
1264      if ( fact == null || fact.equals("") ) return new boolean[0][4];
1265 
1266      // first collect all attributes: node --> parent --> grandparent --> etc
1267      // and while doing so, count attributes
1268 
1269      FactDescription desc;
1270      Vector temp = new Vector();
1271      int sum = 0;
1272      boolean[][] attributes;
1273      String name;
1274      TreeNode node = (TreeNode)factIndex.get(fact);
1275      while( node != null ) {
1276         desc = (FactDescription)node.getValue();
1277         name = desc.getName();
1278         attributes = getValidityInfoFor(name);
1279         sum += attributes.length;
1280         temp.addElement(attributes);
1281         node = node.getParent();
1282      }
1283      // next concatenate
1284      boolean[][] result = new boolean[sum][4];
1285      int k = 0;
1286      for(int i = temp.size() - 1; i >= 0; i-- ) {
1287         attributes = (boolean[][])temp.elementAt(i);
1288         for(int j = 0; j < attributes.length; j++ )
1289            result[k++] = attributes[j];
1290      }
1291      return result;
1292   }
1293 
1294   // -- EVENTLISTENER METHODS ---------------------------------------
1295 
1296   public void addChangeListener(ChangeListener x) {
1297     changeListeners.add(ChangeListener.class, x);
1298   }
1299 
1300   public void removeChangeListener(ChangeListener x) {
1301     changeListeners.remove(ChangeListener.class, x);
1302   }
1303 
1304   // -- FIRE EVENT METHODS ------------------------------------------
1305 
1306   protected void fireChanged(int type, Object data) {
1307     save_needed = true;
1308     OntologyDbChangeEvent c = new OntologyDbChangeEvent(this,type,data);
1309     Object[] listeners = changeListeners.getListenerList();
1310     for (int i= listeners.length-2; i >= 0; i -=2) {
1311       if (listeners[i] == ChangeListener.class) {
1312         ChangeListener cl = (ChangeListener)listeners[i+1];
1313         cl.stateChanged(c);
1314       }
1315     }
1316   }
1317 
1318    public static void main(String[] arg) {
1319      String file = null;
1320 
1321      OntologyDb z = new OntologyDb(new GenSym("sym"));
1322 
1323      String dir = System.getProperty("user.dir") +
1324                   System.getProperty("file.separator");
1325      z.openFile(new File(dir + arg[0]));
1326    }
1327 
1328   public Hashtable getFactIndex() {
1329     return factIndex;
1330   }
1331 
1332 }