View Javadoc

1   /*
2    * $Id: RestrictionEditorInspector.java,v 1.7 2005/06/22 20:12:04 aperezlo Exp $
3    *
4    * Copyright (c) 1999-2004, BBN Technologies, LLC.
5    * All rights reserved.
6    * http://www.daml.org/legal/opensource/bbn_license.html
7    */
8   
9   package com.bbn.swede.editor.visualeditors.restriction;
10  
11  import java.net.URISyntaxException;
12  import java.util.ArrayList;
13  import java.util.Arrays;
14  import java.util.Collection;
15  import java.util.HashSet;
16  import java.util.Iterator;
17  import java.util.List;
18  import java.util.Vector;
19  
20  import com.bbn.swede.core.IOWLDocument;
21  import com.bbn.swede.core.OWLCore;
22  import com.bbn.swede.core.dom.AttributeNode;
23  import com.bbn.swede.core.dom.DocumentRoot;
24  import com.bbn.swede.core.dom.IOASTChangeListener;
25  import com.bbn.swede.core.dom.IOASTDelta;
26  import com.bbn.swede.core.dom.IOASTDeltaVisitor;
27  import com.bbn.swede.core.dom.IOWLAbstractSyntaxTree;
28  import com.bbn.swede.core.dom.Namespace;
29  import com.bbn.swede.core.dom.OAST;
30  import com.bbn.swede.core.dom.OASTEvent;
31  import com.bbn.swede.core.dom.OASTNode;
32  import com.bbn.swede.core.dom.TagNode;
33  import com.bbn.swede.core.dom.owl.Imports;
34  import com.bbn.swede.core.dom.owl.Klass;
35  import com.bbn.swede.core.dom.owl.Restriction;
36  import com.bbn.swede.core.dom.rdf.Description;
37  import com.bbn.swede.editor.EditorPlugin;
38  import com.hp.hpl.jena.ontology.Individual;
39  import com.hp.hpl.jena.ontology.OntClass;
40  import com.hp.hpl.jena.ontology.OntModel;
41  import com.hp.hpl.jena.ontology.OntModelSpec;
42  import com.hp.hpl.jena.ontology.OntProperty;
43  import com.hp.hpl.jena.rdf.model.Model;
44  import com.hp.hpl.jena.rdf.model.ModelFactory;
45  import com.hp.hpl.jena.rdf.model.Property;
46  import com.hp.hpl.jena.rdf.model.RDFNode;
47  import com.hp.hpl.jena.rdf.model.Resource;
48  import com.hp.hpl.jena.rdf.model.Statement;
49  import com.hp.hpl.jena.rdf.model.StmtIterator;
50  import com.hp.hpl.jena.rdql.Query;
51  import com.hp.hpl.jena.rdql.QueryResults;
52  import com.hp.hpl.jena.rdql.ResultBinding;
53  import com.hp.hpl.jena.util.iterator.ExtendedIterator;
54  
55  /***
56   * This class supports various queries upon a Jena model which are required for
57   * the proper functioning of the Restriction Editor.
58   * 
59   * @author aperezlo
60   */
61  public class RestrictionEditorInspector
62  {
63  
64     private OntModel _jenaModel;
65  
66     private NamespaceModelSynchronizer _namespaceModelSynchronizer;
67  
68     private List _restrictionsCache;
69  
70     /***
71      * Retrieves the local restrictions from an OWL abstract syntax tree.
72      * @param oast the OAST of the current document
73      * @return a List of all the Restriction nodes in the document
74      */
75     protected List getLocalRestrictions(IOWLAbstractSyntaxTree oast)
76     {
77        List toReturn = toReturn = Arrays.asList(oast.getRoot().getNodesOfType(
78           OASTNode.OWL_RESTRICTION));
79        return toReturn;
80     }
81  
82     //   public OASTNameResolver getNameResolver()
83     //   {
84     //      return _nameResolver;
85     //   }
86  
87     /***
88      * Retrieves the URI of the class on which a restriction is defined.
89      * @param restriction a Jena restriction
90      * @return a String representation of the URI of the class upon which
91      *         this restriction is defined
92      */
93     public String getOrigin(com.hp.hpl.jena.ontology.Restriction restriction)
94     {
95        String toReturn = null;
96        OntModel model = (OntModel)restriction.getModel();
97        Model base = model.getRawModel();
98        StmtIterator stmts = model.listStatements(null, model
99           .createProperty(OASTNode.S_RDFS_URI + "#" + "subClassOf"), restriction
100          .as(RDFNode.class));
101       Statement s = null;
102       Iterator i = null;
103       Resource origin = null;
104       while (stmts.hasNext())
105       {
106          s = stmts.nextStatement();
107          if(s.getSubject().toString() != s.getObject().toString())
108          {
109             if(base.contains(s))
110             {
111                origin = s.getSubject();
112                break;
113             }
114          }
115 
116       }
117       if(origin != null)
118       {
119          toReturn = origin.getURI();
120       }
121 
122       return toReturn;
123    }
124 
125    /***
126     * Returns an object representing a portion of a restriction.
127     * 
128     * @see RestrictionWrapper
129     * @param rest the Restriction
130     * @param column the column (see {@link RestrictionEditor }
131     * @return an object representing the information identified by the requested
132     *         column
133     */
134    Object getObjectFromRestriction(Restriction rest, int column)
135    {
136       Object toReturn = null;
137       RestrictionWrapper wrapper = new RestrictionWrapper(rest);
138       switch(column)
139       {
140          case RestrictionEditor.PROPERTY_NAME_COLUMN:
141             toReturn = wrapper.getOnProperty();
142             break;
143          case RestrictionEditor.RESTRICTION_ORIGIN_COLUMN:
144             Resource jenaResource = rest.getAssociatedResource();
145             if(jenaResource.canAs(com.hp.hpl.jena.ontology.Restriction.class))
146             {
147                com.hp.hpl.jena.ontology.Restriction jenaRestriction = (com.hp.hpl.jena.ontology.Restriction)jenaResource
148                   .as(com.hp.hpl.jena.ontology.Restriction.class);
149                toReturn = getOrigin(jenaRestriction);
150             }
151             break;
152          case RestrictionEditor.RESTRICTION_TYPE_COLUMN:
153             toReturn = wrapper.getRestrictionType();
154             break;
155          case RestrictionEditor.RESTRICTION_VALUE_COLUMN:
156             String type = wrapper.getRestrictionType();
157             if(type == null)
158             {
159                toReturn = null;
160             }
161             else
162             {
163                toReturn = wrapper.getRestrictionValueText();
164                if(toReturn == null)
165                {
166                   java.net.URI uri = wrapper.getRestrictionValueURI();
167                   if(uri != null)
168                   {
169                      String tempQName = wrapper.getRestrictionValueURI()
170                         .toString();
171                      if(tempQName != null)
172                      {
173                         toReturn = ((OAST)rest.getOWLAbstractSyntaxTree())
174                            .getURIForQName(tempQName);
175                      }
176                   }
177                }
178             }
179             break;
180          default:
181             break;
182       } // switch
183 
184       return toReturn;
185    }
186 
187    /***
188     * Convenience method to request the value of an attribute in the RDF
189     * namespace. <br />
190     * <br />
191     * Typical usage: oastGetRDF(oast, node, "ID"); <br />
192     * Returns value of <code>rdf:ID</code> on node <code>node</code> in oast
193     * <code>iOast</code>
194     * 
195     * @param iOast the oast
196     * @param node the node
197     * @param sRdf the desired attribute in the RDF namespace
198     * @return the attribute value
199     */
200    public String oastGetRDF(IOWLAbstractSyntaxTree iOast, TagNode node,
201       String sRdf)
202    {
203       OAST oast = (OAST)iOast;
204       String toReturn = node.getName();
205       AttributeNode attr = null;
206       String qName = oast.getQNameForURI(OASTNode.S_RDF_URI + "#" + sRdf);
207       attr = node.getAttribute(qName);
208       if(attr != null)
209       {
210          toReturn = attr.getValue();
211       }
212       return toReturn;
213    }
214 
215    /***
216     * Retrieves all the rdf:Description tags relating to a URI.
217     * @param aboutURI the URI of a class or resource
218     * @param oast the OAST in which to search
219     * @return a List of rdf:Description nodes with the value of the 'about'
220     *         attribute matching <code>aboutURI</code>
221     */
222    public List getDescriptions(String aboutURI, IOWLAbstractSyntaxTree oast)
223    {
224       List toReturn = new ArrayList();
225       String aboutQName = "rdf:about";
226       OASTNode[] descriptions = oast.getRoot().getNodesOfType(
227          OASTNode.RDF_DESCRIPTION);
228       for(int i = 0; i < descriptions.length; i++)
229       {
230          Description desc = (Description)descriptions[i];
231          AttributeNode attr = desc.getAttribute(aboutQName);
232          if(attr != null)
233          {
234             if(aboutURI.equals(attr.getValue()))
235             {
236                toReturn.add(desc);
237             }
238          }
239       }
240 
241       return toReturn;
242    }
243 
244    /***
245     * Gathers all the available instances in the set of known namespaces (i.e.
246     * all of the instances defined in documents which can be accessed of the
247     * group including those documents that are given namespaces, and those that
248     * are specified in owl:import statements).
249     * 
250     * 
251     * @return a List of java.net.URIs representing individuals
252     */
253    public List getAllInstances()
254    {
255       List toReturn = new ArrayList();
256       OntModel model = ModelFactory.createOntologyModel(
257          OntModelSpec.OWL_DL_MEM_TRANS_INF, getModel());
258 
259       //      OntModel model = getModel();
260       //      HashSet results = new HashSet();
261       //      QueryResults qr = Query.exec("SELECT ?individual WHERE (?individual
262       // <rdf:type> ?classType)", model);
263       //      while(qr.hasNext())
264       //      {
265       //         Resource r = (Resource) ((ResultBinding) qr.next()).get("individual");
266       //         if(!r.isAnon())
267       //         {
268       //            try
269       //            {
270       //               results.add(new java.net.URI(r.getURI()));
271       //            }
272       //            catch (URISyntaxException e1)
273       //            {
274       //               e1.printStackTrace();
275       //            }
276       //         }
277       //      }
278       //      
279       //      toReturn.addAll(results);
280 
281       ExtendedIterator ei = model.listIndividuals();
282       try
283       {
284          while (ei.hasNext())
285          {
286             Individual individual = (Individual)ei.next();
287             if(individual != null)
288             {
289                if(!individual.isAnon())
290                {
291                   try
292                   {
293                      String s = individual.getURI();
294                      java.net.URI tempURI = null;
295                      if(s != null)
296                      {
297                         tempURI = new java.net.URI(s);
298                         if(tempURI != null)
299                         {
300                            toReturn.add(tempURI);
301                         }
302                      }
303                   }
304                   catch (URISyntaxException e)
305                   {
306                      e.printStackTrace();
307                   }
308                }
309             }
310          }
311       }
312       catch (Exception e)
313       {
314          e.printStackTrace();
315       }
316       finally
317       {
318          ei.close();
319          if(model.getDeductionsModel() != null)
320          {
321             model.getDeductionsModel().close();
322          }
323       }
324 
325       return toReturn;
326    }
327 
328    /***
329     * Returns URIs (in String form) of all the available properties in known
330     * namespaces (i.e. all of the instances defined in documents which can be
331     * accessed of the group including those documents that are given namespaces,
332     * and those that are specified in owl:import statements).
333     * 
334     * @return a List of Strings representing all relevant property URIs
335     */
336    public List getAllProperties()
337    {
338       HashSet properties = new HashSet();
339       Property property = null;
340       OASTNode node = null;
341       OntModel model = getModel();
342 
343       QueryResults qr = Query.exec(
344          "SELECT ?property WHERE (?property <rdf:type> <rdf:Property>)", model);
345       while (qr.hasNext())
346       {
347          Resource temp = (Resource)((ResultBinding)qr.next()).get("property");
348          if(temp.canAs(Property.class))
349          {
350             property = (Property)temp.as(Property.class);
351             if(property.getURI().indexOf("urn:x-hp-jena") == -1)
352             {
353                properties.add(property.getURI());
354             }
355          }
356       }
357 
358       ExtendedIterator ei = model.listObjectProperties().andThen(
359          model.listDatatypeProperties());
360       while (ei.hasNext())
361       {
362          OntProperty ontProperty = (OntProperty)ei.next();
363          if(ontProperty.getURI() != null)
364          {
365             if(ontProperty.getURI().indexOf("urn:x-hp-jena") == -1)
366             {
367                properties.add(ontProperty.getURI());
368             }
369          }
370       }
371       ei.close();
372 
373       List toReturn = new ArrayList(properties);
374       return toReturn;
375    }
376 
377    /***
378     * This method sets the Jena model to be used by this inspector, and notifies
379     * any waiting threads that a value has been set.
380     * 
381     * @param model the Jena model this inspector will use
382     */
383    public synchronized void setModel(OntModel model)
384    {
385       _jenaModel = model;
386       notifyAll();
387    }
388 
389    /***
390     * Returns the Jena model used by this inspector. This method is synchronized
391     * and will not return until it has a non-null value for the model. If the
392     * model has not yet been set, this method will cause the invoking thread to
393     * wait and yield until it is set.
394     * 
395     * @return the Jena model used by this inspector
396     */
397    public synchronized OntModel getModel()
398    {
399       while (_jenaModel == null)
400       {
401          try
402          {
403             wait(200);
404             Thread.yield();
405          }
406          catch (InterruptedException e)
407          {
408             e.printStackTrace();
409          }
410       }
411       return _jenaModel;
412    }
413 
414    /***
415     * Returns a QueryJob to retrieve the restrictions on a class from an OAST.
416     * @param sUri The URI of the class
417     * @param oast The OAST
418     * @see QueryJob 
419     * @see #getRestrictions(String, IOWLAbstractSyntaxTree)
420     * @return a QueryJob
421     */
422    public QueryJob getRestrictionsAsQueryJob(final String sUri,
423       final IOWLAbstractSyntaxTree oast)
424    {
425       QueryJob toReturn = new QueryJob()
426       {
427          protected Object run()
428          {
429             return getRestrictions(sUri, oast);
430          }
431       };
432 
433       return toReturn;
434    }
435 
436    /***
437     * Retrieves the restrictions on a class from an OWL abstract syntax tree.
438     * @param sUri the URI of a class
439     * @param oast all of the restrictions of which the class identified by URI
440     *        is a subclass
441     * @return a List of OAST Restriction objects which represent the
442     *         restrictions associated w/ this URI
443     */
444    public List getRestrictions(String sUri, IOWLAbstractSyntaxTree oast)
445    {
446       List toReturn = new ArrayList();
447       OntModel model = getModel();
448       OntClass parentClass = model.getOntClass(sUri);
449       int count = 0;
450       long time = System.currentTimeMillis();
451       try
452       {
453          if(parentClass != null)
454          {
455             ExtendedIterator ei = parentClass.listSuperClasses(false);
456             //         ExtendedIterator ei = parentClass.listSuperClasses(true);
457             while (ei.hasNext())
458             {
459                count++;
460                OntClass possibleRestriction = (OntClass)ei.next();
461                OASTNode node = null;
462                if(possibleRestriction.isRestriction())
463                {
464                   node = oast.getNode(possibleRestriction);
465                   if(node != null)
466                   {
467                      toReturn.add((Restriction)node);
468                   }
469                   else
470                   {
471                      toReturn.add(possibleRestriction);
472                   }
473                }
474             }
475             ei.close();
476          }
477       }
478       catch (Exception e)
479       {
480          OWLCore
481             .trace(
482                EditorPlugin.getID(),
483                "RestrictionEditorInspector2.getRestrictions(String, OAST): Unexpected exception caught: '"
484                   + e + "'", false);
485       }
486       time = System.currentTimeMillis() - time;
487       OWLCore
488          .trace(
489             EditorPlugin.getID(),
490             "RestrictionEditorInspector2.getRestrictions(String, OAST): went through loop '"
491                + count
492                + "' times in '"
493                + (time / ((double)1000))
494                + "' seconds...", false);
495 
496       return toReturn;
497    }
498 
499    /***
500     * Returns a List of the URIs (as java.net.URI) of all of the Classes in all
501     * of the namespaces of this document. This list will include Classes defined
502     * in the language, e.g. owl:Thing, etc....
503     * 
504     * @return a List of the URIs of all of the classes available to this
505     *         document
506     */
507    public List getAllClasses()
508    {
509       ArrayList classes = null;
510       HashSet classSet = new HashSet();
511       OntClass klass = null;
512       OASTNode node = null;
513       OntModel model = getModel();
514       String uriString = null;
515       Resource r = null;
516       QueryResults qr = Query.exec(
517          "SELECT ?class WHERE (?class <rdf:type> <rdfs:Class>)", model);
518       while (qr.hasNext())
519       {
520          r = (Resource)((ResultBinding)qr.next()).get("class");
521          if(r.canAs(OntClass.class))
522          {
523             klass = (OntClass)r.as(OntClass.class);
524 
525             if(!(klass.isEnumeratedClass() || klass.isIntersectionClass()
526                || klass.isUnionClass() || klass.isRestriction() || klass
527                .isComplementClass()))
528             {
529                uriString = klass.getURI();
530             }
531          }
532          else
533          {
534             uriString = r.getURI();
535          }
536          try
537          {
538             uriString = klass.getURI();
539             if(uriString != null)
540             {
541                classSet.add(new java.net.URI(uriString));
542             }
543          }
544          catch (URISyntaxException e)
545          {
546             e.printStackTrace();
547          }
548       }
549 
550       ExtendedIterator ei = model.listNamedClasses();
551       while (ei.hasNext())
552       {
553          uriString = null;
554          klass = (OntClass)ei.next();
555          if(!(klass.isEnumeratedClass() || klass.isIntersectionClass()
556             || klass.isUnionClass() || klass.isRestriction() || klass
557             .isComplementClass()))
558          {
559             uriString = klass.getURI();
560          }
561          try
562          {
563             if(uriString != null)
564             {
565                classSet.add(new java.net.URI(uriString));
566             }
567          }
568          catch (Exception e)
569          {
570             e.printStackTrace();
571          }
572 
573       }
574       ei.close();
575 
576       try
577       {
578          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#string"));
579          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#boolean"));
580          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#decimal"));
581          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#float"));
582          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#double"));
583          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#duration"));
584          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#dateTime"));
585          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#time"));
586          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#date"));
587          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#gYearMonth"));
588          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#gYear"));
589          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#gMonthDay"));
590          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#gDay"));
591          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#gMonth"));
592          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#hexBinary"));
593          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#base64Binary"));
594          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#anyURI"));
595          classSet
596             .add(new java.net.URI(OASTNode.S_XSD_URI + "#normalizedString"));
597          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#token"));
598          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#language"));
599          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#NMTOKEN"));
600          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#Name"));
601          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#NCName"));
602          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#integer"));
603          classSet.add(new java.net.URI(OASTNode.S_XSD_URI
604             + "#nonPositiveInteger"));
605          classSet
606             .add(new java.net.URI(OASTNode.S_XSD_URI + "#negativeInteger"));
607          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#long"));
608          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#int"));
609          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#short"));
610          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#byte"));
611          classSet.add(new java.net.URI(OASTNode.S_XSD_URI
612             + "#nonNegativeInteger"));
613          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#unsignedLong"));
614          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#unsignedInt"));
615          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#unsignedShort"));
616          classSet.add(new java.net.URI(OASTNode.S_XSD_URI + "#unsignedByte"));
617          classSet
618             .add(new java.net.URI(OASTNode.S_XSD_URI + "#positiveInteger"));
619       }
620       catch (Exception e)
621       {
622          //do nothing
623       }
624       classes = new ArrayList(classSet);
625       return classes;
626    }
627 
628    /***
629     * Returns all of the named Classes defined within this OAST's document.
630     * 
631     * @param oast the OAST
632     * @return a List of the URIs (as java.net.URI) of all the named Klass
633     *         objects in this document
634     */
635    public List getKlasses(IOWLAbstractSyntaxTree oast)
636    {
637       List toReturn = new ArrayList();
638       Klass klass = null;
639       String baseURI = oast.getBaseURI();
640       OASTNode[] classes = oast.getRoot().getNodesOfType(OASTNode.OWL_CLASS);
641       String uri = null;
642       AttributeNode aNode = null;
643       for(int i = 0; i < classes.length; i++)
644       {
645          klass = (Klass)classes[i];
646          aNode = klass.getAttribute("rdf:ID");
647          if(aNode != null)
648          {
649             uri = aNode.getValue();
650             if(uri.indexOf("#") == -1)
651             {
652                uri = baseURI + "#" + uri;
653             }
654             try
655             {
656                toReturn.add(new java.net.URI(uri));
657             }
658             catch (URISyntaxException e)
659             {
660                e.printStackTrace();
661             }
662          }
663       }
664 
665       return toReturn;
666    }
667 
668    /***
669     * Returns a QueryJob set to execute the given request w/ the given
670     * parameters.
671     * 
672     * @param oast The OAST to query
673     * @see QueryJob
674     * @see #getClasses(IOWLAbstractSyntaxTree)
675     * @return a QueryJob
676     */
677    public QueryJob getClassesAsQueryJob(final IOWLAbstractSyntaxTree oast)
678    {
679       QueryJob toReturn = new QueryJob()
680       {
681          protected Object run()
682          {
683             return getClasses(oast);
684          }
685       };
686       return toReturn;
687    }
688 
689    /***
690     * Gets all classes with local restrictions (that is, restrictions that are
691     * defined within this OAST's document).
692     * 
693     * @param oast the OAST
694     * @return a List of strings representing the URIs of the classes
695     */
696    public List getClasses(IOWLAbstractSyntaxTree oast)
697    {
698       List localRestrictions = getLocalRestrictions(oast);
699       OntModel model = getModel();
700       List toReturn = null;
701       HashSet classURIs = new HashSet();
702       Iterator i = localRestrictions.iterator();
703       while (i.hasNext())
704       {
705          Restriction restriction = (Restriction)i.next();
706          Resource res = restriction.getAssociatedResource();
707          if(res != null)
708          {
709             if(res.canAs(OntClass.class))
710             {
711                OntClass jenaResource = (OntClass)res.as(OntClass.class);
712                if(jenaResource.isRestriction())
713                {
714                   ExtendedIterator ei = null;
715                   try
716                   {
717                      ei = jenaResource.listSubClasses(false);
718                      while (ei.hasNext())
719                      {
720                         OntClass jenaClass = (OntClass)ei.next();
721                         classURIs.add(jenaClass.getURI());
722                      }
723                   }
724                   catch (Exception e)
725                   {
726                      OWLCore
727                         .trace(
728                            "com.bbn.swede.editor.visualeditor."
729                               + "RestrictionEditorInspector.getClasses(IOWLAbstractSyntaxTree)",
730                            "Mishap! '" + e + "'...", false);
731                   }
732                   finally
733                   {
734                      if(!(ei == null))
735                      {
736                         ei.close();
737                      }
738                   }
739                }
740             }
741          }
742       }
743 
744       toReturn = new ArrayList();
745       toReturn.addAll(classURIs);
746       return toReturn;
747    }
748 
749    /***
750     * Reacts to an change in the document's OAST.
751     * @param event The event describing the change.
752     * @see IOASTChangeListener#oastChanged(OASTEvent)
753     */
754    public void oastChanged(OASTEvent event)
755    {
756       if(_jenaModel != null)
757       {
758          if(_namespaceModelSynchronizer == null)
759          {
760             _namespaceModelSynchronizer = new NamespaceModelSynchronizer();
761          }
762          _namespaceModelSynchronizer.oastChanged(event);
763       }
764    }
765 
766    private final class NamespaceModelSynchronizer implements
767       IOASTChangeListener
768    {
769       private ArrayList _uris;
770 
771       private IOWLAbstractSyntaxTree _nameSpaceModelSynchronizerOast;
772 
773       private final class NamespaceChangedVisitor implements IOASTDeltaVisitor
774       {
775          private HashSet _namespaceDeltas = new HashSet();
776 
777          /***
778           * Retrieves the changed namespaces located by the visitor.
779           * @return A set containing all changed namespaces.
780           */
781          public HashSet getNamespaceDeltas()
782          {
783             return _namespaceDeltas;
784          }
785 
786          public boolean visit(IOASTDelta delta)
787          {
788             boolean shouldKeepGoing = true;
789             OASTNode node = null;
790             if((delta.getType() & (IOASTDelta.CHANGED | IOASTDelta.REMOVED | IOASTDelta.INSERTED)) != 0)
791             {
792                node = delta.getNodeAfter();
793                if(node != null)
794                {
795                   if((node.getNodeType() == OASTNode.NAMESPACE)
796                      || ((node.getNodeType() == OASTNode.RDF_RESOURCE) && ((node
797                         .getParent() != null) && (node.getParent()
798                            .getNodeType() == OASTNode.OWL_IMPORTS))))
799                   {
800                      _namespaceDeltas.add(delta);
801                      shouldKeepGoing = false;
802                   }
803                }
804                else
805                {
806                   node = delta.getNodeBefore();
807                   if(node != null)
808                   {
809                      if((node.getNodeType() == OASTNode.NAMESPACE)
810                         || ((node.getNodeType() == OASTNode.RDF_RESOURCE) && ((node
811                            .getParent() != null) && (node.getParent()
812                               .getNodeType() == OASTNode.OWL_IMPORTS))))
813                      {
814                         _namespaceDeltas.add(delta);
815                         shouldKeepGoing = false;
816                      }
817                   }
818                }
819             }
820             return shouldKeepGoing;
821          }
822       }
823 
824       public NamespaceModelSynchronizer()
825       {
826          _uris = new ArrayList();
827          _nameSpaceModelSynchronizerOast = null;
828       }
829 
830       private String yoinkURI(OASTNode node)
831       {
832          String toReturn = null;
833          try
834          {
835             if(node.getNodeType() == OASTNode.NAMESPACE)
836             {
837                toReturn = ((Namespace)node).getValue();
838             }
839             else if(node.getNodeType() == OASTNode.RDF_RESOURCE)
840             {
841                toReturn = ((AttributeNode)node).getValue();
842             }
843          }
844          catch (Exception e)
845          {
846             //do nothing
847          }
848          if((toReturn != null) && (!toReturn.endsWith("#")))
849          {
850             toReturn += "#";
851          }
852          return toReturn;
853       }
854 
855       private int countInstances(Collection c, Object element)
856       {
857          Vector counter = new Vector(c);
858          int toReturn = 0;
859          int lastFound = -1;
860          boolean keepGoing = true;
861          while (keepGoing)
862          {
863             lastFound = counter.indexOf(element, lastFound + 1);
864             if(lastFound < 0)
865             {
866                keepGoing = false;
867             }
868             else
869             {
870                toReturn++;
871             }
872          }
873          return toReturn;
874       }
875 
876       /*
877        * This method is called to initialize everything and then process the
878        * first event. It is called only after the model has initially been
879        * loaded, so all of the statements of any namespaces or imports will
880        * already be in the model. That is, we have the current state of the
881        * OAST, so all the URI references will be synched, but we may still need
882        * to add or remove model statements.
883        * 
884        * @param event the first event
885        */
886       private void load(OASTEvent event)
887       {
888          List nodes = new ArrayList();
889          nodes.addAll(Arrays.asList(_nameSpaceModelSynchronizerOast.getRoot()
890             .getNodesOfType(OASTNode.NAMESPACE)));
891          List imports = new ArrayList();
892          imports.addAll(Arrays.asList(_nameSpaceModelSynchronizerOast.getRoot()
893             .getNodesOfType(OASTNode.OWL_IMPORTS)));
894          String uri = null;
895          Iterator i = null;
896          OASTNode node = null;
897          OASTNode otherNode = null;
898          NamespaceChangedVisitor visitor = new NamespaceChangedVisitor();
899 
900          i = imports.iterator();
901          while (i.hasNext())
902          {
903             node = (OASTNode)i.next();
904             otherNode = ((Imports)node).getAttribute("rdf:resource");
905             if(otherNode != null)
906             {
907                nodes.add(otherNode);
908             }
909          }
910 
911          i = nodes.iterator();
912          while (i.hasNext()) // synch up the collection of URIs w/ the OAST
913                              // (initially)
914          {
915             node = (OASTNode)i.next();
916             uri = yoinkURI(node);
917             _uris.add(uri);
918          }
919 
920          // process the first event - if it's an addition, then we still need to
921          // add the statements
922          // if it's a remove, then we need to
923 
924          event.getDelta().accept(visitor);
925          Iterator deltasIterator = visitor.getNamespaceDeltas().iterator();
926          IOWLDocument doc = null;
927          Model model = null;
928          while (deltasIterator.hasNext())
929          {
930             IOASTDelta delta = (IOASTDelta)deltasIterator.next();
931             if(delta.getType() == IOASTDelta.INSERTED)
932             {
933                uri = yoinkURI(delta.getNodeAfter());
934                doc = _nameSpaceModelSynchronizerOast.getNamespace(uri);
935                if(doc != null)
936                {
937                   model = doc.getDocumentInfo().getModel();
938                   synchronized (_jenaModel)
939                   {
940                      _jenaModel.add(model);
941                   }
942                }
943             }
944             else if(delta.getType() == IOASTDelta.REMOVED)
945             {
946                uri = yoinkURI(delta.getNodeBefore());
947                if(!(countInstances(_uris, uri) > 0))
948                {
949                   doc = _nameSpaceModelSynchronizerOast.getNamespace(uri);
950                   if(doc != null)
951                   {
952                      model = doc.getDocumentInfo().getModel();
953                      synchronized (_jenaModel)
954                      {
955                         _jenaModel.remove(model);
956                      }
957                   }
958                }
959             }
960             else if((delta.getType() & IOASTDelta.CHANGED) != 0)
961             {
962                uri = yoinkURI(delta.getNodeBefore());
963                if(!(countInstances(_uris, uri) > 0))
964                {
965                   doc = _nameSpaceModelSynchronizerOast.getNamespace(uri);
966                   if(doc != null)
967                   {
968                      model = doc.getDocumentInfo().getModel();
969                      synchronized (_jenaModel)
970                      {
971                         _jenaModel.remove(model);
972                      }
973                   }
974                }
975                uri = yoinkURI(delta.getNodeAfter());
976                doc = _nameSpaceModelSynchronizerOast.getNamespace(uri);
977                if(doc != null)
978                {
979                   model = doc.getDocumentInfo().getModel();
980                   synchronized (_jenaModel)
981                   {
982                      _jenaModel.add(model);
983                   }
984                }
985             }
986          }
987       }
988 
989       private void remove(String uri)
990       {
991          if(_uris.contains(uri))
992          {
993             _uris.remove(uri);
994             // only remove the statements from the model if no reference to the
995             // namespace exists...
996             if(!_uris.contains(uri))
997             {
998                IOWLDocument doc = null;
999                Model toRemove = null;
1000                if(_nameSpaceModelSynchronizerOast != null)
1001                {
1002                   doc = _nameSpaceModelSynchronizerOast.getNamespace(uri);
1003                   if(doc != null)
1004                   {
1005                      toRemove = doc.getDocumentInfo().getModel();
1006                      synchronized (_jenaModel)
1007                      {
1008                         _jenaModel.remove(toRemove);
1009                      }
1010                   }
1011                }
1012             }
1013          }
1014       }
1015 
1016       private void add(String uri)
1017       {
1018          IOWLDocument doc = null;
1019          Model toAdd = null;
1020          _uris.add(uri);
1021          if(_nameSpaceModelSynchronizerOast != null)
1022          {
1023             doc = _nameSpaceModelSynchronizerOast.getNamespace(uri);
1024             if(doc != null)
1025             {
1026                toAdd = doc.getDocumentInfo().getModel();
1027                synchronized (_jenaModel)
1028                {
1029                   _jenaModel.add(toAdd);
1030                }
1031             }
1032          }
1033 
1034       }
1035 
1036       public void oastChanged(OASTEvent event)
1037       {
1038          String uri = null;
1039          HashSet namespaceDeltas = new HashSet();
1040          OASTNode node = null;
1041          boolean done = false;
1042          NamespaceChangedVisitor visitor = new NamespaceChangedVisitor();
1043          if(_nameSpaceModelSynchronizerOast == null)
1044          {
1045             DocumentRoot root = (DocumentRoot)event.getDelta().getNodeBefore();
1046             if(root != null)
1047             {
1048                _nameSpaceModelSynchronizerOast = root
1049                   .getOWLAbstractSyntaxTree();
1050             }
1051             else
1052             {
1053                root = (DocumentRoot)event.getDelta().getNodeAfter();
1054                if(root != null)
1055                {
1056                   _nameSpaceModelSynchronizerOast = root
1057                      .getOWLAbstractSyntaxTree();
1058                }
1059             }
1060             if(_nameSpaceModelSynchronizerOast != null)
1061             {
1062                load(event);
1063                done = true;
1064             }
1065          }
1066          if(!done)
1067          {
1068             event.getDelta().accept(visitor);
1069             Iterator deltaIterator = visitor.getNamespaceDeltas().iterator();
1070             while (deltaIterator.hasNext())
1071             {
1072                uri = null;
1073                IOASTDelta delta = (IOASTDelta)deltaIterator.next();
1074                if(delta.getType() == IOASTDelta.REMOVED)
1075                {
1076                   node = delta.getNodeBefore();
1077                   uri = yoinkURI(node);
1078                   remove(uri);
1079                }
1080                else if(delta.getType() == IOASTDelta.INSERTED)
1081                {
1082                   node = delta.getNodeAfter();
1083                   uri = yoinkURI(node);
1084                   add(uri);
1085                }
1086                else if((delta.getType() & IOASTDelta.CHANGED) != 0)
1087                {
1088                   node = delta.getNodeBefore();
1089                   uri = yoinkURI(node);
1090                   remove(uri);
1091                   node = delta.getNodeAfter();
1092                   uri = yoinkURI(node);
1093                   add(uri);
1094                }
1095             }
1096          }
1097       }
1098    }
1099 
1100 }