View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 2000-2002 (C) Intalio Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  
36  package org.exolab.castor.xml.schema.reader;
37  
38  import org.exolab.castor.xml.AttributeSet;
39  import org.exolab.castor.xml.Namespaces;
40  import org.exolab.castor.xml.XMLException;
41  import org.exolab.castor.xml.schema.Annotation;
42  import org.exolab.castor.xml.schema.AttributeDecl;
43  import org.exolab.castor.xml.schema.AttributeGroupReference;
44  import org.exolab.castor.xml.schema.ComplexType;
45  import org.exolab.castor.xml.schema.ContentType;
46  import org.exolab.castor.xml.schema.Facet;
47  import org.exolab.castor.xml.schema.Schema;
48  import org.exolab.castor.xml.schema.SchemaContext;
49  import org.exolab.castor.xml.schema.SchemaException;
50  import org.exolab.castor.xml.schema.SchemaNames;
51  import org.exolab.castor.xml.schema.SimpleContent;
52  import org.exolab.castor.xml.schema.SimpleType;
53  import org.exolab.castor.xml.schema.Wildcard;
54  import org.exolab.castor.xml.schema.XMLType;
55  
56  /**
57   * A class for unmarshalling restriction elements of a simpleContent
58   * 
59   * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a>
60   * @version $Revision$ $Date: 2006-04-14 04:14:43 -0600 (Fri, 14 Apr 2006) $ TODO: support the
61   *          correct restriction for facets and attributes
62   **/
63  public class SimpleContentRestrictionUnmarshaller extends ComponentReader {
64  
65  
66    // --------------------/
67    // - Member Variables -/
68    // --------------------/
69  
70    /**
71     * The current ComponentReader
72     **/
73    private ComponentReader unmarshaller;
74  
75    /**
76     * The current branch depth
77     **/
78    private int depth = 0;
79  
80    /**
81     * The complexType we are unmarshalling
82     **/
83    private ComplexType _complexType = null;
84  
85    private Schema _schema = null;
86    private String _id = null;
87    private boolean foundAnnotation = false;
88    private boolean foundSimpleType = false;
89    private boolean foundFacets = false;
90    private boolean foundAttribute = false;
91    private boolean foundAttributeGroup = false;
92  
93    /**
94     * The content type
95     **/
96    private SimpleTypeDefinition _simpleTypeDef = null;
97  
98    // ----------------/
99    // - Constructors -/
100   // ----------------/
101   /**
102    * Creates a new RestrictionUnmarshaller.
103    * 
104    * @param schemaContext the {@link SchemaContext} to get some configuration settings from
105    * @param complexType the complexType being unmarshalled
106    * @param atts the AttributeList
107    */
108   public SimpleContentRestrictionUnmarshaller(final SchemaContext schemaContext,
109       final ComplexType complexType, final AttributeSet atts) {
110 
111     super(schemaContext);
112 
113     _complexType = complexType;
114     _complexType.setDerivationMethod(SchemaNames.RESTRICTION);
115     _complexType.setRestriction(true);
116     _schema = complexType.getSchema();
117     _id = atts.getValue(SchemaNames.ID_ATTR);
118 
119     // -- base
120     String base = atts.getValue(SchemaNames.BASE_ATTR);
121 
122     if ((base != null) && (base.length() > 0)) {
123 
124       XMLType baseType = _schema.getType(base);
125       if (baseType == null) {
126         _complexType.setBase(base);
127         _complexType.setContentType(new SimpleContent(_schema, base));
128       } else if (baseType.isSimpleType()) {
129         String err = "complexType: ";
130         String name = _complexType.getName();
131         if (name != null) {
132           err += name;
133         } else {
134           err += "#anonymous-complexType#";
135         }
136 
137         err += "A complex type cannot be a restriction" + " of a simpleType:";
138         err += baseType.getName();
139         throw new IllegalStateException(err);
140       }
141       // we are now sure that the base is a ComplexType
142       // but is the base of this complexType a simpleType? (see 4.3.3->simpleContent->content type)
143       else {
144         ComplexType temp = (ComplexType) baseType;
145 
146         if (!temp.isSimpleContent()) {
147           // UPO - base type may have complex content if
148           // 1. content model is emptiable
149           // 2. it has mixed content
150           // See bug report http://jira.codehaus.org/browse/CASTOR-1238
151           if ((temp.getContentType().getType() == ContentType.MIXED) && temp.isEmptiable()) {
152             // OK
153           } else {
154             String err = "complexType: ";
155             String name = _complexType.getName();
156             if (name != null) {
157               err += name;
158             } else {
159               err += "#anonymous-complexType#";
160             }
161 
162             err += ": In a simpleContent when using restriction the base type"
163                 + " must be a complexType with a simple content model or it must"
164                 + " be a complex content model which is mixed and emptiable.";
165             throw new IllegalStateException(err);
166           }
167         } else {
168           // retrieve the base type of this complexType
169           // the base type is the complexType but we have to
170           // work with the simple type of the content type.
171           SimpleContent contentType = (SimpleContent) temp.getContentType();
172           _complexType.setBaseType(temp);
173           _complexType.setBase(temp.getName());
174           _simpleTypeDef = new SimpleTypeDefinition(_schema, temp.getName(), _id);
175           SimpleType simpleType = contentType.getSimpleType();
176           if (simpleType != null) {
177             _simpleTypeDef.setBaseType(simpleType);
178           } else {
179             _simpleTypeDef.setBaseTypeName(contentType.getTypeName());
180           }
181         }
182       }
183     }
184 
185 
186   } // -- SimpleContentRestrictionUnmarshaller
187 
188   // -----------/
189   // - Methods -/
190   // -----------/
191 
192   /**
193    * Returns the name of the element that this ComponentReader handles
194    * 
195    * @return the name of the element that this ComponentReader handles
196    **/
197   public String elementName() {
198     return SchemaNames.RESTRICTION;
199   } // -- elementName
200 
201   /**
202    * Returns the Object created by this ComponentReader
203    * 
204    * @return the Object created by this ComponentReader
205    **/
206   public Object getObject() {
207     return null;
208   } // -- getObject
209 
210   /**
211    * Signals the start of an element with the given name.
212    *
213    * @param name the NCName of the element. It is an error if the name is a QName (ie. contains a
214    *        prefix).
215    * @param namespace the namespace of the element. This may be null. Note: A null namespace is not
216    *        the same as the default namespace unless the default namespace is also null.
217    * @param atts the AttributeSet containing the attributes associated with the element.
218    * @param nsDecls the namespace declarations being declared for this element. This may be null.
219    **/
220   public void startElement(String name, String namespace, AttributeSet atts, Namespaces nsDecls)
221       throws XMLException {
222     // -- Do delagation if necessary
223     if (unmarshaller != null) {
224       unmarshaller.startElement(name, namespace, atts, nsDecls);
225       ++depth;
226       return;
227     }
228 
229 
230     // -- annotation
231     if (name.equals(SchemaNames.ANNOTATION)) {
232 
233       if (foundFacets || foundSimpleType || foundAttribute || foundAttributeGroup)
234         error("An annotation must appear as the first child " + "of 'restriction' elements.");
235 
236       if (foundAnnotation)
237         error("Only one (1) annotation may appear as a child of " + "'restriction' elements.");
238 
239       foundAnnotation = true;
240       unmarshaller = new AnnotationUnmarshaller(getSchemaContext(), atts);
241     }
242 
243     else if (SchemaNames.SIMPLE_TYPE.equals(name)) {
244       if (foundSimpleType)
245         error("Only one (1) 'simpleType' may appear as a child of " + "'restriction' elements.");
246 
247       if (foundFacets)
248         error("A 'simpleType', as a child of 'restriction' "
249             + "elements, must appear before any facets.");
250 
251       if (foundAttribute || foundAttributeGroup)
252         error("A 'simpleType', as a child of 'restriction' "
253             + "elements, must appear before any attribute elements.");
254 
255       foundSimpleType = true;
256       unmarshaller = new SimpleTypeUnmarshaller(getSchemaContext(), _schema, atts);
257 
258     } else if (FacetUnmarshaller.isFacet(name)) {
259       foundFacets = true;
260       if (foundAttribute || foundAttributeGroup)
261         error("A 'facet', as a child of 'restriction' "
262             + "elements, must appear before any attribute elements.");
263 
264       unmarshaller = new FacetUnmarshaller(getSchemaContext(), name, atts);
265       if (_simpleTypeDef == null) {
266         SimpleContent content = (SimpleContent) _complexType.getContentType();
267         _simpleTypeDef = new SimpleTypeDefinition(_schema, content.getTypeName(), _id);
268       }
269     } else if (SchemaNames.ATTRIBUTE.equals(name)) {
270       foundAttribute = true;
271       unmarshaller = new AttributeUnmarshaller(getSchemaContext(), _schema, atts);
272     } else if (SchemaNames.ATTRIBUTE_GROUP.equals(name)) {
273 
274       // --In a complexType we only reference attribute group
275       if (atts.getValue(SchemaNames.REF_ATTR) == null) {
276         error("A 'complexType' may contain referring " + "attributeGroups, but not defining ones.");
277       }
278       foundAttributeGroup = true;
279       unmarshaller = new AttributeGroupUnmarshaller(getSchemaContext(), _schema, atts);
280     }
281     // -- <anyAttribute>
282     else if (SchemaNames.ANY_ATTRIBUTE.equals(name)) {
283       unmarshaller =
284           new WildcardUnmarshaller(getSchemaContext(), _complexType, _schema, name, atts);
285     }
286 
287     else
288       illegalElement(name);
289   } // -- startElement
290 
291   /**
292    * Signals to end of the element with the given name.
293    *
294    * @param name the NCName of the element. It is an error if the name is a QName (ie. contains a
295    *        prefix).
296    * @param namespace the namespace of the element.
297    **/
298   public void endElement(String name, String namespace) throws XMLException {
299 
300     // -- Do delagation if necessary
301     if ((unmarshaller != null) && (depth > 0)) {
302       unmarshaller.endElement(name, namespace);
303       --depth;
304       return;
305     }
306 
307     // -- have unmarshaller perform any necessary clean up
308     unmarshaller.finish();
309 
310     // -- annotation
311     if (SchemaNames.ANNOTATION.equals(name)) {
312       Annotation ann = ((AnnotationUnmarshaller) unmarshaller).getAnnotation();
313       _complexType.addAnnotation(ann);
314     }
315     // -- <anyAttribute>
316     else if (SchemaNames.ANY_ATTRIBUTE.equals(name)) {
317       Wildcard wildcard = ((WildcardUnmarshaller) unmarshaller).getWildcard();
318       try {
319         _complexType.setAnyAttribute(wildcard);
320       } catch (SchemaException e) {
321         throw new IllegalArgumentException(e.getMessage());
322       }
323     }
324     // Note: the attributes are added to the complexType
325     // since a simpleType does not contain attributes at all
326     // -- attribute
327     else if (SchemaNames.ATTRIBUTE.equals(name)) {
328       AttributeDecl attrDecl = ((AttributeUnmarshaller) unmarshaller).getAttribute();
329 
330       /* TODO add the validation code later */
331 
332       /*
333        * ComplexType baseType = (ComplexType)_complexType.getBaseType(); if (
334        * (baseType.getAttributeDecls() == null) || (baseType.getAttributeDecl(attrDecl.getName()) ==
335        * null) ) error("The restricted attribute must be present in the" +" base type."); baseType =
336        * null;
337        */
338 
339       _complexType.addAttributeDecl(attrDecl);
340     }
341     // -- attribute groups
342     else if (SchemaNames.ATTRIBUTE_GROUP.equals(name)) {
343       AttributeGroupReference attrGroupRef = (AttributeGroupReference) unmarshaller.getObject();
344       _complexType.addAttributeGroupReference(attrGroupRef);
345     }
346     // -- simpleType
347     else if (SchemaNames.SIMPLE_TYPE.equals(name)) {
348       SimpleType type = (SimpleType) unmarshaller.getObject();
349       _complexType.setContentType(new SimpleContent(type));
350     }
351     // --facet
352     else {
353       _simpleTypeDef.addFacet((Facet) unmarshaller.getObject());
354       foundFacets = true;
355       // set the flag in order to create the new base in
356       // the finish() method
357     }
358 
359 
360     unmarshaller = null;
361   } // -- endElement
362 
363   public void characters(char[] ch, int start, int length) throws XMLException {
364     // -- Do delagation if necessary
365     if (unmarshaller != null) {
366       unmarshaller.characters(ch, start, length);
367     }
368   } // -- characters
369 
370   /**
371    * Terminates the process of this restriction by setting a proper base. We set a new base if the
372    * base simple type has been restricted by the use of facets since all other restrictions may
373    * concern the complexType character of the type (i.e attribute for instance is only related to a
374    * complexType...)
375    */
376   public void finish() {
377 
378     if (_simpleTypeDef != null) {
379       SimpleType baseType = _simpleTypeDef.createSimpleType();
380       _complexType.setContentType(new SimpleContent(baseType));
381     }
382     // the restriction was properly handle
383     // we can set the flag
384     _complexType.setRestriction(true);
385   }
386 } // -- SimpleContentRestrictionUnmarshaller