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  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.AttributeGroup;
53  import org.exolab.castor.xml.schema.ComplexType;
54  import org.exolab.castor.xml.schema.SchemaContext;
55  import org.exolab.castor.xml.schema.Group;
56  import org.exolab.castor.xml.schema.Schema;
57  import org.exolab.castor.xml.schema.SchemaException;
58  import org.exolab.castor.xml.schema.SchemaNames;
59  import org.exolab.castor.xml.schema.Wildcard;
60  
61  import java.util.StringTokenizer;
62  
63  /**
64   * A class for Unmarshalling WildCard
65   * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a>
66   * @version $Revision$ $Date: 2003-07-03 15:49:44 -0600 (Thu, 03 Jul 2003) $
67  **/
68  public class WildcardUnmarshaller extends ComponentReader {
69  
70  
71      /**
72       * The value of the maximum occurance wild card
73       */
74      private static final String MAX_OCCURS_WILDCARD = "unbounded";
75  
76  
77        //--------------------/
78       //- Member Variables -/
79      //--------------------/
80  
81      /**
82       * The current ComponentReader
83      **/
84      private ComponentReader unmarshaller;
85  
86      /**
87       * The current branch depth
88      **/
89      private int depth = 0;
90  
91      /**
92       * The wildcard we are constructing
93       */
94       private Wildcard _wildcard = null;
95      /**
96       * The Schema being "unmarshalled"
97      **/
98      private Schema _schema = null;
99  
100     /**
101      * The element name of the Group to be unmarshalled.
102      */
103     private String _element = SchemaNames.ANY;
104 
105 
106       //----------------/
107      //- Constructors -/
108     //----------------/
109     public WildcardUnmarshaller(
110             final SchemaContext schemaContext,
111             final ComplexType complexType, 
112             final Schema schema,
113             final String element,
114             final AttributeSet atts) {
115         this(schemaContext, schema, element, atts, new Wildcard(complexType));
116     }
117 
118     public WildcardUnmarshaller(
119             final SchemaContext schemaContext,
120             final Group group,
121             final Schema schema,
122             final String element,
123             final AttributeSet atts) {
124         this(schemaContext, schema, element, atts, new Wildcard(group));
125     }
126 
127     public WildcardUnmarshaller(
128             final SchemaContext schemaContext,
129             final AttributeGroup attGroup,
130             final Schema schema,
131             final String element,
132             final AttributeSet atts) {
133         this(schemaContext, schema, element, atts, new Wildcard(attGroup));
134     }
135 
136 
137     /**
138      * Creates a new WildcardUnmarshaller.
139      * @param schemaContext the {@link SchemaContext} to get some configuration settings from
140      * @param schema the Schema to which the {@link Wildcard} belongs
141      * @param element the name of the element
142      * @param atts the AttributeList
143     **/
144     private WildcardUnmarshaller(
145             final SchemaContext schemaContext,
146             final Schema schema, 
147             final String element, 
148             final AttributeSet atts,
149             final Wildcard wildcard) {
150         super(schemaContext);
151         _wildcard = wildcard;
152         this._schema = schema;
153         this._element = element;
154 
155         //-- handle attributes
156         String attValue = null;
157 
158         if (SchemaNames.ANY_ATTRIBUTE.equals(element))
159            _wildcard.setAttributeWildcard();
160         _element = element;
161 
162         //--namespace
163         attValue = atts.getValue(SchemaNames.NAMESPACE);
164 
165         if (attValue != null) {
166            // check if there is more than one namespace
167            StringTokenizer tokenizer = new StringTokenizer(attValue);
168            while (tokenizer.hasMoreTokens()) {
169                //need to retrieve all the namespaces
170                String temp = tokenizer.nextToken();
171                //if there is more than one namespace ##any or ##other should not
172                //appear
173                /**@todo optimize the following?*/
174                if (tokenizer.countTokens() >1 )
175                    if ( (SchemaNames.NAMESPACE_ANY.equals(temp)) ||
176                         (SchemaNames.NAMESPACE_OTHER.equals(temp)) )
177                         throw new IllegalArgumentException(temp+" is not valid when multiple namespaces are listed.");
178 
179                /**
180                 *@todo validation on the value of the attribute
181                 * we need a way to check the validity of an URI.
182                 * A temporary solution if to assume that the URI are URL.
183                 * @see SchemaNames#isNamespaceName()
184                 */
185                 if (SchemaNames.isNamespaceName(temp))
186                    _wildcard.addNamespace(temp);
187                 else {
188                      String err = "Invalid 'namespace' value: "+temp;
189                      throw new IllegalArgumentException(err);
190                 }
191            }
192          }//if
193          else _wildcard.addNamespace(SchemaNames.NAMESPACE_ANY);
194 
195         /*
196          * @maxOccurs
197          * If maxOccurs is present, the value is either unbounded
198          * or the int value of the attribute, otherwise maxOccurs
199          * equals the minOccurs value.
200          */
201         attValue = atts.getValue(SchemaNames.MAX_OCCURS_ATTR);
202         if (attValue != null) {
203             if (_wildcard.isAttributeWildcard())
204                 throw new IllegalStateException("'maxOccurs' is prohibited on a <anyAttribute> element.");
205             if (MAX_OCCURS_WILDCARD.equals(attValue)) attValue = "-1";
206             int maxOccurs = toInt(attValue);
207             _wildcard.setMaxOccurs(maxOccurs);
208         }
209         //-- minOccurs
210         attValue = atts.getValue("minOccurs");
211         if (attValue != null) {
212              if (_wildcard.isAttributeWildcard())
213                 throw new IllegalStateException("'minOccurs' is prohibited on a <anyAttribute> element.");
214             _wildcard.setMinOccurs(toInt(attValue));
215         }
216         //-- processContents
217         attValue = atts.getValue("processContents");
218 
219         if (attValue != null) {
220            try {
221                _wildcard.setProcessContents(attValue);
222            } catch (SchemaException e) {
223                throw new IllegalArgumentException(e.getMessage());
224            }
225         }
226 
227 
228         //-- id
229         _wildcard.setId(atts.getValue("id"));
230 
231     } //-- WildCardUnmarshaller
232 
233       //-----------/
234      //- Methods -/
235     //-----------/
236 
237      /**
238      * Returns the name of the element that this ComponentReader
239      * handles
240      * @return the name of the element that this ComponentReader
241      * handles
242     **/
243     public String elementName() {
244         return _element;
245     } //-- elementName
246 
247 
248     /**
249      * Returns the Wildcard unmarshalled by this Unmarshaller.
250      * @return the unmarshalled Wildcard
251      */
252     public Wildcard getWildcard() {
253         return _wildcard;
254     }
255     /**
256      * Returns the Object created by this ComponentReader
257      * @return the Object created by this ComponentReader
258     **/
259     public Object getObject() {
260         return getWildcard();
261     } //-- getObject
262 
263     /**
264      * Signals the start of an element with the given name.
265      *
266      * @param name the NCName of the element. It is an error
267      * if the name is a QName (ie. contains a prefix).
268      * @param namespace the namespace of the element. This may be null.
269      * Note: A null namespace is not the same as the default namespace unless
270      * the default namespace is also null.
271      * @param atts the AttributeSet containing the attributes associated
272      * with the element.
273      * @param nsDecls the namespace declarations being declared for this 
274      * element. This may be null.
275     **/
276     public void startElement(String name, String namespace, AttributeSet atts,
277         Namespaces nsDecls)
278         throws XMLException
279     {
280         //-- Do delagation if necessary
281         if (unmarshaller != null) {
282             unmarshaller.startElement(name, namespace, atts, nsDecls);
283             ++depth;
284             return;
285         }
286          //-- <annotation>
287         if (SchemaNames.ANNOTATION.equals(name)) {
288             unmarshaller = new AnnotationUnmarshaller(getSchemaContext(), atts);
289         }
290 
291         else {
292             StringBuffer err = new StringBuffer("illegal element <");
293             err.append(name);
294             err.append("> found in <");
295             err.append(_element);
296             err.append(">");
297             throw new SchemaException(err.toString());
298         }
299 
300     } //-- startElement
301 
302     /**
303      * Signals to end of the element with the given name.
304      *
305      * @param name the NCName of the element. It is an error
306      * if the name is a QName (ie. contains a prefix).
307      * @param namespace the namespace of the element.
308     **/
309     public void endElement(String name, String namespace)
310         throws XMLException
311     {
312 
313         //-- Do delagation if necessary
314         if ((unmarshaller != null) && (depth > 0)) {
315             unmarshaller.endElement(name, namespace);
316             --depth;
317             return;
318         }
319 
320         //-- check for name mismatches
321         if (unmarshaller != null) {
322             if (!name.equals(unmarshaller.elementName())) {
323                 String err = "missing end element for ";
324                 err += unmarshaller.elementName();
325                 throw new SchemaException(err);
326             }
327         }
328 
329         //-- have unmarshaller perform any necessary clean up
330         unmarshaller.finish();
331 
332         //-- <annotation>
333         if (name == SchemaNames.ANNOTATION) {
334             _schema.addAnnotation((Annotation)unmarshaller.getObject());
335         }
336         unmarshaller = null;
337     } //-- endElement
338 
339     public void characters(char[] ch, int start, int length)
340         throws XMLException
341     {
342         //-- Do delagation if necessary
343         if (unmarshaller != null) {
344             unmarshaller.characters(ch, start, length);
345         }
346     } //-- characters
347 
348 }