View Javadoc

1   /*
2    * $Id: OASTNode.java,v 1.61 2005/07/12 19:57:59 jlerner 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   package com.bbn.swede.core.dom;
9   
10  import java.util.ArrayList;
11  import java.util.Arrays;
12  import java.util.HashMap;
13  import java.util.Iterator;
14  import java.util.Map;
15  
16  import org.eclipse.core.resources.IFile;
17  import org.eclipse.jface.text.IRegion;
18  
19  import com.bbn.swede.core.IOWLDocument;
20  import com.bbn.swede.core.resources.SWResourceManager;
21  
22  /***
23   * Common implementation and factory methods for OAST nodes.  This class
24   * includes general utility functions and default implementations of many
25   * node-specific methods with generic handling for language elements.  OASTNode
26   * also provides node creation methods that create the correct node type
27   * given just a tag or attribute QName.
28   * @author jlerner
29   */
30  public abstract class OASTNode
31  {
32     /***
33      * Type constant indicating a document root node.
34      */
35     public static final int DOCUMENT = -1;
36     /***
37      * Type constant indicating an XML namespace node.  This is an attribute
38      * node type.
39      */
40     public static final int NAMESPACE = -2;
41     /***
42      * Type constant indicating an XML base node.  This is an attribute node 
43      * type.
44      */
45     public static final int BASE = -3;
46     /***
47      * Type constant indicating a literal node.  This is a text node type.
48      */
49     public static final int LITERAL = -4;
50     /***
51      * <p>Type constant indicating a generic thing node.
52      * This is a class node type.</p>
53      * 
54      * <p>A tag will be created as a generic given the following conditions:
55      * <ol>
56      *   <li>The tag's qname is not recognized as a language element</li>
57      *   <li>The tag's parent is an rdf:RDF tag or a property node</li>
58      * </ol></p>
59      */
60     public static final int GENERICTHING = -5;
61     /***
62      * <p>Type constant indicating a generic predicate node.  This is a property 
63      * node type.</p>
64      * 
65      * <p>A tag will be created as a generic given the following 
66      * conditions:
67      * <ol>
68      *   <li>The tag's qname is not recognized as a language element</li>
69      *   <li>The tag's parent is a class node</li>
70      * </ol></p>
71      */
72     public static final int GENERICPREDICATE = -6;
73     /***
74      * <p>Type constant indicating a generic attribute node.  This is an attribute
75      * node type.</p>
76      * 
77      * <p>An attribute will be created as a generic if its qname is
78      * unrecognized or is ordinarily considered a class or property element from
79      * one of the language namespaces.</p>
80      */
81     public static final int GENERICATTRIBUTE = -7;
82     /***
83      * <p>Type constant indicating an unparseable node.
84      * This is a text node type.</p>
85      * 
86      * <p>Unparseable nodes represent XML errors in the document.  They are kept
87      * isolated so the rest of the document remains usable and are indicated
88      * by an error marker.</p>
89      */
90     public static final int UNPARSEABLE = -8;
91     /***
92      * Type constant indicating an XML comment node.  This is a text node type.
93      */
94     public static final int COMMENT = -9;
95     /***
96      * <p>Type constant indicating an XML processing instruction node.  
97      * This is a text node type.</p>
98      * 
99      * <p>Processing instructions, along with other XML prolog nodes, are prepended
100     * on all partial parses to ensure that the parser uses the proper encoding
101     * and entity substitutions.</p>
102     */
103    public static final int PROCESSING_INSTRUCTION = -10;
104    /***
105     * <p>Type constant indicating a DOCTYPE node.  This is a text node type.</p>
106     * 
107     * <p>DOCTYPEs, along with other XML prolog nodes, are prepended
108     * on all partial parses to ensure that the parser uses the proper encoding
109     * and entity substitutions.</p>
110     */
111    public static final int DOCTYPE = -11;
112    /***
113     * <p>Type constant indicating an XML version node.
114     * This is a text node type.</p>
115     * 
116     * <p>The XML version tag, along with other XML prolog nodes, is prepended
117     * on all partial parses to ensure that the parser uses the proper encoding
118     * and entity substitutions.</p>
119     */
120    public static final int XML_VERSION = -12;
121 
122    /***
123     * Type constant indicating the start of the RDF node types.  Indices
124     * into the RDF element name array can be obtained by subtracting this
125     * value from any of the <code>RDF_*</code> type constants.
126     * @see #AS_RDF
127     */
128    protected static final int RDF = 0;
129    /***
130     * Type constant indicating an rdf:RDF node.  This is a tag node type.
131     */
132    public static final int RDF_RDF = 0;
133    /***
134     * Type constant indicating an rdf:Description node.
135     * This is a class node type.
136     */
137    public static final int RDF_DESCRIPTION = 1;
138    /***
139     * Type constant indicating an rdf:XMLLiteral node.
140     */
141    public static final int RDF_XMLLITERAL = 2;
142    /***
143     * Type constant indicating an rdf:Property node.
144     * This is a class node type.
145     */
146    public static final int RDF_PROPERTY = 3;
147    /***
148     * Type constant indicating an rdf:Statement node.
149     */
150    public static final int RDF_STATEMENT = 4;
151    /***
152     * Type constant indicating an rdf:Bag node.
153     */
154    public static final int RDF_BAG = 5;
155    /***
156     * Type constant indicating an rdf:Seq node.
157     */
158    public static final int RDF_SEQ = 6;
159    /***
160     * Type constant indicating an rdf:Alt node.
161     */
162    public static final int RDF_ALT = 7;
163    /***
164     * Type constant indicating an rdf:List node.
165     * This is a class node type.
166     */
167    public static final int RDF_LIST = 8;
168    /***
169     * Type constant indicating an rdf:type node.
170     * This is a property node type.
171     */
172    public static final int RDF_TYPE = 9;
173    /***
174     * Type constant indicating an rdf:first node.
175     * This is a property node type.
176     */
177    public static final int RDF_FIRST = 10;
178    /***
179     * Type constant indicating an rdf:rest node.
180     * This is a property node type.
181     */
182    public static final int RDF_REST = 11;
183    /***
184     * Type constant indicating an rdf:value node.
185     */
186    public static final int RDF_VALUE = 12;
187    /***
188     * Type constant indicating an rdf:subject node.
189     */
190    public static final int RDF_SUBJECT = 13;
191    /***
192     * Type constant indicating an rdf:predicate node.
193     */
194    public static final int RDF_PREDICATE = 14;
195    /***
196     * Type constant indicating an rdf:object node.
197     */
198    public static final int RDF_OBJECT = 15;
199    /***
200     * Type constant indicating an rdf:ID node.
201     * This is an attribute node type.
202     */
203    public static final int RDF_ID = 16;
204    /***
205     * Type constant indicating an rdf:about node.
206     * This is an attribute node type.
207     */
208    public static final int RDF_ABOUT = 17;
209    /***
210     * Type constant indicating an rdf:resource node.
211     * This is an attribute node type.
212     */
213    public static final int RDF_RESOURCE = 18;
214    /***
215     * Type constant indicating an rdf:datatype node.
216     * This is an attribute node type.
217     */
218    public static final int RDF_DATATYPE = 19;
219    /***
220     * Type constant indicating an rdf:nodeID node.
221     * This is an attribute node type.
222     */
223    public static final int RDF_NODEID = 20;
224    /***
225     * Type constant indicating an rdf:parseType node.
226     * This is an attribute node type.
227     */
228    public static final int RDF_PARSETYPE = 21;
229    /***
230     * Array of element names for items in the RDF namespace.
231     */
232    public static final String[] AS_RDF =
233    {
234       "RDF",
235       "Description",
236       "XMLLiteral",
237       "Property",
238       "Statement",
239       "Bag",
240       "Seq",
241       "Alt",
242       "List",
243       "type",
244       "first",
245       "rest",
246       "value",
247       "subject",
248       "predicate",
249       "object",
250       "ID",
251       "about",
252       "resource",
253       "datatype",
254       "nodeID",
255       "parseType",
256    };
257 
258    /***
259     * Type constant indicating the start of the RDFS node types.  Indices
260     * into the RDFS element name array can be obtained by subtracting this
261     * value from any of the <code>RDFS_*</code> type constants.
262     * @see #AS_RDFS
263     */
264    public static final int RDFS = 25;
265    /***
266     * Type constant indicating an rdfs:comment node.
267     * This is a property node type.
268     */
269    public static final int RDFS_COMMENT = 25;
270    /***
271     * Type constant indicating an rdfs:label node.
272     * This is a property node type.
273     */
274    public static final int RDFS_LABEL = 26;
275    /***
276     * Type constant indicating an rdfs:subClassOf node.
277     * This is a property node type.
278     */
279    public static final int RDFS_SUBCLASSOF = 27;
280    /***
281     * Type constant indicating an rdfs:Resource node.
282     */
283    public static final int RDFS_RESOURCE = 28;
284    /***
285     * Type constant indicating an rdfs:Literal node.
286     */
287    public static final int RDFS_LITERAL = 29;
288    /***
289     * Type constant indicating an rdfs:Class node.
290     * This is a class node type.
291     */
292    public static final int RDFS_CLASS = 30;
293    /***
294     * Type constant indicating an rdfs:Datatype node.
295     */
296    public static final int RDFS_DATATYPE = 31;
297    /***
298     * Type constant indicating an rdfs:Container node.
299     */
300    public static final int RDFS_CONTAINER = 32;
301    /***
302     * Type constant indicating an rdfs:ContainerMembershipProperty node.
303     */
304    public static final int RDFS_CONTAINERMEMBERSHIPPROPERTY = 33;
305    /***
306     * Type constant indicating an rdfs:subPropertyOf node.
307     * This is a property node type.
308     */
309    public static final int RDFS_SUBPROPERTYOF = 34;
310    /***
311     * Type constant indicating an rdfs:domain node.
312     * This is a property node type.
313     */
314    public static final int RDFS_DOMAIN = 35;
315    /***
316     * Type constant indicating an rdfs:domain node.
317     * This is a property node type.
318     */
319    public static final int RDFS_RANGE = 36;
320    /***
321     * Type constant indicating an rdfs:member node.
322     */
323    public static final int RDFS_MEMBER = 37;
324    /***
325     * Type constant indicating an rdfs:seeAlso node.
326     * This is a property node type.
327     */
328    public static final int RDFS_SEEALSO = 38;
329    /***
330     * Type constant indicating an rdfs:isDefinedBy node.
331     */
332    public static final int RDFS_ISDEFINEDBY = 39;
333    /***
334     * Array of element names for items in the RDFS namespace.
335     */
336    public static final String[] AS_RDFS =
337    {
338       "comment",
339       "label",
340       "subClassOf",
341       "Resource",
342       "Literal",
343       "Class",
344       "Datatype",
345       "Container",
346       "ContainerMembershipProperty",
347       "subPropertyOf",
348       "domain",
349       "range",
350       "member",
351       "seeAlso",
352       "isDefinedBy",
353    };
354 
355    /***
356     * Type constant indicating the start of the OWL node types.  Indices
357     * into the RDFS element name array can be obtained by subtracting this
358     * value from any of the <code>OWL_*</code> type constants.
359     * @see #AS_OWL
360     */
361    public static final int OWL = 50;
362    /***
363     * Type constant indicating an owl:Class node.
364     * This is a class node type.
365     */
366    public static final int OWL_CLASS = 50;
367    /***
368     * Type constant indicating an owl:DatatypeProperty node.
369     * This is a class node type.
370     */
371    public static final int OWL_DATATYPEPROPERTY = 51;
372    /***
373     * Type constant indicating an owl:ObjectProperty node.
374     * This is a class node type.
375     */
376    public static final int OWL_OBJECTPROPERTY = 52;
377    /***
378     * Type constant indicating an owl:Restriction node.
379     * This is a class node type.
380     */
381    public static final int OWL_RESTRICTION = 53;
382    /***
383     * Type constant indicating an owl:onProperty node.
384     * This is a property node type.
385     */
386    public static final int OWL_ONPROPERTY = 54;
387    /***
388     * Type constant indicating an owl:Ontology node.
389     * This is a class node type.
390     */
391    public static final int OWL_ONTOLOGY = 55;
392    /***
393     * Type constant indicating an owl:versionInfo node.
394     * This is a property node type.
395     */
396    public static final int OWL_VERSIONINFO = 56;
397    /***
398     * Type constant indicating an owl:imports node.
399     * This is a property node type.
400     */
401    public static final int OWL_IMPORTS = 57;
402    /***
403     * Type constant indicating an owl:AllDifferent node.
404     * This is a class node type.
405     */
406    public static final int OWL_ALLDIFFERENT = 58;
407    /***
408     * Type constant indicating an owl:AnnotationProperty node.
409     * This is a class node type.
410     */
411    public static final int OWL_ANNOTATIONPROPERTY = 59;
412    /***
413     * Type constant indicating an owl:DataRange node.
414     * This is a class node type.
415     */
416    public static final int OWL_DATARANGE = 60;
417    /***
418     * Type constant indicating an owl:DeprecatedClass node.
419     * This is a class node type.
420     */
421    public static final int OWL_DEPRECATEDCLASS = 61;
422    /***
423     * Type constant indicating an owl:DeprecatedProperty node.
424     * This is a class node type.
425     */
426    public static final int OWL_DEPRECATEDPROPERTY = 62;
427    /***
428     * Type constant indicating an owl:FunctionalProperty node.
429     * This is a class node type.
430     */
431    public static final int OWL_FUNCTIONALPROPERTY = 63;
432    /***
433     * Type constant indicating an owl:InverseFunctionalProperty node.
434     * This is a class node type.
435     */
436    public static final int OWL_INVERSEFUNCTIONALPROPERTY = 64;
437    /***
438     * Type constant indicating an owl:Nothing node.
439     */
440    public static final int OWL_NOTHING = 65;
441    /***
442     * Type constant indicating an owl:OntologyProperty node.
443     * This is a class node type.
444     */
445    public static final int OWL_ONTOLOGYPROPERTY = 66;
446    /***
447     * Type constant indicating an owl:SymmetricProperty node.
448     * This is a class node type.
449     */
450    public static final int OWL_SYMMETRICPROPERTY = 67;
451    /***
452     * Type constant indicating an owl:Thing node.
453     * This is a class node type.
454     */
455    public static final int OWL_THING = 68;
456    /***
457     * Type constant indicating an owl:TransitiveProperty node.
458     * This is a class node type.
459     */
460    public static final int OWL_TRANSITIVEPROPERTY = 69;
461    /***
462     * Type constant indicating an owl:allValuesFrom node.
463     * This is a property node type.
464     */
465    public static final int OWL_ALLVALUESFROM = 70;
466    /***
467     * Type constant indicating an owl:backwardCompatibleWith node.
468     * This is a property node type.
469     */
470    public static final int OWL_BACKWARDCOMPATIBLEWITH = 71;
471    /***
472     * Type constant indicating an owl:cardinality node.
473     * This is a property node type.
474     */
475    public static final int OWL_CARDINALITY = 72;
476    /***
477     * Type constant indicating an owl:complimentOf node.
478     * This is a property node type.
479     */
480    public static final int OWL_COMPLEMENTOF = 73;
481    /***
482     * Type constant indicating an owl:differentFrom node.
483     * This is a property node type.
484     */
485    public static final int OWL_DIFFERENTFROM = 74;
486    /***
487     * Type constant indicating an owl:distinctMembers node.
488     * This is a property node type.
489     */
490    public static final int OWL_DISTINCTMEMBERS = 75;
491    /***
492     * Type constant indicating an owl:equivalentClass node.
493     * This is a property node type.
494     */
495    public static final int OWL_EQUIVALENTCLASS = 76;
496    /***
497     * Type constant indicating an owl:equivalentProperty node.
498     * This is a property node type.
499     */
500    public static final int OWL_EQUIVALENTPROPERTY = 77;
501    /***
502     * Type constant indicating an owl:hasValue node.
503     * This is a property node type.
504     */
505    public static final int OWL_HASVALUE = 78;
506    /***
507     * Type constant indicating an owl:incompatibleWith node.
508     * This is a property node type.
509     */
510    public static final int OWL_INCOMPATIBLEWITH = 79;
511    /***
512     * Type constant indicating an owl:intersectionOf node.
513     * This is a property node type.
514     */
515    public static final int OWL_INTERSECTIONOF = 80;
516    /***
517     * Type constant indicating an owl:inverseOf node.
518     * This is a property node type.
519     */
520    public static final int OWL_INVERSEOF = 81;
521    /***
522     * Type constant indicating an owl:maxCardinality node.
523     * This is a property node type.
524     */
525    public static final int OWL_MAXCARDINALITY = 82;
526    /***
527     * Type constant indicating an owl:minCardinality node.
528     * This is a property node type.
529     */
530    public static final int OWL_MINCARDINALITY = 83;
531    /***
532     * Type constant indicating an owl:oneOf node.
533     * This is a property node type.
534     */
535    public static final int OWL_ONEOF = 84;
536    /***
537     * Type constant indicating an owl:priorVersion node.
538     * This is a property node type.
539     */
540    public static final int OWL_PRIORVERSION = 85;
541    /***
542     * Type constant indicating an owl:sameAs node.
543     * This is a property node type.
544     */
545    public static final int OWL_SAMEAS = 86;
546    /***
547     * Type constant indicating an owl:someValuesFrom node.
548     * This is a property node type.
549     */
550    public static final int OWL_SOMEVALUESFROM = 87;
551    /***
552     * Type constant indicating an owl:unionOf node.
553     * This is a property node type.
554     */
555    public static final int OWL_UNIONOF = 88;
556    /***
557     * Type constant indicating an owl:disjointWith node.
558     * This is a property node type.
559     */
560    public static final int OWL_DISJOINTWITH = 89;
561    /***
562     * Array of element names for items in the OWL namespace.
563     */
564    public static final String[] AS_OWL =
565    {
566       "Class",
567       "DatatypeProperty",
568       "ObjectProperty",
569       "Restriction",
570       "onProperty",
571       "Ontology",
572       "versionInfo",
573       "imports",
574       "AllDifferent",
575       "AnnotationProperty",
576       "DataRange",
577       "DeprecatedClass",
578       "DeprecatedProperty",
579       "FunctionalProperty",
580       "InverseFunctionalProperty",
581       "Nothing",
582       "OntologyProperty",
583       "SymmetricProperty",
584       "Thing",
585       "TransitiveProperty",
586       "allValuesFrom",
587       "backwardCompatibleWith",
588       "cardinality",
589       "complementOf",
590       "differentFrom",
591       "distinctMembers",
592       "equivalentClass",
593       "equivalentProperty",
594       "hasValue",
595       "incompatibleWith",
596       "intersectionOf",
597       "inverseOf",
598       "maxCardinality",
599       "minCardinality",
600       "oneOf",
601       "priorVersion",
602       "sameAs",
603       "someValuesFrom",
604       "unionOf",
605       "disjointWith",
606    };
607    
608    /***
609     * The URI of the XML schema.  This document contains definitions for the
610     * XSD datatypes.
611     */
612    public static final String S_XSD_URI = "http://www.w3.org/2001/XMLSchema";
613    /***
614     * The URI of the OWL language specification.
615     */
616    public static final String S_OWL_URI = "http://www.w3.org/2002/07/owl";
617    /***
618     * The URI of the RDFS language specification.
619     */
620    public static final String S_RDFS_URI =
621       "http://www.w3.org/2000/01/rdf-schema";
622    /***
623     * The URI of the RDF language specification.
624     */
625    public static final String S_RDF_URI =
626       "http://www.w3.org/1999/02/22-rdf-syntax-ns";
627    
628    private static final String S_READ_ONLY_EXCEPTION = 
629       " is read-only and its OAST cannot be modified";
630 
631    /***
632     * The character offset of this node within the document.
633     */
634    protected int _iOffset;
635    /***
636     * The length in charactrs of this node within the document.
637     */
638    protected int _iLength;
639    private ArrayList _alChildren;
640    /***
641     * The parent of this node.  Apart from the document root, all nodes attached
642     * to an OAST must have a parent.  Any node may act as the root of a detached
643     * node tree, indicated by a <code>null</code> parent.
644     */
645    protected OASTNode _nodeParent;
646    /***
647     * The tree to which this node is attached.
648     */
649    protected IOWLAbstractSyntaxTree _tree;
650 
651    /***
652     * Returns the namespace abbreviation for the node.  This implementation
653     * returns one of "owl", "rdfs", or "rdf" for language nodes or null for
654     * anything else.  Subclasses that represent non-language tags or attributes
655     * should override this method to return a non-null namespace.
656     * @return The namespace abbreviation for the node, or <code>null</code> if 
657     *         it is not a language node
658     */
659    public String getNamespace()
660    {
661       int iType = getNodeType();
662       if (iType >= OWL)
663       {
664          return "owl";
665       }
666       if (iType >= RDFS)
667       {
668          return "rdfs";
669       }
670       if (iType >= RDF)
671       {
672          return "rdf";
673       }
674       return null;
675    }
676 
677    /***
678     * Returns the node's local name.  This implementation returns local names
679     * for language nodes, and null for everything else.  Subclasses that
680     * represent non-language tags and attributes should override this method to
681     * return a non-null local name.
682     * @return The local name of the node, or <code>null</code> if it is not a 
683     *         language node
684     */
685    public String getName()
686    {
687       int iType = getNodeType();
688       if (iType >= OWL)
689       {
690          return (AS_OWL[iType - OWL]);
691       }
692       if (iType >= RDFS)
693       {
694          return (AS_RDFS[iType - RDFS]);
695       }
696       if (iType >= RDF)
697       {
698          return (AS_RDF[iType - RDF]);
699       }
700       return null;
701    }
702 
703    /***
704     * Returns the node's qualified name.  This implementation returns qnames for
705     * language nodes, and null for everything else.  Subclasses that represent
706     * non-language tags and attributes should override this method to return a
707     * non-null qname.
708     * @return The qualified name of the node, or <code>null</code> if it is not
709     *         a lanuage node
710     */
711    public String getQName()
712    {
713       int iType = getNodeType();
714       if (iType >= OWL)
715       {
716          return ("owl:" + AS_OWL[iType - OWL]);
717       }
718       if (iType >= RDFS)
719       {
720          return ("rdfs:" + AS_RDFS[iType - RDFS]);
721       }
722       if (iType >= RDF)
723       {
724          return ("rdf:" + AS_RDF[iType - RDF]);
725       }
726       return null;
727    }
728 
729    /***
730     * Returns the full URI of the node.  This implementation returns URIs only
731     * for language nodes, and null for everything else.  Subclasses that
732     * represent non-language tags and attributes should override this method to
733     * return a non-null URI.
734     * @return The node's URI, or <code>null</code> if it is not a language node.
735     */
736    public String getUri()
737    {
738       int iType = getNodeType();
739       if (iType >= OWL)
740       {
741          return "http://www.w3.org/2002/07/owl#" + AS_OWL[iType - OWL];
742       }
743       if (iType >= RDFS)
744       {
745          return "http://www.w3.org/2000/01/rdf-schema#" + AS_RDFS[iType - RDFS];
746       }
747       if (iType >= RDF)
748       {
749          return "http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
750                 + AS_RDF[iType - RDF];
751       }
752       return null;
753    }
754 
755    /***
756     * Returns the qualified name associated with a particular node type.  Node
757     * types are defined as public static fields in OASTNode. 
758     * @param iNodeType Node type whose qname will be returned
759     * @return A qname for node types of the form RDF_*, RDFS_*, and OWL_*,
760     *         otherwise <code>null</code>.
761     */
762    public static String getQName(int iNodeType)
763    {
764       if (iNodeType >= OWL)
765       {
766          return "owl:" + AS_OWL[iNodeType - OWL];
767       }
768       if (iNodeType >= RDFS)
769       {
770          return "rdfs:" + AS_RDFS[iNodeType - RDFS];
771       }
772       if (iNodeType >= RDF)
773       {
774          return "rdf:" + AS_RDF[iNodeType - RDF];
775       }
776       return null;
777    }
778 
779    /***
780     * Checks if a qualified name is correct for a specific node type.  Node
781     * types are defined as public static fields in OASTNode.
782     * @param qName The qualified name to check
783     * @param iNodeType The node type to check against
784     * @return true if the node type matches the qname, false if not
785     */
786    public static boolean match(String qName, int iNodeType)
787    {
788       if (iNodeType < 0)
789       {
790          return true;
791       }
792       int iPos = qName.indexOf(':');
793       if (iPos < 0)
794       {
795          return false;
796       }
797       String sNS = qName.substring(0, iPos);
798       String sFragment = qName.substring(iPos + 1);
799       if (sNS.equals("owl"))
800       {
801          int index = iNodeType - OWL;
802          if (index < 0 || index >= AS_OWL.length)
803          {
804             return false;
805          }
806          return sFragment.equals(AS_OWL[iNodeType - OWL]);
807       }
808       else if (sNS.equals("rdfs"))
809       {
810          int index = iNodeType - RDFS;
811          if (index < 0 || index >= AS_RDFS.length)
812          {
813             return false;
814          }
815          return sFragment.equals(AS_RDFS[iNodeType - RDFS]);
816       }
817       else if (sNS.equals("rdf"))
818       {
819          int index = iNodeType - RDF;
820          if (index < 0 || index >= AS_RDF.length)
821          {
822             return false;
823          }
824          return sFragment.equals(AS_RDF[iNodeType - RDF]);
825       }
826       else
827       {
828          return false;
829       }
830    }
831 
832    /***
833     * Constructs a new node with no parent and no children.
834     */
835    public OASTNode()
836    {
837       _alChildren = new ArrayList();
838    }
839 
840    /***
841     * Sets the character offset that marks the beginning of the node.  This
842     * method is only intended for setting node positions before attaching them
843     * to a tree.  No node displacement will be performed as a result of this 
844     * change.
845     * @param iOffset The new begin offset
846     */
847    protected void setOffset(int iOffset)
848    {
849       _iOffset = iOffset;
850    }
851 
852    /***
853     * Sets the length of the node, in characters. This method is only intended 
854     * for setting node sizes before attaching them to a tree.  No node 
855     * displacement will be performed as a result of this change.
856     * @param iLength The new character length
857     */
858    protected void setLength(int iLength)
859    {
860       _iLength = iLength;
861    }
862 
863    /***
864     * Retrieves the character offset that marks the beginning of the node.
865     * @return The current begin offset
866     */
867    public int getOffset()
868    {
869       return _iOffset;
870    }
871 
872    /***
873     * Retrieves the length of the node, in characters.
874     * @return The current character length
875     */
876    public int getLength()
877    {
878       return _iLength;
879    }
880 
881    /***
882     * Returns an array of node types indicating what is allowed as a child
883     * of the node.  Node types are defined as public static fields in OASTNode.
884     * This method is not currently used, but will eventually become important 
885     * for real-time syntax checking.
886     * @return An array of allowed node types.  
887     */
888    protected abstract int[] allowedChildren();
889    
890    /***
891     * Returns an integer indicating a node's type.  Subclasses must override
892     * this method to return one of the node types defined as public static
893     * fields in OASTNode.  There is a distinct node type for each langauge 
894     * element as well as several additional types for generics and XML 
895     * constructs.
896     * @return The type of this node
897     */
898    public abstract int getNodeType();
899 
900    /***
901     * Returns the node's parent.  Every node in an OAST must have a parent,
902     * except for the document root node.
903     * @return The parent node, or <code>null</code> if this node is the
904     *         document root.
905     */
906    public OASTNode getParent()
907    {
908       return _nodeParent;
909    }
910    
911    /***
912     * Adds a node to the end of this node's child list.  No attention is paid
913     * to the new child's offset or the offsets of the existing children.  This
914     * node will also be set as the parent of the appended child node.  
915     * This method is only intended for use when building a node structure in 
916     * memory while parsing a document.
917     * @param node The new child node to append
918     */
919    protected void appendChild(OASTNode node)
920    {
921       _alChildren.add(node);
922       node._nodeParent = this;
923    }
924    
925    /***
926     * Returns an object that can be used to synchronize editing operations
927     * on the node.  If the node is attached to an OWL abstract syntax tree,
928     * the tree is returned.  Otherwise, the root node of this node's detached
929     * subtree is used.
930     * @return An object that can be used to synchronize editing operations
931     */
932    protected Object getLockObject()
933    {
934       if (_tree != null)
935       {
936          return _tree;
937       }
938       
939       OASTNode node = this;
940       while (node.getParent() != null)
941       {
942          node = node.getParent();
943       }
944       return node;
945    }
946 
947    /***
948     * Inserts a node at the correct position in this node's child list.  
949     * Existing children should be displaced to make room before the new node is
950     * inserted, as addChild will place it in the correct position in the list
951     * but will not displace existing nodes.
952     * @see NodeDisplacementVisitor
953     * @param node The new child node to insert
954     */
955    private void addChild(OASTNode node)
956    {
957       synchronized (getLockObject())
958       {
959          int iPos = 0;
960          for (; iPos < _alChildren.size(); iPos++)
961          {
962             OASTNode child = (OASTNode) _alChildren.get(iPos);
963             if (node.getOffset() <= child.getOffset())
964             {
965                break;
966             }
967          }
968          _alChildren.add(iPos, node);
969       }
970    }
971 
972    /***
973     * Removes a child from this node's list of children.  If the specified node
974     * is not in the child list, nothing happens.  The other children will not
975     * be displaced as a result of the removal; that must be handled externally.
976     * @see NodeDisplacementVisitor
977     * @param node The child node to remove.
978     */
979    private void removeChild(OASTNode node)
980    {
981       synchronized (getLockObject())
982       {
983          _alChildren.remove(node);
984       }
985    }
986 
987    /***
988     * Finds the most specific node that contains a given offset.
989     * @param offset The offset to locate in the subtree rooted at this node
990     * @return The lowest-level node in the tree that contains the specified
991     *         offset
992     */
993    public OASTNode getContainingChild(int offset)
994    {
995       if (offset < getOffset() || offset >= (getOffset() + getLength()))
996       {
997          return null;
998       }
999       OASTNode nodeReturn = null;
1000       Iterator it = _alChildren.iterator();
1001       while (nodeReturn == null && it.hasNext())
1002       {
1003          OASTNode node = (OASTNode) it.next();
1004          nodeReturn = node.getContainingChild(offset);
1005       }
1006       return (nodeReturn == null ? this : nodeReturn);
1007    }
1008 
1009    /***
1010     * Creates a node for a specific qualified name and appends it as a child
1011     * of this node.  This method is able to create language nodes and generic 
1012     * nodes for XML tags
1013     * @param sQName Qaulified name indicating the type of the new child
1014     * @return The new node
1015     */
1016    /*package*/ OASTNode createChild(String sQName)/package-summary/html">class="comment">package*/ OASTNode createChild(String sQName)/package-summary.html">/*package*/ OASTNode createChild(String sQName)/package-summary.html">class="comment">package*/ OASTNode createChild(String sQName)
1017    {
1018       OASTNode node = TagNode.create(sQName, this);
1019       if (node != null)
1020       {
1021          appendChild(node);
1022       }
1023       return node;
1024    }
1025 
1026    /***
1027     * Creates a node for a specified qualified attribute name and attribute
1028     * value and appends it as a child of this node.  This method is able to
1029     * create attribute nodes for language elements, XML namespaces, XML base,
1030     * and generics.  
1031     * @param sQName Qualified name of the attribute
1032     * @param sValue Value of the attribute
1033     * @return The new node
1034     */
1035    /*package*/ AttributeNode createChildAttribute(String sQName, String sValue)/package-summary/html">class="comment">package*/ AttributeNode createChildAttribute(String sQName, String sValue)/package-summary.html">/*package*/ AttributeNode createChildAttribute(String sQName, String sValue)/package-summary.html">class="comment">package*/ AttributeNode createChildAttribute(String sQName, String sValue)
1036    {
1037       AttributeNode att = AttributeNode.create(sQName, sValue);
1038       if (att != null)
1039       {
1040          appendChild(att);
1041       }
1042       return att;
1043    }
1044 
1045    /***
1046     * Compiles a list of all nodes of a particular type in the subtree rooted 
1047     * at this node.  This node will be included in the results, if it matches. 
1048     * @param iNodeType The node type to search for
1049     * @return A list of all nodes in this subtree matching the specified type,
1050     *         or an empty list if there are no matches.
1051     */
1052    public OASTNode[] getNodesOfType(int iNodeType)
1053    {
1054       ArrayList alNodes = new ArrayList();
1055       Iterator it = _alChildren.iterator();
1056       while (it.hasNext())
1057       {
1058          OASTNode node = (OASTNode) it.next();
1059          if (node.getNodeType() == iNodeType)
1060          {
1061             alNodes.add(node);
1062          }
1063          OASTNode[] nodes = node.getNodesOfType(iNodeType);
1064          alNodes.addAll(Arrays.asList(nodes));
1065       }
1066       return (OASTNode[])alNodes.toArray(new OASTNode[0]);
1067    }
1068 
1069    /***
1070     * Compiles a list of all nodes of a particular type in the subtree rooted 
1071     * at this node, up to a specified maximum depth.  This node will be 
1072     * included in the results, if it matches. 
1073     * @param iNodeType The node type to search for
1074     * @param iDepth The number of levels to search.  0 indicates just this node,
1075     *               1 indicates this node and its children, etc...
1076     * @return A list of all nodes in the specified levels of this subtree 
1077     *         matching the specified type, or an empty list if there are no 
1078     *         matches.
1079     */
1080    public OASTNode[] getNodesOfType(int iNodeType, int iDepth)
1081    {
1082       ArrayList alNodes = new ArrayList();
1083       Iterator it = _alChildren.iterator();
1084       iDepth--;
1085       while (it.hasNext())
1086       {
1087          OASTNode node = (OASTNode) it.next();
1088          if (node.getNodeType() == iNodeType)
1089          {
1090             alNodes.add(node);
1091          }
1092          if (iDepth > 0)
1093          {
1094             OASTNode[] nodes = node.getNodesOfType(iNodeType, iDepth);
1095             alNodes.addAll(Arrays.asList(nodes));
1096          }
1097       }
1098       return (OASTNode[])alNodes.toArray(new OASTNode[0]);
1099    }
1100 
1101    /***
1102     * Returns a list of this node's children.
1103     * @return The node's list of children
1104     */
1105    public OASTNode[] getChildren()
1106    {
1107       return (OASTNode[])_alChildren.toArray(new OASTNode[0]);
1108    }
1109 
1110    /***
1111     * Locates the node before a specified entry in this node's child list.
1112     * @param child The child whose previous sibling will be located
1113     * @return The node before the specified one in the child list, or
1114     *         <code>null</code> if either the specified node is the first child
1115     *         of this node or is not a child of it at all.
1116     *        
1117     */
1118    public OASTNode getPreviousChild(OASTNode child)
1119    {
1120       int i;
1121       for (i = 1; i < _alChildren.size(); i++)
1122       {
1123          if (_alChildren.get(i) == child)
1124          {
1125             return (OASTNode)_alChildren.get(i - 1);
1126          }
1127       }
1128       return null;
1129    }
1130 
1131    /***
1132     * Locates the node after a specified entry in this node's child list.
1133     * @param child The child whose next sibling will be located
1134     * @return The node after the specified one in the child list, or
1135     *         <code>null</code> if either the specified node is the last child
1136     *         of this node or is not a child at all.
1137     */
1138    public OASTNode getNextChild(OASTNode child)
1139    {
1140       int i;
1141       for (i = 0; i < _alChildren.size() - 1; i++)
1142       {
1143          if (_alChildren.get(i) == child)
1144          {
1145             return (OASTNode)_alChildren.get(i + 1);
1146          }
1147       }
1148       return null;
1149    }
1150    
1151    /***
1152     * Compiles a list of namespaces in the scope of this node.  In the unlikely
1153     * event of redefined namespace abbreviations, the definition closer to this
1154     * node in the tree will be used.
1155     * @return A java.util.Map containing namespace abbreviations and the
1156     *         associated full URI
1157     */
1158    public Map getNamespaces()
1159    {
1160       Namespace[] namespaces = _nodeParent.collectNamespaces();
1161       Map map = new HashMap(namespaces.length);
1162       for (int i = 0; i < namespaces.length; i++)
1163       {
1164          Namespace ns = namespaces[i];
1165          if (!map.containsKey(ns.getAbbreviation()))
1166          {
1167             map.put(ns.getAbbreviation(), ns.getValue());
1168          }
1169       }
1170       return map;
1171    }
1172 
1173    /***
1174     * Recursive helper method for {@link #getNamespace()}.  This method uses 
1175     * {@link #getParent()} to move up the OAST, gathering Namespace nodes at 
1176     * each level.
1177     * @return A list of Namespace nodes collected from nodes above this one
1178     *         in the tree
1179     */
1180    private Namespace[] collectNamespaces()
1181    {
1182       ArrayList al = new ArrayList();
1183       Iterator it = _alChildren.iterator();
1184       while (it.hasNext())
1185       {
1186          OASTNode node = (OASTNode) it.next();
1187          if (node.getNodeType() == NAMESPACE)
1188          {
1189             Namespace ns = (Namespace) node;
1190             if (ns.getAbbreviation().length() > 0)
1191             {
1192                al.add(ns);
1193             }
1194          }
1195       }
1196       if (_nodeParent != null)
1197       {
1198          Namespace[] namespaces = _nodeParent.collectNamespaces();
1199          al.addAll(Arrays.asList(namespaces));
1200       }
1201       return (Namespace[])al.toArray(new Namespace[0]);
1202    }
1203 
1204    /***
1205     * Locates the default namespace in the scope of this node.
1206     * @return The URI of the default namespace or <code>null</code> if no
1207     *         default namespace is found
1208     */
1209    public String getDefaultNamespace()
1210    {
1211       Namespace ns = _nodeParent.findDefaultNS();
1212       if (ns == null)
1213       {
1214          return null;
1215       }
1216       return ns.getValue();
1217    }
1218 
1219    /***
1220     * Recursive helper method for {@link #getDefaultNamespace()}.  This method 
1221     * uses {@link #getParent()} to move up the tree until it either locates a 
1222     * Namespace node with no abbreviation or runs out of tree.
1223     * @return A Namespace node representing the default namespace or
1224     *         <code>null</code> if no default namespace is found.
1225     */
1226    private Namespace findDefaultNS()
1227    {
1228       Iterator it = _alChildren.iterator();
1229       while (it.hasNext())
1230       {
1231          OASTNode node = (OASTNode) it.next();
1232          if (node.getNodeType() == NAMESPACE)
1233          {
1234             Namespace ns = (Namespace) node;
1235             if (ns.getAbbreviation().length() == 0)
1236             {
1237                return ns;
1238             }
1239          }
1240       }
1241       if (_nodeParent == null)
1242       {
1243          return null;
1244       }
1245       return _nodeParent.findDefaultNS();
1246    }
1247 
1248    /***
1249     * Locates the XML base in the scope of this node.
1250     * @return The URI of the XML base, or <code>null</code> if no XML base is
1251     *         found.
1252     */
1253    public String getXmlBase()
1254    {
1255       Base base = _nodeParent.findXmlBase();
1256       if (base == null)
1257       {
1258          return null;
1259       }
1260       return base.getValue();
1261    }
1262 
1263    /***
1264     * Recursive helper method for {@link #getXmlBase()}.  This method uses 
1265     * {@link #getParent()} to move up the tree until it either locates a Base 
1266     * node or runs out of tree.
1267     * @return A Base node representing the XML base for this node, or 
1268     *         <code>null</code> if no XML base is found. 
1269     */
1270    protected Base findXmlBase()
1271    {
1272       OASTNode[] nodes = getNodesOfType(BASE, 1);
1273       if (nodes.length == 0)
1274       {
1275          if (_nodeParent == null)
1276          {
1277             return null;
1278          }
1279          return _nodeParent.findXmlBase();
1280       }
1281 
1282       Base base = (Base)nodes[0];
1283       return base;
1284    }
1285 
1286    /***
1287     * Returns a string representation of the node.  The default implementation
1288     * just returns the node's qname, but subclasses may override it to supply
1289     * something more appropriate.
1290     * @return A string representation of the node.
1291     */
1292    public String toString()
1293    {
1294       return getQName();
1295    }
1296 
1297    /***
1298     * Calculates the node's depth in the tree.  Note that the document root
1299     * is considered to be at depth 0.
1300     * @return The depth of the node.
1301     */
1302    public int getLevel()
1303    {
1304       if (_nodeParent == null)
1305       {
1306          return 0;
1307       }
1308       return 1 + _nodeParent.getLevel();
1309    }
1310 
1311    /***
1312     * Finds a common ancestor for this node and another one at the lowest
1313     * possible level in the tree.  In the best case, this node contains the
1314     * other node (or vice versa) and is simply returned.  In the worst case, 
1315     * the common ancestor might be the document root.
1316     * @param other The node to find a common ancestor with
1317     * @return The lowest-level node that includes both this node and
1318     *         <code>other</code>.
1319     */
1320    public OASTNode findCommonAncestor(OASTNode other)
1321    {
1322       int iLevelThis = getLevel();
1323       int iLevelOther = other.getLevel();
1324       OASTNode node = this;
1325       while (iLevelThis < iLevelOther)
1326       {
1327          other = other.getParent();
1328          iLevelOther--;
1329       }
1330       while (iLevelOther < iLevelThis)
1331       {
1332          node = node.getParent();
1333          iLevelThis--;
1334       }
1335       while (node != other)
1336       {
1337          node = node.getParent();
1338          other = other.getParent();
1339       }
1340       return node;
1341    }
1342 
1343    /***
1344     * Performs a preorder traversal starting with this node.  Traversals
1345     * are synchronized against the containing OAST to ensure that visitors
1346     * do not run concurrently.
1347     * @param visitor The visitor to call at each step of the recursion
1348     */
1349    public final void accept(IOASTNodeVisitor visitor)
1350    {
1351       synchronized (getLockObject())
1352       {
1353          if (!visitor.visit(this))
1354          {
1355             return;
1356          }
1357          for (int i = 0; i < _alChildren.size(); i++)
1358          {
1359             ((OASTNode) _alChildren.get(i)).accept(visitor);
1360          }
1361       }
1362    }
1363 
1364    /***
1365     * Checks if the node starts on or after a specific offset.
1366     * @param offset The offset to compare against
1367     * @return true if this node begins on or after the offset, false otherwise
1368     */
1369    public boolean startsAfter(int offset)
1370    {
1371       return (offset <= getOffset());
1372    }
1373 
1374    /***
1375     * Checks if the node ends before specific offset.
1376     * @param offset The offset to compare against
1377     * @return true if this node ends before on or at the offset, false otherwise
1378     */
1379    public boolean endsBefore(int offset)
1380    {
1381       return (offset >= (getOffset() + getLength()));
1382    }
1383 
1384    /***
1385     * Subclasses must implement this method to provide text representing the
1386     * contents of the node and its children.  This method is only used
1387     * by the editor for inserting an extrnally-constructed node (i.e., as a
1388     * result of a New... wizard) into the text.  The formatting of the
1389     * generated text is thus unimportant, as it will likely be modified by the
1390     * Auto-Indent Strategy and Content Formatter anyway.  
1391     * @return A text approximation of the node and its children
1392     */
1393    public abstract String generateNodeText();
1394    
1395    /***
1396     * Initialization method called when a node is attached to an
1397     * IOWLAbstractSyntaxTree.  Subclasses may override this method to perform 
1398     * additional custom setup, but must call <code>super.init()</code> to 
1399     * execute standard initialization code.
1400     */
1401    protected void init()
1402    {
1403    }
1404    
1405    /***
1406     * Cleanup method called when a node is detached from an 
1407     * IOWLAbstractSyntaxTree.  Subclasses may override this method to perform 
1408     * additional custom cleanup operations, but must call 
1409     * <code>super.cleanup()</code> to execute standard destruction code.
1410     */
1411    protected void cleanup()
1412    {
1413    }
1414 
1415    /***
1416     * Finds the OWL document that this node is from.
1417     * @return The OWL document that contains this node
1418     */
1419    public IOWLDocument getOWLDocument()
1420    {
1421       if (getNodeType() == DOCUMENT)
1422       {
1423          IFile file = ((DocumentRoot) this).getFile();
1424          IOWLDocument doc =
1425             (IOWLDocument) SWResourceManager.getModel().getCorrespondingElement(file);
1426          return doc;
1427       }
1428       if (_nodeParent != null)
1429       {
1430          return _nodeParent.getOWLDocument();
1431       }
1432       return null;
1433    }
1434 
1435    /***
1436     * Retrieves the last attribute child of the node.
1437     * @return The last attribute child, or null if there are no attributes
1438     */
1439    public AttributeNode getLastAttribute()
1440    {
1441       if (_alChildren.size() == 0)
1442       {
1443          //no children
1444          return null;
1445       }
1446       
1447       OASTNode nodePrev = (OASTNode)_alChildren.get(0);
1448       if (!(nodePrev instanceof AttributeNode))
1449       {
1450          //no attributes
1451          return null;
1452       }
1453       for (int i = 1; i < _alChildren.size(); i++)
1454       {
1455          OASTNode node = (OASTNode)_alChildren.get(i);
1456          if (!(node instanceof AttributeNode))
1457          {
1458             break;
1459          }
1460          nodePrev = node;
1461       }
1462       
1463       return (AttributeNode)nodePrev;
1464    }
1465 
1466    /***
1467     * Retrieves the first non-attribute child of the node.
1468     * @return The first non-attribute child, or null if there are no child nodes
1469     *         or all children are attributes
1470     */
1471    public OASTNode getFirstChild()
1472    {
1473       Iterator it = _alChildren.iterator();
1474       while (it.hasNext())
1475       {
1476          OASTNode child = (OASTNode) it.next();
1477          if (!(child instanceof AttributeNode))
1478          {
1479             return child;
1480          }
1481       }
1482       return null;
1483    }
1484    
1485    /***
1486     * <p>Returns a rough partitioning of the node based on the node's tag 
1487     * structure; child nodes are not taken into account.  Partitioning should
1488     * be as follows:</p>
1489     * 
1490     * <ul>
1491     *   <li>1 partition  - singleton tags, textual nodes, document root</li>
1492     *   <li>2 partitions - attributes, adjacent begin/end tags 
1493     *       (i.e. &lt;foo&gt;&lt;/foo&gt;)</li>
1494     *   <li>3 partitions - begin/end tags with whitespace and/or nodes 
1495     *       between them (i.e. &lt;foo&gt;bar&lt;/foo&gt;)</li>
1496     * </ul> 
1497     * @return A rough partitioning of the node.
1498     */
1499    public abstract IRegion[] simplePartitioning();
1500 
1501    /***
1502     * Adjust the node's offset or length to reflect the addition or removal
1503     * of characters in the file.
1504     * @param offset Position in the document where the change occurred.  This
1505     *               node's position will only be changed if some or all of it
1506     *               occurs after this offset.
1507     * @param length Magnitude of the position adjustment.  May be negative.
1508     * @return true if the node was displaced, false if not
1509     */
1510    public boolean displace(int offset, int length)
1511    {
1512       synchronized (getLockObject())
1513       {
1514          return displace(this, offset, length);
1515       }
1516    }
1517    
1518    /***
1519     * Static helper method for node displacement.
1520     * @param node The node to displace
1521     * @param offset Position in the document where the change occurred.  This
1522     *               node's position will only be changed if some or all of it
1523     *               occurs after this offset.
1524     * @param length Magnitude of the position adjustment.  May be negative.
1525     * @return true if the node was displaced, false if not
1526     */
1527    protected static boolean displace(OASTNode node, int offset, int length)
1528    {
1529       if (node.getOffset() >= offset && node.getOffset() + length >= 0)
1530       {
1531          node.setOffset(node.getOffset() + length);
1532          return true;
1533       }
1534       else if (offset < (node.getOffset() + node.getLength()))
1535       {
1536          node.setLength(node.getLength() + length);
1537          return true;
1538       }
1539 
1540       return false;
1541 
1542    }
1543 
1544    /***
1545     * <p>Inserts a child node into this node.  The tree containing this node 
1546     * can optionally be displaced first to make room for it the new child.  The
1547     * child will be inserted at its stored offset, which must fall inside
1548     * of this node.</p>
1549     * 
1550     * <p>If this node is attached to an OWL abstract syntax tree, the new
1551     * child node will be attached to it and an event will be dispatched to all 
1552     * OAST event listeners to alert them to the insertion.</p>
1553     * @param child the new child node to insert
1554     * @param bDisplace <code>true</code> if the tree needs to be displaced
1555     *                  to make room for <code>child</code>, <code>false</code>
1556     *                  if there is already space for it.
1557     * @throws OASTException if this node is attached to a read-only OAST
1558     *                       or the starting offset of the new child does not
1559     *                       fall within this node
1560     */
1561    public void insert(OASTNode child, boolean bDisplace) throws OASTException
1562    {
1563       if (child.getOffset() < _iOffset
1564          || child.getOffset() >= _iOffset + _iLength)
1565       {
1566          throw new OASTException(
1567             child + "'s starting offset does not occur within this node", this);
1568       }
1569       
1570       if (_tree == null)
1571       {
1572          doInsert(child, bDisplace);
1573       }
1574       else
1575       {
1576          if (_tree.isReadOnly())
1577          {
1578             String sName = _tree.getRoot().getOWLDocument().getElementName();
1579             throw new OASTException(sName + S_READ_ONLY_EXCEPTION, _tree);
1580          }
1581          IOASTDelta delta = OASTDelta.createInsertDelta(this, new OASTNode[]{child});
1582          OASTEvent event = new OASTEvent(delta);
1583          child.attach(_tree, bDisplace);
1584          ((OAST)_tree).changed(event);
1585       }
1586    }
1587    
1588    /***
1589     * Helper method for <code>insert()</code> and <code>attach()</code>.
1590     * @param child the new child node to insert
1591     * @param bDisplace <code>true</code> if the tree needs to be displaced
1592     *                  to make room for <code>child</code>, <code>false</code>
1593     *                  if there is already space for it.
1594     */
1595    private void doInsert(OASTNode child, boolean bDisplace)
1596    {
1597       //this should be safe, since if the insert is happening during an
1598       //attach() call, the tree reference will already have been set
1599       synchronized (getLockObject())
1600       {
1601          if (bDisplace)
1602          {
1603             OASTNode root = getRoot();
1604             root.accept(new NodeDisplacementVisitor(child.getOffset(), child.getLength()));
1605          }
1606          child._nodeParent = this;
1607          addChild(child);
1608       }
1609    }
1610    
1611    /***
1612     * <p>Attaches the node to an OWL abstract syntax tree at its stored offset and
1613     * length.  As an optional first step, nodes already in the tree will be 
1614     * displaced to make room for this node.  Next, the appropriate parent/child 
1615     * relationships will be created to tie the node to the tree.  Finally, 
1616     * <code>init()</code> will be called on this node and all of its 
1617     * descendants once the node is fully attached to the OAST.</p>
1618     * 
1619     * <p>Any further edit operation against this node or any of its descendants
1620     * will be synchronized against the specified OAST until it is removed from
1621     * the tree by calling {@link #detach(boolean)}.  If this node is already
1622     * attached to an OAST, it will be detached from it first, with
1623     * displacement.</p>
1624     * 
1625     * <p>This method is for internal use by API functions and the parser and is
1626     * not intended for use by clients.</p>
1627     * @param tree The tree to attach the node to
1628     * @param bDisplace <code>true</code> to have the tree displace existing nodes
1629     *                  to make room before attaching this one, <code>false</code>
1630     *                  if there is already space for it.
1631     */
1632    public void attach(IOWLAbstractSyntaxTree tree, boolean bDisplace)
1633    {
1634       if (tree == null)
1635       {
1636          return;
1637       }
1638       if (_tree != null)
1639       {
1640          detach(true);
1641       }
1642       synchronized (tree)
1643       {
1644          accept(new TreeReferenceVisitor(tree));
1645          OASTNode parent = _tree.getNode(_iOffset);
1646          if (parent.getOffset() == _iOffset && parent.getParent() != null)
1647          {
1648             parent = parent.getParent();
1649          }
1650          parent.doInsert(this, bDisplace);
1651          accept(new NodeInitVisitor());
1652 
1653          if (tree.hasModel())
1654          {
1655             if(parent instanceof PropertyNode)
1656             {
1657                ((OAST)tree).addToModel(getParent());
1658             }
1659             else
1660             {
1661                ((OAST)tree).addToModel(this);
1662             }
1663          }
1664       }
1665    }
1666    
1667    /***
1668     * <p>Replaces an existing child node with a new one.  The tree will be
1669     * displaced to compensate for the removal and insertion.</p>
1670     * 
1671     * <p>If this node is attached to an OWL abstract syntax tree, the removed
1672     * child will be detached from it, the replacement child will be attached
1673     * to it, and an event will be dispatched to all OAST event listeners
1674     * to alert them to the change.</p>
1675     * @param oldChild The child to remove
1676     * @param newChild The child to insert in <code>oldChild</code>'s place.
1677     * @throws OASTException if this node is attached to a read-only OAST,
1678     *                       <code>oldChild</code> is not a child of this node,
1679     *                       or <code>newChild</code> is <code>null</code>.
1680     */
1681    public void replace(OASTNode oldChild, OASTNode newChild) throws OASTException
1682    {
1683       if (!_alChildren.contains(oldChild))
1684       {
1685          throw new OASTException(
1686             oldChild + " is not a child of " + this, this);
1687       }
1688       else if (newChild == null)
1689       {
1690          throw new OASTException(
1691             "Cannot replace " + oldChild + " with a null node", this);
1692       }
1693       
1694       if (_tree == null)
1695       {
1696          int iDisplacement = oldChild.getOffset() - newChild.getOffset();
1697          if (iDisplacement != 0)
1698          {
1699             newChild.accept(new NodeDisplacementVisitor(0, iDisplacement));
1700          }
1701          doRemove(oldChild, true);
1702          doInsert(newChild, true);
1703       }
1704       else
1705       {
1706          if (_tree.isReadOnly())
1707          {
1708             String sName = _tree.getRoot().getOWLDocument().getElementName();
1709             throw new OASTException(sName + S_READ_ONLY_EXCEPTION, _tree);
1710          }
1711          IOASTDelta delta = OASTDelta.createReplaceDelta(oldChild, newChild);
1712          OASTEvent event = new OASTEvent(delta);
1713          oldChild.detach(true);
1714          newChild.attach(_tree, true);
1715          ((OAST)_tree).changed(event);
1716       }
1717    }
1718    
1719    /***
1720     * <p>Removes a child node from this node.  The tree containing this node 
1721     * can optionally be displaced afterwards to compensate for the removed 
1722     * child.</p>
1723     * 
1724     * <p>If this node is attached to an OWL abstract syntax tree, the removed
1725     * child node will be detached from it and an event will be dispatched to 
1726     * all OAST event listeners to alert them to the removal.</p>
1727     * @param child the child node to remove
1728     * @param bDisplace <code>true</code> if the tree needs to be displaced
1729     *                  to make room for <code>child</code>, <code>false</code>
1730     *                  if there is already space for it.
1731     * @throws OASTException if this node is attached to a read-only OAST
1732     *                       or <code>child</code> is not a child of this node.
1733     */
1734    public void remove(OASTNode child, boolean bDisplace) throws OASTException
1735    {
1736       if (!_alChildren.contains(child))
1737       {
1738          throw new OASTException(
1739             child + " is not a child of " + this, this);
1740       }
1741       
1742       if (_tree == null)
1743       {
1744          doRemove(child, bDisplace);
1745       }
1746       else
1747       {
1748          if (_tree.isReadOnly())
1749          {
1750             String sName = _tree.getRoot().getOWLDocument().getElementName();
1751             throw new OASTException(sName + S_READ_ONLY_EXCEPTION, _tree);
1752          }
1753          IOASTDelta delta = OASTDelta.createRemoveDelta(new OASTNode[]{child});
1754          OASTEvent event = new OASTEvent(delta);
1755          child.detach(bDisplace);
1756          ((OAST)_tree).changed(event);
1757       }
1758    }
1759    
1760    /***
1761     * Helper method for <code>remove()</code> and <code>detach()</code>.
1762     * @param child the child node to remove
1763     * @param bDisplace <code>true</code> if the tree needs to be displaced
1764     *                  to make room for <code>child</code>, <code>false</code>
1765     *                  if there is already space for it.
1766     */
1767    private void doRemove(OASTNode child, boolean bDisplace)
1768    {
1769       synchronized (getLockObject())
1770       {
1771          removeChild(child);
1772          child._nodeParent = null;
1773          if (bDisplace)
1774          {
1775             OASTNode root = getRoot();
1776             root.getRoot().accept(new NodeDisplacementVisitor(child.getOffset(), -child.getLength()));
1777          }
1778       }
1779    }
1780    /***
1781     * <p>Detaches the node from its associated OWL abstract syntax tree.  
1782     * First, <code>cleanup()</code> will be called on this node and all of its 
1783     * descendants, while this node is still attached to the tree.  Next, the
1784     * parent/child relationships tying the node to the tree will be
1785     * removed.  As an optional final step, the remaining nodes in the tree will 
1786     * be displaced to compensate for the removal.</p>
1787     * 
1788     * <p>This method is for internal use by API functions and the parser and is
1789     * not intended for use by clients.</p>
1790     * @param bDisplace <code>true</code> to have the tree displace existing nodes
1791     *                  to make room before attaching this one, <code>false</code>
1792     *                  if there is already space for it.
1793     */
1794    public void detach(boolean bDisplace)
1795    {
1796       if (_tree == null)
1797       {
1798          return;
1799       }
1800       synchronized (_tree)
1801       {
1802          if (_tree.hasModel())
1803          {
1804             ((OAST)_tree).removeFromModel(this);
1805          }
1806          accept(new NodeCleanupVisitor());
1807          _nodeParent.doRemove(this, bDisplace);
1808          accept(new TreeReferenceVisitor(null));
1809       }
1810    }
1811    
1812    /***
1813     * Retrieves the root node of the tree containing this node.  This will be
1814     * a DocumentRoot if the node is attached to an OAST.  If this node is not
1815     * attached to an OAST, the root node may be of any type.
1816     * @return The root node of this node's tree
1817     */
1818    protected OASTNode getRoot()
1819    {
1820       if (_tree != null)
1821       {
1822          return _tree.getRoot();
1823       }
1824       else
1825       {
1826          OASTNode node = this;
1827          while (node.getParent() != null)
1828          {
1829             node = node.getParent();
1830          }
1831          return node;
1832       }
1833    }
1834    
1835    /***
1836     * Returns the tree the node is attached to.
1837     * @return The tree the node is attached to, or <code>null</code> if it is
1838     *         not currently attached to any tree.
1839     */
1840    public IOWLAbstractSyntaxTree getOWLAbstractSyntaxTree()
1841    {
1842       return _tree;
1843    }
1844    
1845    /***
1846     * Creates a new OAST node of the same type as this one.
1847     * @return A new node of the same node type
1848     */
1849    protected abstract OASTNode duplicateType();
1850    
1851    /***
1852     * Creates a deep copy of a node and all nodes below it in the tree.  The
1853     * resulting copy is not attached to any OWL abstract syntax tree.
1854     * @return A deep copy of this node, including copies of any node structure
1855     *         below it in the tree.
1856     */
1857    public Object clone()
1858    {
1859       OASTNode node = duplicateType();
1860       node._iOffset = _iOffset;
1861       node._iLength = _iLength;
1862       node._tree = null;
1863       node._alChildren = new ArrayList();
1864       Iterator it = _alChildren.iterator();
1865       while (it.hasNext())
1866       {
1867          OASTNode n = (OASTNode)it.next();
1868          node._alChildren.add(n.clone());
1869       }
1870       return node;
1871    }
1872 
1873    /***
1874     * Calls OASTNode.init() on visited nodes in response to their insertion.
1875     * @author jlerner
1876     */
1877    public class NodeInitVisitor implements IOASTNodeVisitor
1878    {
1879       /* (non-Javadoc)
1880        * @see com.bbn.swede.core.dom.IOASTNodeVisitor#visit(com.bbn.swede.core.dom.OASTNode)
1881        */
1882       public boolean visit(OASTNode node)
1883       {
1884          node.init();
1885          return true;
1886       }
1887    }
1888 
1889    /***
1890     * Calls OASTNode.cleanup() on visited nodes in preparation for their 
1891     * removal.
1892     * @author jlerner
1893     */
1894    public class NodeCleanupVisitor implements IOASTNodeVisitor
1895    {
1896       /* (non-Javadoc)
1897        * @see com.bbn.swede.core.dom.IOASTNodeVisitor#visit(com.bbn.swede.core.dom.OASTNode)
1898        */
1899       public boolean visit(OASTNode node)
1900       {
1901          node.cleanup();
1902          return true;
1903       }
1904 
1905    }
1906 
1907    /***
1908     * A visitor for setting the back reference to the containing OAST for 
1909     * a subtree of OASTNodes.
1910     * @author jlerner
1911     */
1912    private class TreeReferenceVisitor implements IOASTNodeVisitor
1913    {
1914       private IOWLAbstractSyntaxTree _tree;
1915       
1916       /***
1917        * Creates a new TreeReferenceVisitor.
1918        * @param tree The tree that should be set as the back reference for
1919        *             each visited node.  May be <code>null</code>. 
1920        */
1921       public TreeReferenceVisitor(IOWLAbstractSyntaxTree tree)
1922       {
1923          _tree = tree;
1924       }
1925       /* (non-Javadoc)
1926        * @see com.bbn.swede.core.dom.IOASTNodeVisitor#visit(com.bbn.swede.core.dom.OASTNode)
1927        */
1928       public boolean visit(OASTNode node)
1929       {
1930          node._tree = _tree;
1931          return true;
1932       }
1933       
1934    }
1935 }