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