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 1999-2002 (C) Intalio, Inc. All Rights Reserved.
42   *
43   * $Id$
44   */
45  
46  package org.exolab.castor.xml.schema.reader;
47  
48  //-- imported classes and packages
49  import org.exolab.castor.xml.AttributeSet;
50  import org.exolab.castor.xml.Namespaces;
51  import org.exolab.castor.xml.XMLException;
52  import org.exolab.castor.xml.schema.Annotation;
53  import org.exolab.castor.xml.schema.ElementDecl;
54  import org.exolab.castor.xml.schema.Group;
55  import org.exolab.castor.xml.schema.ModelGroup;
56  import org.exolab.castor.xml.schema.Order;
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.Wildcard;
62  
63  /**
64   * A class for Unmarshalling ModelGroups
65   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
66   * @version $Revision$ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $
67  **/
68  public class GroupUnmarshaller extends ComponentReader {
69  
70        //--------------------------/
71       //- Static Class Variables -/
72      //--------------------------/
73  
74      /**
75       * The value of the maximum occurance wild card
76       */
77      private static final String MAX_OCCURS_WILDCARD = "unbounded";
78  
79        //--------------------/
80       //- Member Variables -/
81      //--------------------/
82  
83      /**
84       * The current ComponentReader
85      **/
86      private ComponentReader unmarshaller;
87  
88      /**
89       * The current branch depth
90      **/
91      private int depth = 0;
92  
93      /**
94       * The ModelGroup reference for the ModelGroup we are constructing
95      **/
96      private Group _group = null;
97  
98      /**
99       * The Schema being "unmarshalled"
100     **/
101     private Schema _schema = null;
102 
103     /**
104      * The element name of the Group to be unmarshalled.
105     **/
106     private String _element = SchemaNames.SEQUENCE;
107 
108     private boolean foundAll        = false;
109     private boolean foundElement    = false;
110     private boolean foundGroup      = false;
111     private boolean foundModelGroup = false;
112     private boolean foundAnnotation = false;
113 
114       //----------------/
115      //- Constructors -/
116     //----------------/
117 
118     /**
119      * Creates a new GroupUnmarshaller.
120      * @param schemaContext the {@link SchemaContext} to get some configuration settings from
121      * @param schema the Schema to which the Group belongs
122      * @param element the element name for this type of group
123      * @param atts the AttributeList
124     **/
125     public GroupUnmarshaller(
126             final SchemaContext schemaContext,
127             final Schema schema,
128             final String element,
129             final AttributeSet atts) {
130         super(schemaContext);
131 
132         this._schema = schema;
133 
134         _group = new Group();
135         //-- handle attributes
136         String attValue = null;
137 
138 
139         if (SchemaNames.SEQUENCE.equals(element)) {
140                 _group.setOrder(Order.sequence);
141         }
142         else if (SchemaNames.CHOICE.equals(element)) {
143              _group.setOrder(Order.choice);
144         }
145         else if (SchemaNames.ALL.equals(element)) {
146                foundAll = true;
147              _group.setOrder(Order.all);
148         }
149         else {
150                 String err = "Invalid group element name: '" +
151                     element + "'";
152                 throw new IllegalArgumentException(err);
153             }
154 
155 
156         _element = element;
157 
158         //-- set name
159         attValue = atts.getValue(SchemaNames.NAME_ATTR);
160         if (attValue != null) {
161             _group.setName(attValue);
162         }
163 
164         /*
165          * @maxOccurs
166          * If maxOccurs is present, the value is either unbounded
167          * or the int value of the attribute, otherwise maxOccurs
168          * equals the minOccurs value.
169          */
170         attValue = atts.getValue(SchemaNames.MAX_OCCURS_ATTR);
171 
172         if (attValue != null) {
173             if (MAX_OCCURS_WILDCARD.equals(attValue))
174                 _group.setMaxOccurs(-1);
175             else
176                 _group.setMaxOccurs(toInt(attValue));
177         }
178         //-- minOccurs
179         attValue = atts.getValue("minOccurs");
180         if (attValue != null)
181             _group.setMinOccurs(toInt(attValue));
182 
183         if (_group.getOrder() == Order.all) {
184             if (_group.getMaxOccurs() != 1) {
185                String err = "Wrong maxOccurs value for a <all>:"+_group.getMaxOccurs();
186                err += "\n1 is the only possible value.";
187                throw new IllegalArgumentException(err);
188             }
189             if (_group.getMinOccurs() > 1) {
190                String err = "Wrong minOccurs value for a <all>:"+_group.getMinOccurs();
191                err += "\n0 or 1 are the only possible values.";
192                throw new IllegalArgumentException(err);
193             }
194         }
195         //-- id
196         _group.setId(atts.getValue("id"));
197 
198     } //-- GroupUnmarshaller
199 
200       //-----------/
201      //- Methods -/
202     //-----------/
203 
204     /**
205      * Returns the name of the element that this ComponentReader
206      * handles
207      * @return the name of the element that this ComponentReader
208      * handles
209     **/
210     public String elementName() {
211         return _element;
212     } //-- elementName
213 
214 
215     /**
216      * Returns the Group that was unmarshalled by this Unmarshaller.
217      * This method should only be called after unmarshalling
218      * has been completed.
219      *
220      * @return the unmarshalled Group
221     **/
222     public Group getGroup() {
223         return _group;
224     } //-- getGroup
225 
226     /**
227      * Returns the Object created by this ComponentReader
228      * @return the Object created by this ComponentReader
229     **/
230     public Object getObject() {
231         return getGroup();
232     } //-- getObject
233 
234     /**
235      * Signals the start of an element with the given name.
236      *
237      * @param name the NCName of the element. It is an error
238      * if the name is a QName (ie. contains a prefix).
239      * @param namespace the namespace of the element. This may be null.
240      * Note: A null namespace is not the same as the default namespace unless
241      * the default namespace is also null.
242      * @param atts the AttributeSet containing the attributes associated
243      * with the element.
244      * @param nsDecls the namespace declarations being declared for this
245      * element. This may be null.
246     **/
247     public void startElement(String name, String namespace, AttributeSet atts,
248         Namespaces nsDecls)
249         throws XMLException
250     {
251         //-- Do delagation if necessary
252         if (unmarshaller != null) {
253             unmarshaller.startElement(name, namespace, atts, nsDecls);
254             ++depth;
255             return;
256         }
257 
258         if (SchemaNames.ANNOTATION.equals(name)) {
259             if (foundElement || foundGroup ||foundModelGroup)
260                 error("An annotation may only appear as the first child "+
261                     "of an element definition.");
262 
263 
264             if (foundAnnotation)
265                 error("Only one (1) 'annotation' is allowed as a child of "+
266                     "element definitions.");
267 
268             foundAnnotation = true;
269             unmarshaller = new AnnotationUnmarshaller(getSchemaContext(), atts);
270         }
271         else if (SchemaNames.ELEMENT.equals(name)) {
272             foundElement = true;
273             unmarshaller
274                 = new ElementUnmarshaller(getSchemaContext(), _schema, atts);
275         }
276         //--group
277         else if (name.equals(SchemaNames.GROUP))
278         {
279             foundModelGroup = true;
280             unmarshaller
281                 = new ModelGroupUnmarshaller(getSchemaContext(), _schema, atts);
282         }
283 
284         //--all, sequence, choice
285         else if ( (SchemaNames.isGroupName(name)) && (name != SchemaNames.GROUP) )
286         {
287             foundGroup = true;
288             if (SchemaNames.ALL.equals(name))
289                foundAll = true;
290             unmarshaller
291                 = new GroupUnmarshaller(getSchemaContext(), _schema, name, atts);
292         }
293         //--any
294         else if (SchemaNames.ANY.equals(name)) {
295              if (foundAll)
296                 error("<any> can not appear as a child of a <all> element");
297              unmarshaller
298                  = new WildcardUnmarshaller(getSchemaContext(), _group, _schema, name, atts);
299         }
300 
301         else {
302             StringBuffer err = new StringBuffer("illegal element <");
303             err.append(name);
304             err.append("> found in <group>.");
305             throw new SchemaException(err.toString());
306         }
307 
308     } //-- startElement
309 
310     /**
311      * Signals to end of the element with the given name.
312      *
313      * @param name the NCName of the element. It is an error
314      * if the name is a QName (ie. contains a prefix).
315      * @param namespace the namespace of the element.
316     **/
317     public void endElement(String name, String namespace)
318         throws XMLException
319     {
320 
321         //-- Do delagation if necessary
322         if ((unmarshaller != null) && (depth > 0)) {
323             unmarshaller.endElement(name, namespace);
324             --depth;
325             return;
326         }
327         //-- check for name mismatches
328         if (unmarshaller != null) {
329             if (!name.equals(unmarshaller.elementName())) {
330                 String err = "missing end element for ";
331                 err += unmarshaller.elementName();
332                 throw new SchemaException(err);
333             }
334         }
335 
336         //-- have unmarshaller perform any necessary clean up
337         unmarshaller.finish();
338 
339          //-- <any>
340         if (SchemaNames.ANY.equals(name)) {
341            Wildcard wildcard =
342                  ((WildcardUnmarshaller)unmarshaller).getWildcard();
343             try {
344                 _group.addWildcard(wildcard);
345             } catch (SchemaException e) {
346                 throw new IllegalArgumentException(e.getMessage());
347             }
348         }
349         if (SchemaNames.ANNOTATION.equals(name)) {
350             Annotation ann = (Annotation)unmarshaller.getObject();
351             _group.addAnnotation(ann);
352         }
353         else if (SchemaNames.ELEMENT.equals(name)) {
354             ElementDecl element = (ElementDecl) unmarshaller.getObject();
355             _group.addElementDecl(element);
356         }
357         else if (name.equals(SchemaNames.GROUP)) {
358             ModelGroup group = (ModelGroup) unmarshaller.getObject();
359             _group.addGroup(group);
360         }
361         else if ( (SchemaNames.isGroupName(name)) && (name != SchemaNames.GROUP) )
362         {
363             Group group = ((GroupUnmarshaller)unmarshaller).getGroup();
364             _group.addGroup(group);
365         }
366 
367         unmarshaller = null;
368     } //-- endElement
369 
370     public void characters(char[] ch, int start, int length)
371         throws XMLException
372     {
373         //-- Do delagation if necessary
374         if (unmarshaller != null) {
375             unmarshaller.characters(ch, start, length);
376         }
377     } //-- characters
378 
379 } //-- GroupUnmarshaller