1   /*
2    *  AnnotationSchema.java
3    *
4    *  Copyright (c) 1998-2001, The University of Sheffield.
5    *
6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
7    *  software, licenced under the GNU Library General Public License,
8    *  Version 2, June 1991 (in the distribution as file licence.html,
9    *  and also available at http://gate.ac.uk/gate/licence.html).
10   *
11   *  Cristian URSU, 27/Sept/2000
12   *
13   *  $Id: AnnotationSchema.java,v 1.20 2002/11/22 11:44:34 valyt Exp $
14   */
15  package gate.creole;
16  
17  import java.util.*;
18  import java.net.*;
19  import java.io.*;
20  
21  import gate.util.*;
22  import gate.*;
23  
24  import org.xml.sax.*;
25  import javax.xml.parsers.*;
26  import org.jdom.input.*;
27  import org.jdom.*;
28  
29  /** This class handles annotation schemas.An annotation schema is a
30    * representation of an annotation, together with its types and their
31    * attributes, values and types.
32    */
33  public class AnnotationSchema extends AbstractLanguageResource{
34    public static final String FILE_URL_PARAM_NAME = "xmlFileUrl";
35  
36    /** Debug flag */
37    private static final boolean DEBUG = false;
38  
39    /** A map between XSchema types and Java Types */
40    private static Map xSchema2JavaMap;
41  
42    /** A map between JAva types and XSchema */
43    private static Map java2xSchemaMap;
44  
45    /** This sets up two Maps between XSchema types and their coresponding
46      * Java types + a DOM xml parser
47      */
48    private static void setUpStaticData()
49    throws ResourceInstantiationException
50    {
51      xSchema2JavaMap = new HashMap();
52      java2xSchemaMap = new HashMap();
53  
54      xSchema2JavaMap.put("string",   String.class.getName());
55      xSchema2JavaMap.put("integer",  Integer.class.getName());
56      xSchema2JavaMap.put("int",      Integer.class.getName() );
57      xSchema2JavaMap.put("boolean",  Boolean.class.getName());
58      xSchema2JavaMap.put("float",    Float.class.getName());
59      xSchema2JavaMap.put("double",   Double.class.getName());
60      xSchema2JavaMap.put("short",    Short.class.getName());
61      xSchema2JavaMap.put("byte",     Byte.class.getName());
62  
63      java2xSchemaMap.put(String.class.getName(),   "string");
64      java2xSchemaMap.put(Integer.class.getName(),  "integer");
65      java2xSchemaMap.put(Boolean.class.getName(),  "boolean");
66      java2xSchemaMap.put(Float.class.getName(),    "float");
67      java2xSchemaMap.put(Double.class.getName(),   "double");
68      java2xSchemaMap.put(Short.class.getName(),    "short");
69      java2xSchemaMap.put(Byte.class.getName(),     "byte");
70    } //setUpStaticData
71  
72    /** The name of the annotation */
73    protected String annotationName = null;
74  
75    /** Returns the value of annotation name */
76    public String getAnnotationName(){
77      return annotationName;
78    } // getAnnotationName
79  
80    /** Sets the annotation name */
81    public void setAnnotationName(String annotationName) {
82      this.annotationName = annotationName;
83    } // setAnnotationName
84  
85    /** Schemas for the attributes */
86    protected Set featureSchemaSet = null;
87  
88    /** Constructs an annotation schema. */
89    public AnnotationSchema(){
90    } // AnnotationSchema
91  
92    /** Returns the feature schema set */
93    public Set getFeatureSchemaSet(){
94      return featureSchemaSet;
95    } // getAttributeSchemas
96  
97    /** Sets the feature schema set */
98    public void setFeatureSchemaSet(Set featureSchemaSet) {
99      this.featureSchemaSet = featureSchemaSet;
100   } // setFeatureSchemaSet
101 
102   /** @return a FeatureSchema object from featureSchemaSet, given a
103     * feature name.It will return null if the feature name is not found.
104     */
105   public FeatureSchema getFeatureSchema(String featureName) {
106     Iterator fsIterator = featureSchemaSet.iterator();
107     while (fsIterator.hasNext()) {
108       FeatureSchema fs = (FeatureSchema) fsIterator.next();
109       if (fs.getFeatureName().equals(featureName) )
110         return fs;
111     }
112     return null;
113   } // getFeatureSchema
114 
115   /** Initialise this resource, and return it. If the schema XML source file
116     * URL has been set, it will construct itself from that file.
117     */
118   public Resource init() throws ResourceInstantiationException {
119     // set up the static data if it's not there already
120     if(xSchema2JavaMap == null || java2xSchemaMap == null)
121       setUpStaticData();
122 
123     // parse the XML file if we have its URL
124     if(xmlFileUrl != null) fromXSchema(xmlFileUrl);
125 
126     return this;
127   } // init()
128 
129   /** The xml file URL of the resource */
130   protected URL xmlFileUrl;
131 
132   /**
133    * The namepsace used in the xml file
134    */
135   protected Namespace namespace;
136 
137   /** Set method for the resource xml file URL */
138   public void setXmlFileUrl(URL xmlFileUrl) { this.xmlFileUrl = xmlFileUrl; }
139 
140   /** Get method for the resource xml file URL */
141   public URL getXmlFileUrl() { return xmlFileUrl; }
142 
143   /** Creates an AnnotationSchema object from an XSchema file
144     * @param anXSchemaURL the URL where to find the XSchema file
145     */
146   public void fromXSchema(URL anXSchemaURL)
147               throws ResourceInstantiationException {
148     org.jdom.Document jDom = null;
149     SAXBuilder saxBuilder = new SAXBuilder(false);
150     try{
151       jDom = saxBuilder.build(anXSchemaURL);
152     }catch(JDOMException je){
153       throw new ResourceInstantiationException(je);
154     }
155     workWithJDom(jDom);
156   } // fromXSchema
157 
158   /** Creates an AnnotationSchema object from an XSchema file
159     * @param anXSchemaInputStream the Input Stream containing the XSchema file
160     */
161   public void fromXSchema(InputStream anXSchemaInputStream)
162               throws ResourceInstantiationException {
163     org.jdom.Document jDom = null;
164     SAXBuilder saxBuilder = new SAXBuilder(false);
165     try{
166       jDom = saxBuilder.build(anXSchemaInputStream);
167     }catch(JDOMException je){
168       throw new ResourceInstantiationException(je);
169     }
170     workWithJDom(jDom);
171   } // end fromXSchema
172 
173   /** This method uses the JDom structure for our XSchema needs. What it does is
174     * to add semantics to the XML elements defined in XSchema. In the end we need
175     * to construct an AnnotationSchema object form an XSchema file.
176     *
177     * @param jDom the JDOM structure containing the XSchema document. It must not
178     * be <b>null<b>
179     */
180   private void workWithJDom(org.jdom.Document jDom){
181     // Use the jDom structure the way we want
182     org.jdom.Element rootElement = jDom.getRootElement();
183     namespace = rootElement.getNamespace();
184     // get all children elements from the rootElement
185     List rootElementChildrenList = rootElement.getChildren("element", namespace);
186     Iterator rootElementChildrenIterator = rootElementChildrenList.iterator();
187     while (rootElementChildrenIterator.hasNext()){
188       org.jdom.Element childElement =
189                         (org.jdom.Element) rootElementChildrenIterator.next();
190       createAnnotationSchemaObject(childElement);
191     }//end while
192   } // workWithJdom
193 
194   /** This method creates an AnnotationSchema object fom an org.jdom.Element
195     * @param anElement is an XSchema element element
196     */
197   private void createAnnotationSchemaObject(org.jdom.Element anElement){
198     // Get the value of the name attribute. If this attribute doesn't exists
199     // then it will receive a default one.
200     annotationName = anElement.getAttributeValue("name");
201     if (annotationName == null)
202         annotationName = "UnknownElement";
203     // See if this element has a complexType element inside it
204     org.jdom.Element complexTypeElement = anElement.getChild("complexType",
205                                                              namespace);
206     if (complexTypeElement != null){
207       List complexTypeCildrenList = complexTypeElement.getChildren("attribute",
208                                                                    namespace);
209       Iterator complexTypeCildrenIterator = complexTypeCildrenList.iterator();
210       if (complexTypeCildrenIterator.hasNext())
211         featureSchemaSet = new HashSet();
212       while (complexTypeCildrenIterator.hasNext()) {
213         org.jdom.Element childElement =
214                     (org.jdom.Element) complexTypeCildrenIterator.next();
215         createAndAddFeatureSchemaObject(childElement);
216       }// end while
217     }// end if
218   } // createAnnoatationSchemaObject
219 
220   /** This method creates and adds a FeatureSchema object to the current
221     * AnnotationSchema one.
222     * @param anElement is an XSchema attribute element
223     */
224   public void createAndAddFeatureSchemaObject(org.jdom.Element
225                                                           anAttributeElement) {
226     String featureName = null;
227     String featureType = null;
228     String featureUse  = null;
229     String featureValue = null;
230     Set    featurePermissibleValuesSet = null;
231 
232     // Get the value of the name attribute. If this attribute doesn't exists
233     // then it will receive a default one.
234     featureName = anAttributeElement.getAttributeValue("name");
235     if (featureName == null)
236       featureName = "UnknownFeature";
237 
238     // See if it has a type attribute associated
239     featureType = anAttributeElement.getAttributeValue("type");
240     if (featureType != null)
241       // Set it to the corresponding Java type
242       featureType = (String) xSchema2JavaMap.get(featureType);
243 
244     // Get the value of use attribute
245     featureUse = anAttributeElement.getAttributeValue("use");
246     if (featureUse == null)
247       // Set it to the default value
248       featureUse = "optional";
249 
250     // Get the value of value attribute
251     featureValue = anAttributeElement.getAttributeValue("value");
252     if (featureValue == null)
253       featureValue = "";
254 
255     // Let's check if it has a simpleType element inside
256     org.jdom.Element simpleTypeElement  =
257                                   anAttributeElement.getChild("simpleType",
258                                                               namespace);
259 
260     // If it has (!= null) then check to see if it has a restrictionElement
261     if (simpleTypeElement != null) {
262       org.jdom.Element restrictionElement =
263                               simpleTypeElement.getChild("restriction",
264                                                          namespace);
265       if (restrictionElement != null) {
266         // Get the type attribute for restriction element
267         featureType = restrictionElement.getAttributeValue("base");
268 
269         // Check to see if that attribute was present. getAttributeValue will
270         // return null if it wasn't present
271         if (featureType == null)
272           // If it wasn't present then set it to default type (string)
273           featureType =  (String) xSchema2JavaMap.get("string");
274         else
275           // Set it to the corresponding Java type
276           featureType = (String) xSchema2JavaMap.get(featureType);
277 
278         // Check to see if there are any enumeration elements inside
279         List enumerationElementChildrenList =
280                                  restrictionElement.getChildren("enumeration",
281                                                                 namespace);
282         Iterator enumerationChildrenIterator =
283                                 enumerationElementChildrenList.iterator();
284 
285         // Check if there is any enumeration element in the list
286         if (enumerationChildrenIterator.hasNext())
287             featurePermissibleValuesSet = new HashSet();
288         while (enumerationChildrenIterator.hasNext()) {
289           org.jdom.Element enumerationElement =
290                         (org.jdom.Element) enumerationChildrenIterator.next();
291           String permissibleValue =
292                             enumerationElement.getAttributeValue("value");
293           // Add that value to the featureSchema possible values set.
294           featurePermissibleValuesSet.add(permissibleValue);
295         }// end while
296       }// end if( restrictionElement != null)
297     }// end if (simpleTypeElement != null)
298 
299     // If it doesn't have a simpleTypeElement inside and featureType is null or
300     // it wasn't recognised, then we set the default type to string.
301     if (simpleTypeElement == null && featureType == null )
302       featureType =  (String) xSchema2JavaMap.get("string");
303 
304     // Create an add a featureSchema object
305     FeatureSchema featureSchema = new FeatureSchema(
306                                                    featureName,
307                                                    featureType,
308                                                    featureValue,
309                                                    featureUse,
310                                                    featurePermissibleValuesSet);
311     featureSchemaSet.add(featureSchema);
312   } // createAndAddFeatureSchemaObject
313 
314   /** @return a String containing the XSchema document representing
315     *  an AnnotationSchema object.
316     */
317   public String toXSchema(){
318     StringBuffer schemaString = new StringBuffer();
319     schemaString.append("<?xml version=\"1.0\"?>\n" +
320                    "<schema xmlns=\"http://www.w3.org/2000/10/XMLSchema\">\n"+
321                    " <element name=\"" + annotationName + "\"");
322 
323     if (featureSchemaSet == null)
324       schemaString.append("/>\n");
325     else {
326       schemaString.append(">\n  <complexType>\n");
327       Iterator featureSchemaSetIterator = featureSchemaSet.iterator();
328       while (featureSchemaSetIterator.hasNext()){
329         FeatureSchema fs = (FeatureSchema) featureSchemaSetIterator.next();
330         schemaString.append("   " + fs.toXSchema(java2xSchemaMap));
331       }// end while
332       schemaString.append("  </complexType>\n");
333       schemaString.append(" </element>\n");
334     }// end if else
335     schemaString.append("</schema>\n");
336     return schemaString.toString();
337   }// toXSchema
338 } // AnnotationSchema
339 
340 
341