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