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