1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.axis2.schema;
21
22 import org.apache.axis2.namespace.Constants;
23 import org.apache.axis2.schema.i18n.SchemaCompilerMessages;
24 import org.apache.axis2.schema.util.PrimitiveTypeFinder;
25 import org.apache.axis2.schema.util.PrimitiveTypeWrapper;
26 import org.apache.axis2.schema.util.SchemaPropertyLoader;
27 import org.apache.axis2.schema.writer.BeanWriter;
28 import org.apache.axis2.util.SchemaUtil;
29 import org.apache.axis2.util.URLProcessor;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.ws.commons.schema.XmlSchema;
33 import org.apache.ws.commons.schema.XmlSchemaAll;
34 import org.apache.ws.commons.schema.XmlSchemaAny;
35 import org.apache.ws.commons.schema.XmlSchemaAnyAttribute;
36 import org.apache.ws.commons.schema.XmlSchemaAttribute;
37 import org.apache.ws.commons.schema.XmlSchemaAttributeGroup;
38 import org.apache.ws.commons.schema.XmlSchemaAttributeGroupRef;
39 import org.apache.ws.commons.schema.XmlSchemaChoice;
40 import org.apache.ws.commons.schema.XmlSchemaComplexContent;
41 import org.apache.ws.commons.schema.XmlSchemaComplexContentExtension;
42 import org.apache.ws.commons.schema.XmlSchemaComplexContentRestriction;
43 import org.apache.ws.commons.schema.XmlSchemaComplexType;
44 import org.apache.ws.commons.schema.XmlSchemaContent;
45 import org.apache.ws.commons.schema.XmlSchemaContentModel;
46 import org.apache.ws.commons.schema.XmlSchemaElement;
47 import org.apache.ws.commons.schema.XmlSchemaEnumerationFacet;
48 import org.apache.ws.commons.schema.XmlSchemaExternal;
49 import org.apache.ws.commons.schema.XmlSchemaGroup;
50 import org.apache.ws.commons.schema.XmlSchemaGroupBase;
51 import org.apache.ws.commons.schema.XmlSchemaGroupRef;
52 import org.apache.ws.commons.schema.XmlSchemaImport;
53 import org.apache.ws.commons.schema.XmlSchemaInclude;
54 import org.apache.ws.commons.schema.XmlSchemaLengthFacet;
55 import org.apache.ws.commons.schema.XmlSchemaMaxExclusiveFacet;
56 import org.apache.ws.commons.schema.XmlSchemaMaxInclusiveFacet;
57 import org.apache.ws.commons.schema.XmlSchemaMaxLengthFacet;
58 import org.apache.ws.commons.schema.XmlSchemaMinExclusiveFacet;
59 import org.apache.ws.commons.schema.XmlSchemaMinInclusiveFacet;
60 import org.apache.ws.commons.schema.XmlSchemaMinLengthFacet;
61 import org.apache.ws.commons.schema.XmlSchemaObject;
62 import org.apache.ws.commons.schema.XmlSchemaObjectCollection;
63 import org.apache.ws.commons.schema.XmlSchemaObjectTable;
64 import org.apache.ws.commons.schema.XmlSchemaParticle;
65 import org.apache.ws.commons.schema.XmlSchemaPatternFacet;
66 import org.apache.ws.commons.schema.XmlSchemaSequence;
67 import org.apache.ws.commons.schema.XmlSchemaSimpleContent;
68 import org.apache.ws.commons.schema.XmlSchemaSimpleContentExtension;
69 import org.apache.ws.commons.schema.XmlSchemaSimpleContentRestriction;
70 import org.apache.ws.commons.schema.XmlSchemaSimpleType;
71 import org.apache.ws.commons.schema.XmlSchemaSimpleTypeContent;
72 import org.apache.ws.commons.schema.XmlSchemaSimpleTypeList;
73 import org.apache.ws.commons.schema.XmlSchemaSimpleTypeRestriction;
74 import org.apache.ws.commons.schema.XmlSchemaSimpleTypeUnion;
75 import org.apache.ws.commons.schema.XmlSchemaType;
76
77 import javax.xml.namespace.QName;
78 import java.util.ArrayList;
79 import java.util.HashMap;
80 import java.util.HashSet;
81 import java.util.Iterator;
82 import java.util.LinkedHashMap;
83 import java.util.List;
84 import java.util.Map;
85 import java.util.Properties;
86
87 /**
88 * Schema compiler for ADB. Based on WS-Commons schema object model.
89 */
90 public class SchemaCompiler {
91
92 public static final int COMPONENT_TYPE = 1;
93 public static final int COMPONENT_ELEMENT = 2;
94 public static final int COMPONENT_ATTRIBUTE = 3;
95 public static final int COMPONENT_ATTRIBUTE_GROUP = 4;
96 public static final int COMPONENT_GROUP = 5;
97
98
99 private static final Log log = LogFactory.getLog(SchemaCompiler.class);
100
101 private CompilerOptions options;
102 private HashMap processedTypemap;
103 // have to keep a seperate group type map since same
104 // name can be used to group and complextype
105 private HashMap processedGroupTypeMap;
106
107 //the list of processedElements for the outer elements
108 private HashMap processedElementMap;
109
110 private HashMap processedAnonymousComplexTypesMap;
111
112 //we need this map to keep the referenced elements. these elements need to be kept seperate
113 //to avoid conflicts
114 private HashMap processedElementRefMap;
115 private HashMap simpleTypesMap;
116 private HashMap changedTypeMap;
117
118 private HashSet changedSimpleTypeSet;
119 private HashSet changedComplexTypeSet;
120 private HashSet changedElementSet;
121
122 // this map is necessary to retain the metainformation of types. The reason why these
123 // meta info 'bags' would be useful later is to cater for the extensions and restrictions
124 // of types
125 private HashMap processedTypeMetaInfoMap;
126
127 //
128 private ArrayList processedElementList;
129
130 //a list of nillable elements - used to generate code
131 //for nillable elements
132 private List nillableElementList;
133 // writee reference
134 private BeanWriter writer = null;
135 private Map baseSchemaTypeMap = null;
136
137 //a map for keeping the already loaded schemas
138 //the key is the targetnamespace and the value is the schema object
139 private Map loadedSchemaMap = new HashMap();
140
141 // A map keeping the available schemas
142 //the key is the targetnamespace and the value is the schema object
143 //this map will be populated when multiple schemas
144 //are fed to the schema compiler!
145 private Map availableSchemaMap = new HashMap();
146
147 private Map loadedSourceURI = new HashMap();
148
149 // a list of externally identified QNames to be processed. This becomes
150 // useful when only a list of external elements need to be processed
151
152 public static final String ANY_ELEMENT_FIELD_NAME = "extraElement";
153 public static final String EXTRA_ATTRIBUTE_FIELD_NAME = "extraAttributes";
154
155 public static final String USE_OPTIONAL = "optional";
156 public static final String USE_REQUIRED = "required";
157 public static final String USE_NONE = "none";
158
159 /**
160 * @return the processes element map
161 * includes the Qname of the element as the key and a
162 * String representing the fully qualified class name
163 */
164 public HashMap getProcessedElementMap() {
165 return processedElementMap;
166 }
167
168
169 /**
170 * @return a map of Qname vs models. A model can be anything,
171 * ranging from a DOM document to a stream. This is taken from the
172 * writer and the schema compiler has no control over it
173 */
174 public Map getProcessedModelMap() {
175 return writer.getModelMap();
176 }
177
178 /**
179 * Constructor - Accepts a options bean
180 *
181 * @param options
182 */
183 public SchemaCompiler(CompilerOptions options) throws SchemaCompilationException {
184
185 if (options == null) {
186 //create an empty options object
187 this.options = new CompilerOptions();
188 } else {
189 this.options = options;
190 }
191
192 //instantiate the maps
193 processedTypemap = new HashMap();
194 processedGroupTypeMap = new HashMap();
195
196 processedElementMap = new HashMap();
197 simpleTypesMap = new HashMap();
198 processedElementList = new ArrayList();
199 processedAnonymousComplexTypesMap = new HashMap();
200 changedTypeMap = new HashMap();
201 processedTypeMetaInfoMap = new HashMap();
202 processedElementRefMap = new HashMap();
203 nillableElementList = new ArrayList();
204
205 changedComplexTypeSet = new HashSet();
206 changedSimpleTypeSet = new HashSet();
207 changedElementSet = new HashSet();
208
209 //load the writer and initiliaze the base types
210 writer = SchemaPropertyLoader.getBeanWriterInstance();
211 writer.init(this.options);
212
213 //load the base types
214 baseSchemaTypeMap = SchemaPropertyLoader.getTypeMapperInstance().getTypeMap();
215 // adding all the soap encoding schema classes
216 processedTypemap.putAll(SchemaPropertyLoader.getTypeMapperInstance().getSoapEncodingTypesMap());
217
218
219 }
220
221 /**
222 * Compile a list of schemas
223 * This actually calls the compile (XmlSchema s) method repeatedly
224 *
225 * @param schemalist
226 * @throws SchemaCompilationException
227 * @see #compile(org.apache.ws.commons.schema.XmlSchema)
228 */
229 public void compile(List schemalist) throws SchemaCompilationException {
230 try {
231
232 if (schemalist.isEmpty()) {
233 return;
234 }
235
236 //clear the loaded and available maps
237 loadedSchemaMap.clear();
238 availableSchemaMap.clear();
239
240 XmlSchema schema;
241 // first round - populate the avaialble map
242 for (int i = 0; i < schemalist.size(); i++) {
243 schema = (XmlSchema) schemalist.get(i);
244 availableSchemaMap.put(
245 schema.getTargetNamespace(),
246 schema);
247 }
248
249 //set a mapper package if not avaialable
250 if (writer.getExtensionMapperPackageName() == null) {
251 String nsp = null;
252 //get the first schema from the list and take that namespace as the
253 //mapper namespace
254 for (int i = 0; nsp == null && i < schemalist.size(); i++) {
255 nsp = ((XmlSchema) schemalist.get(i)).getTargetNamespace();
256 if ((nsp != null) && !nsp.equals("")){
257 break;
258 }
259 XmlSchema[] schemas = SchemaUtil.getAllSchemas((XmlSchema) schemalist.get(i));
260 for (int j = 0; schemas != null && j < schemas.length; j++) {
261 nsp = schemas[j].getTargetNamespace();
262 if (nsp != null)
263 break;
264 }
265 }
266 if (nsp == null) {
267 nsp = URLProcessor.DEFAULT_PACKAGE;
268 }
269
270 // if this name space exists in the ns2p list then we use it.
271 if ((options.getNs2PackageMap() != null)
272 && (options.getNs2PackageMap().containsKey(nsp))) {
273 writer.registerExtensionMapperPackageName((String) options.getNs2PackageMap().get(nsp));
274 } else {
275 writer.registerExtensionMapperPackageName(URLProcessor.makePackageName(nsp));
276 }
277 }
278 // second round - call the schema compiler one by one
279 for (int i = 0; i < schemalist.size(); i++) {
280 compile((XmlSchema) schemalist.get(i), true);
281 }
282
283 //finish up
284 finalizeSchemaCompilation();
285
286 } catch (SchemaCompilationException e) {
287 throw e;
288 } catch (Exception e) {
289 throw new SchemaCompilationException(e);
290 }
291 }
292
293 /**
294 * Compile (rather codegen) a single schema element
295 *
296 * @param schema
297 * @throws SchemaCompilationException
298 */
299 public void compile(XmlSchema schema) throws SchemaCompilationException {
300 compile(schema, false);
301 }
302
303 /**
304 * Compile (rather codegen) a single schema element
305 *
306 * @param schema
307 * @param isPartofGroup
308 * @throws SchemaCompilationException
309 */
310 private void compile(XmlSchema schema, boolean isPartofGroup) throws SchemaCompilationException {
311
312 // some documents explicitly imports the schema of built in types. We don't actually need to compile
313 // the built-in types. So check the target namespace here and ignore it.
314 if (Constants.URI_2001_SCHEMA_XSD.equals(schema.getTargetNamespace())) {
315 return;
316 }
317
318 //register the package from this namespace as the mapper classes package
319 if (!isPartofGroup) {
320 //set a mapper package if not avaialable
321 if (writer.getExtensionMapperPackageName() == null) {
322 writer.registerExtensionMapperPackageName(
323 URLProcessor.makePackageName(schema.getTargetNamespace()));
324 }
325 }
326
327 //First look for the schemas that are imported and process them
328 //Note that these are processed recursively!
329
330 //add the schema to the loaded schema list
331 if (!loadedSchemaMap.containsKey(schema.getTargetNamespace())) {
332 loadedSchemaMap.put(schema.getTargetNamespace(), schema);
333 }
334
335 // If we have/are loading a schema with a specific targetnamespace from a certain URI,
336 // then just return back to the caller to avoid recursion.
337 if (schema.getSourceURI() != null) {
338 String key = schema.getTargetNamespace() + ":" + schema.getSourceURI();
339 if (loadedSourceURI.containsKey(key)) {
340 return;
341 }
342 loadedSourceURI.put(key, key);
343 }
344
345 XmlSchemaObjectCollection includes = schema.getIncludes();
346 if (includes != null) {
347 Iterator tempIterator = includes.getIterator();
348 while (tempIterator.hasNext()) {
349 Object o = tempIterator.next();
350 if (o instanceof XmlSchemaImport) {
351 XmlSchema schema1 = ((XmlSchemaImport) o).getSchema();
352 if (schema1 != null) compile(schema1, isPartofGroup);
353 }
354 if (o instanceof XmlSchemaInclude) {
355 XmlSchema schema1 = ((XmlSchemaInclude) o).getSchema();
356 if (schema1 != null) compile(schema1, isPartofGroup);
357 }
358 }
359 }
360
361 //select all the elements. We generate the code for types
362 //only if the elements refer them!!! regardless of the fact that
363 //we have a list of elementnames, we'll need to process all the elements
364 XmlSchemaObjectTable elements = schema.getElements();
365 Iterator xmlSchemaElement1Iterator = elements.getValues();
366 while (xmlSchemaElement1Iterator.hasNext()) {
367 //this is the set of outer elements so we need to generate classes
368 //The outermost elements do not contain occurence counts (!) so we do not need
369 //to check for arraytypes
370 processElement((XmlSchemaElement) xmlSchemaElement1Iterator.next(), schema);
371 }
372
373 Iterator xmlSchemaElement2Iterator = elements.getValues();
374
375 // re-iterate through the elements and write them one by one
376 // if the mode is unpack this process will not really write the
377 // classes but will accumilate the models for a final single shot
378 // write
379 while (xmlSchemaElement2Iterator.hasNext()) {
380 //this is the set of outer elements so we need to generate classes
381 writeElement((XmlSchemaElement) xmlSchemaElement2Iterator.next());
382 }
383
384 if (options.isGenerateAll()) {
385 Iterator xmlSchemaTypes2Iterator = schema.getSchemaTypes().getValues();
386 while (xmlSchemaTypes2Iterator.hasNext()) {
387 XmlSchemaType schemaType = (XmlSchemaType) xmlSchemaTypes2Iterator.next();
388 if (this.isAlreadyProcessed(schemaType.getQName())) {
389 continue;
390 }
391 if (schemaType instanceof XmlSchemaComplexType) {
392 //write classes for complex types
393 XmlSchemaComplexType complexType = (XmlSchemaComplexType) schemaType;
394 if (complexType.getName() != null) {
395 processNamedComplexSchemaType(complexType, schema);
396 }
397 } else if (schemaType instanceof XmlSchemaSimpleType) {
398 //process simple type
399 processSimpleSchemaType((XmlSchemaSimpleType) schemaType,
400 null,
401 schema, null);
402 }
403 }
404 }
405
406 if (!isPartofGroup) {
407 //complete the compilation
408 finalizeSchemaCompilation();
409 }
410 }
411
412 /**
413 * Completes the schema compilation process by writing the
414 * mappers and the classes in a batch if needed
415 *
416 * @throws SchemaCompilationException
417 */
418 private void finalizeSchemaCompilation() throws SchemaCompilationException {
419 //write the extension mapping class
420 writer.writeExtensionMapper(
421 (BeanWriterMetaInfoHolder[])
422 processedTypeMetaInfoMap.values().toArray(
423 new BeanWriterMetaInfoHolder[processedTypeMetaInfoMap.size()]));
424
425
426 if (options.isWrapClasses()) {
427 writer.writeBatch();
428 }
429
430 // resets the changed types
431 XmlSchemaComplexType xmlSchemaComplexType = null;
432 for (Iterator iter = changedComplexTypeSet.iterator();iter.hasNext();){
433 xmlSchemaComplexType = (XmlSchemaComplexType) iter.next();
434 xmlSchemaComplexType.setName(null);
435 }
436
437 XmlSchemaSimpleType xmlSchemaSimpleType = null;
438 for (Iterator iter = changedSimpleTypeSet.iterator();iter.hasNext();){
439 xmlSchemaSimpleType = (XmlSchemaSimpleType) iter.next();
440 xmlSchemaSimpleType.setName(null);
441 }
442
443 XmlSchemaElement xmlSchemaElement = null;
444 for (Iterator iter = changedElementSet.iterator();iter.hasNext();){
445 xmlSchemaElement = (XmlSchemaElement) iter.next();
446 xmlSchemaElement.setSchemaTypeName(null);
447 }
448
449 }
450
451 /**
452 * @return the property map of the schemacompiler.
453 * In this case it would be the property map loaded from
454 * the configuration file
455 */
456 public Properties getCompilerProperties() {
457 return SchemaPropertyLoader.getPropertyMap();
458 }
459
460
461 /**
462 * Writes the element
463 *
464 * @param xsElt
465 * @throws SchemaCompilationException
466 */
467 private void writeElement(XmlSchemaElement xsElt) throws SchemaCompilationException {
468
469 if (this.processedElementMap.containsKey(xsElt.getQName())) {
470 return;
471 }
472
473 XmlSchemaType schemaType = xsElt.getSchemaType();
474
475 BeanWriterMetaInfoHolder metainf = new BeanWriterMetaInfoHolder();
476 if (schemaType != null && schemaType.getName() != null) {
477 //this is a named type
478 QName qName = schemaType.getQName();
479 //find the class name
480 String className = findClassName(qName, isArray(xsElt));
481
482 //this means the schema type actually returns a different QName
483 if (changedTypeMap.containsKey(qName)) {
484 metainf.registerMapping(xsElt.getQName(),
485 (QName) changedTypeMap.get(qName),
486 className);
487 } else {
488 metainf.registerMapping(xsElt.getQName(),
489 qName,
490 className);
491 }
492
493 // register the default value if present
494 if (xsElt.getDefaultValue() != null){
495 metainf.registerDefaultValue(xsElt.getQName(),xsElt.getDefaultValue());
496 }
497
498 if (isBinary(xsElt)) {
499 metainf.addtStatus(xsElt.getQName(),
500 SchemaConstants.BINARY_TYPE);
501 }
502
503 } else if (xsElt.getRefName() != null) {
504 // Since top level elements would not have references
505 // and we only write toplevel elements, this should
506 // not be a problem , atleast should not occur in a legal schema
507 } else if (xsElt.getSchemaTypeName() != null) {
508 QName qName = xsElt.getSchemaTypeName();
509 String className = findClassName(qName, isArray(xsElt));
510 metainf.registerMapping(xsElt.getQName(),
511 qName,
512 className);
513
514
515 } else if (schemaType != null) { //the named type should have been handled already
516
517 //we are going to special case the anonymous complex type. Our algorithm for dealing
518 //with it is to generate a single object that has the complex content inside. Really the
519 //intent of the user when he declares the complexType anonymously is to use it privately
520 //First copy the schema types content into the metainf holder
521 metainf = (BeanWriterMetaInfoHolder) this.processedAnonymousComplexTypesMap.get(xsElt);
522 metainf.setAnonymous(true);
523 } else {
524 //this means we did not find any schema type associated with the particular element.
525 log.warn(SchemaCompilerMessages.getMessage("schema.elementWithNoType", xsElt.getQName().toString()));
526 metainf.registerMapping(xsElt.getQName(),
527 null,
528 writer.getDefaultClassName(),
529 SchemaConstants.ANY_TYPE);
530 }
531
532 if (nillableElementList.contains(xsElt.getQName())) {
533 metainf.registerNillableQName(xsElt.getQName());
534 }
535
536
537 String writtenClassName = writer.write(xsElt, processedTypemap, processedGroupTypeMap, metainf);
538 //register the class name
539 xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, writtenClassName);
540 processedElementMap.put(xsElt.getQName(), writtenClassName);
541 }
542
543 /**
544 * For inner elements
545 *
546 * @param xsElt
547 * @param innerElementMap
548 * @param parentSchema
549 * @throws SchemaCompilationException
550 */
551 private void processElement(XmlSchemaElement xsElt, Map innerElementMap, List localNillableList, XmlSchema parentSchema) throws SchemaCompilationException {
552 processElement(xsElt, false, innerElementMap, localNillableList, parentSchema);
553 }
554
555 /**
556 * For outer elements
557 *
558 * @param xsElt
559 * @param parentSchema
560 * @throws SchemaCompilationException
561 */
562 private void processElement(XmlSchemaElement xsElt, XmlSchema parentSchema) throws SchemaCompilationException {
563 processElement(xsElt, true, null, null, parentSchema);
564 }
565
566 /**
567 * Process and Element
568 *
569 * @param xsElt
570 * @param isOuter We need to know this since the treatment of outer elements is different that
571 * inner elements
572 * @throws SchemaCompilationException
573 */
574 private void processElement(XmlSchemaElement xsElt, boolean isOuter, Map innerElementMap, List localNillableList, XmlSchema parentSchema) throws SchemaCompilationException {
575
576 //if the element is null, which usually happens when the qname is not
577 //proper, throw an exceptions
578 if (xsElt == null) {
579 throw new SchemaCompilationException(
580 SchemaCompilerMessages.getMessage("schema.elementNull"));
581 }
582
583 //The processing element logic seems to be quite simple. Look at the relevant schema type
584 //for each and every element and process that accordingly.
585 //this means that any unused type definitions would not be generated!
586 if (isOuter && processedElementList.contains(xsElt.getQName())) {
587 return;
588 }
589
590 XmlSchemaType schemaType = xsElt.getSchemaType();
591 if (schemaType != null) {
592 processSchema(xsElt, schemaType, parentSchema, false);
593 //at this time it is not wise to directly write the class for the element
594 //so we push the complete element to an arraylist and let the process
595 //pass through. We'll be iterating through the elements writing them
596 //later
597
598 if (!isOuter) {
599 if (schemaType.getName() != null) {
600 // this element already has a name. Which means we can directly
601 // register it
602 String className = findClassName(schemaType.getQName(),
603 isArray(xsElt));
604
605 innerElementMap.put(xsElt.getQName(), className);
606
607 // always store the class name in the element meta Info itself
608 // this details only needed by the unwrappig to set the complex type
609 if (options.isUseWrapperClasses() &&
610 PrimitiveTypeFinder.isPrimitive(className) &&
611 ((xsElt.getMinOccurs() == 0) || (xsElt.isNillable()))) {
612 className = PrimitiveTypeWrapper.getWrapper(className);
613 }
614 schemaType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, className);
615 xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, className);
616
617 if (baseSchemaTypeMap.containsValue(className)) {
618 schemaType.addMetaInfo(
619 SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_PRIMITVE_KEY,
620 Boolean.TRUE);
621 }
622 //since this is a inner element we should add it to the inner element map
623 } else {
624 //this is an anon type. This should have been already processed and registered at
625 //the anon map. we've to write it just like we treat a referenced type(giving due
626 //care that this is meant to be an attribute in some class)
627
628 QName generatedTypeName = generateTypeQName(xsElt.getQName(), parentSchema);
629
630 if (schemaType instanceof XmlSchemaComplexType) {
631 //set a name
632 schemaType.setName(generatedTypeName.getLocalPart());
633 changedComplexTypeSet.add(schemaType);
634 // Must do this up front to support recursive types
635 String fullyQualifiedClassName = writer.makeFullyQualifiedClassName(schemaType.getQName());
636 processedTypemap.put(schemaType.getQName(), fullyQualifiedClassName);
637
638 BeanWriterMetaInfoHolder metaInfHolder = (BeanWriterMetaInfoHolder) processedAnonymousComplexTypesMap.get(xsElt);
639 metaInfHolder.setOwnQname(schemaType.getQName());
640 metaInfHolder.setOwnClassName(fullyQualifiedClassName);
641
642 writeComplexType((XmlSchemaComplexType) schemaType,
643 metaInfHolder);
644 //remove the reference from the anon list since we named the type
645 processedAnonymousComplexTypesMap.remove(xsElt);
646 String className = findClassName(schemaType.getQName(), isArray(xsElt));
647 innerElementMap.put(
648 xsElt.getQName(),
649 className);
650
651 //store in the schema map to retrive in the unwrapping
652 xsElt.addMetaInfo(
653 SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
654 className);
655 } else if (schemaType instanceof XmlSchemaSimpleType) {
656 //set a name
657 schemaType.setName(generatedTypeName.getLocalPart());
658 changedSimpleTypeSet.add(schemaType);
659 // Must do this up front to support recursive types
660 String fullyQualifiedClassName = writer.makeFullyQualifiedClassName(schemaType.getQName());
661 processedTypemap.put(schemaType.getQName(), fullyQualifiedClassName);
662
663 BeanWriterMetaInfoHolder metaInfHolder = (BeanWriterMetaInfoHolder) processedAnonymousComplexTypesMap.get(xsElt);
664 metaInfHolder.setOwnQname(schemaType.getQName());
665 metaInfHolder.setOwnClassName(fullyQualifiedClassName);
666
667 writeSimpleType((XmlSchemaSimpleType) schemaType,
668 metaInfHolder);
669 //remove the reference from the anon list since we named the type
670 processedAnonymousComplexTypesMap.remove(xsElt);
671 String className = findClassName(schemaType.getQName(), isArray(xsElt));
672 innerElementMap.put(
673 xsElt.getQName(),
674 className);
675
676 //store in the schema map
677 xsElt.addMetaInfo(
678 SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
679 className);
680 }
681 }
682 } else {
683 // set the binary status of this element
684 this.processedElementList.add(xsElt.getQName());
685 }
686 //referenced name
687 } else if (xsElt.getRefName() != null) {
688
689 if (xsElt.getRefName().equals(SchemaConstants.XSD_SCHEMA)) {
690 innerElementMap.put(xsElt.getQName(), writer.getDefaultClassName());
691 return;
692 }
693 //process the referenced type. It could be thought that the referenced element replaces this
694 //element
695 XmlSchema resolvedSchema = getParentSchema(parentSchema,xsElt.getRefName(),COMPONENT_ELEMENT);
696 if (resolvedSchema == null){
697 throw new SchemaCompilationException("can not find the element " + xsElt.getRefName()
698 + " from the parent schema " + parentSchema.getTargetNamespace());
699 }
700 XmlSchemaElement referencedElement = resolvedSchema.getElementByName(xsElt.getRefName());
701 if (referencedElement == null) {
702 throw new SchemaCompilationException(
703 SchemaCompilerMessages.getMessage("schema.referencedElementNotFound", xsElt.getRefName().toString()));
704 }
705
706 // here what we want is to set the schema type name for the element
707 if ((referencedElement.getSchemaType() != null)
708 && (referencedElement.getSchemaType().getQName() != null)){
709 // i.e this element refers to an complex type name
710 if (!this.processedElementRefMap.containsKey(referencedElement.getQName())) {
711 if (this.baseSchemaTypeMap.containsKey(referencedElement.getSchemaTypeName())) {
712 this.processedElementRefMap.put(referencedElement.getQName(),
713 this.baseSchemaTypeMap.get(referencedElement.getSchemaTypeName()));
714 } else {
715 XmlSchema resolvedTypeSchema = getParentSchema(resolvedSchema,
716 referencedElement.getSchemaTypeName(),
717 COMPONENT_TYPE);
718 XmlSchemaType xmlSchemaType = resolvedTypeSchema.getTypeByName(
719 referencedElement.getSchemaTypeName().getLocalPart());
720 processSchema(referencedElement, xmlSchemaType, resolvedTypeSchema, true);
721 this.processedElementRefMap.put(referencedElement.getQName(),
722 this.processedTypemap.get(referencedElement.getSchemaTypeName()));
723 }
724 }
725 String javaClassName;
726 if (this.baseSchemaTypeMap.containsKey(referencedElement.getSchemaTypeName())) {
727 // here we have to do nothing since we do not generate a name
728 } else {
729 javaClassName = (String) this.processedTypemap.get(referencedElement.getSchemaTypeName());
730 referencedElement.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
731 javaClassName);
732 xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
733 javaClassName);
734 }
735 } else if (referencedElement.getSchemaType() != null) {
736 if (!this.processedElementRefMap.containsKey(referencedElement.getQName())) {
737
738 processSchema(referencedElement, referencedElement.getSchemaType(), resolvedSchema, true);
739 // if this is an anonomous complex type we have to set this
740 this.processedElementRefMap.put(referencedElement.getQName(),
741 this.processedTypemap.get(referencedElement.getSchemaTypeName()));
742
743 }
744
745 String javaClassName = (String) this.processedTypemap.get(referencedElement.getSchemaTypeName());
746 referencedElement.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
747 javaClassName);
748 xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
749 javaClassName);
750 }
751
752 // schema type name is present but not the schema type object
753 } else if (xsElt.getSchemaTypeName() != null) {
754 //There can be instances where the SchemaType is null but the schemaTypeName is not!
755 //this specifically happens with xsd:anyType.
756 QName schemaTypeName = xsElt.getSchemaTypeName();
757
758 XmlSchema resolvedSchema = getParentSchema(parentSchema,schemaTypeName,COMPONENT_TYPE);
759 XmlSchemaType typeByName = null;
760 if (resolvedSchema != null){
761 typeByName = resolvedSchema.getTypeByName(schemaTypeName);
762 }
763
764 if (typeByName != null) {
765 //this type is found in the schema so we can process it
766 processSchema(xsElt, typeByName, resolvedSchema, false);
767 if (!isOuter) {
768 String className = findClassName(schemaTypeName, isArray(xsElt));
769 //since this is a inner element we should add it to the inner element map
770 innerElementMap.put(xsElt.getQName(), className);
771 // set the class name to be used in unwrapping
772 xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
773 className);
774 } else {
775 this.processedElementList.add(xsElt.getQName());
776 }
777 } else {
778 //this type is not found at all. we'll just register it with whatever the class name we can comeup with
779 if (!isOuter) {
780 String className = findClassName(schemaTypeName, isArray(xsElt));
781 innerElementMap.put(xsElt.getQName(), className);
782 // set the class name to be used in unwrapping
783 xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
784 className);
785 } else {
786 this.processedElementList.add(xsElt.getQName());
787 }
788 }
789 }
790
791 //add this elements QName to the nillable group if it has the nillable attribute
792 if (xsElt.isNillable()) {
793 if (isOuter) {
794 this.nillableElementList.add(xsElt.getQName());
795 } else {
796 localNillableList.add(xsElt.getQName());
797 }
798 }
799
800 }
801
802 /**
803 * Generate a unique type Qname using an element name
804 *
805 * @param referenceEltQName
806 * @param parentSchema
807 */
808 private QName generateTypeQName(QName referenceEltQName, XmlSchema parentSchema) {
809 QName generatedTypeName = new QName(referenceEltQName.getNamespaceURI(),
810 referenceEltQName.getLocalPart() + getNextTypeSuffix(referenceEltQName.getLocalPart()));
811 while (parentSchema.getTypeByName(generatedTypeName) != null) {
812 generatedTypeName = new QName(referenceEltQName.getNamespaceURI(),
813 referenceEltQName.getLocalPart() + getNextTypeSuffix(referenceEltQName.getLocalPart()));
814 }
815 return generatedTypeName;
816 }
817
818 /**
819 * Finds whether a given class is already made
820 *
821 * @param qName
822 */
823 private boolean isAlreadyProcessed(QName qName) {
824 return processedTypemap.containsKey(qName) ||
825 simpleTypesMap.containsKey(qName) ||
826 baseSchemaTypeMap.containsKey(qName) ||
827 processedGroupTypeMap.containsKey(qName);
828 }
829
830
831 /**
832 * A method to pick the ref class name
833 *
834 * @param name
835 * @param isArray
836 */
837 private String findRefClassName(QName name, boolean isArray) {
838 String className = null;
839 if (processedElementRefMap.get(name) != null) {
840 className = (String) processedElementRefMap.get(name);
841
842 if (isArray) {
843 //append the square braces that say this is an array
844 //hope this works for all cases!!!!!!!
845 //todo this however is a thing that needs to be
846 //todo fixed to get complete language support
847 className = className + "[]";
848 }
849 }
850 return className;
851
852 }
853
854 /**
855 * Finds a class name from the given Qname
856 *
857 * @param qName
858 * @param isArray
859 * @return FQCN
860 */
861 private String findClassName(QName qName, boolean isArray) throws SchemaCompilationException {
862
863 //find the class name
864 String className;
865 if (processedTypemap.containsKey(qName)) {
866 className = (String) processedTypemap.get(qName);
867 } else if (simpleTypesMap.containsKey(qName)) {
868 className = (String) simpleTypesMap.get(qName);
869 } else if (baseSchemaTypeMap.containsKey(qName)) {
870 className = (String) baseSchemaTypeMap.get(qName);
871 } else {
872 if (isSOAP_ENC(qName.getNamespaceURI())) {
873 throw new SchemaCompilationException(SchemaCompilerMessages.getMessage("schema.soapencoding.error", qName.toString()));
874
875 }
876 // We seem to have failed in finding a class name for the
877 //contained schema type. We better set the default then
878 //however it's better if the default can be set through the
879 //property file
880 className = writer.getDefaultClassName();
881 log.warn(SchemaCompilerMessages
882 .getMessage("schema.typeMissing", qName.toString()));
883 }
884
885 if (isArray) {
886 //append the square braces that say this is an array
887 //hope this works for all cases!!!!!!!
888 //todo this however is a thing that needs to be
889 //todo fixed to get complete language support
890 className = className + "[]";
891 }
892 return className;
893 }
894
895 /**
896 * Returns true if SOAP_ENC Namespace.
897 *
898 * @param s a string representing the URI to check
899 * @return true if <code>s</code> matches a SOAP ENCODING namespace URI,
900 * false otherwise
901 */
902 public static boolean isSOAP_ENC(String s) {
903 if (s.equals(Constants.URI_SOAP11_ENC))
904 return true;
905 return s.equals(Constants.URI_SOAP12_ENC);
906 }
907
908 /**
909 * Process a schema element which has been refered to by an element
910 *
911 * @param schemaType
912 * @throws SchemaCompilationException
913 */
914 private void processSchema(XmlSchemaElement xsElt,
915 XmlSchemaType schemaType,
916 XmlSchema parentSchema,
917 boolean isWriteAnonComplexType) throws SchemaCompilationException {
918 if (schemaType instanceof XmlSchemaComplexType) {
919 //write classes for complex types
920 XmlSchemaComplexType complexType = (XmlSchemaComplexType) schemaType;
921 // complex type name may not be null if we have set it
922 if (complexType.getName() != null && !this.changedComplexTypeSet.contains(schemaType)) {
923 // here complex type may be in another shcema so we have to find the
924 // correct parent schema.
925 XmlSchema resolvedSchema = getParentSchema(parentSchema,complexType.getQName(),COMPONENT_TYPE);
926 if (resolvedSchema == null){
927 throw new SchemaCompilationException("can not find the parent schema for the " +
928 "complex type " + complexType.getQName() + " from the parent schema " +
929 parentSchema.getTargetNamespace());
930 } else {
931 processNamedComplexSchemaType(complexType, resolvedSchema);
932 }
933 } else {
934 processAnonymousComplexSchemaType(xsElt, complexType, parentSchema, isWriteAnonComplexType);
935 }
936 } else if (schemaType instanceof XmlSchemaSimpleType) {
937 //process simple type
938 processSimpleSchemaType((XmlSchemaSimpleType) schemaType,
939 xsElt,
940 parentSchema, null);
941 }
942 }
943
944
945 /**
946 * @param complexType
947 * @throws SchemaCompilationException
948 */
949 private void processAnonymousComplexSchemaType(XmlSchemaElement elt,
950 XmlSchemaComplexType complexType,
951 XmlSchema parentSchema,
952 boolean isWriteAnonComplexType)
953 throws SchemaCompilationException {
954
955 //here we have a problem when processing the circulare element
956 // references if we differ this processing
957 // generate a name to the complex type and register it here
958 QName generatedTypeName = null;
959 String javaClassName = null;
960 if (isWriteAnonComplexType) {
961
962 generatedTypeName = generateTypeQName(elt.getQName(), parentSchema);
963
964 if (elt.getSchemaTypeName() == null) {
965 elt.setSchemaTypeName(generatedTypeName);
966 this.changedElementSet.add(elt);
967 }
968
969 //set a name
970 complexType.setName(generatedTypeName.getLocalPart());
971 this.changedComplexTypeSet.add(complexType);
972
973 javaClassName = writer.makeFullyQualifiedClassName(generatedTypeName);
974 processedTypemap.put(generatedTypeName, javaClassName);
975 this.processedElementRefMap.put(elt.getQName(), javaClassName);
976 complexType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, javaClassName);
977 }
978
979
980 BeanWriterMetaInfoHolder metaInfHolder = processComplexType(elt.getQName(),complexType, parentSchema);
981
982 // here the only difference is that we generate the class
983 // irrespective of where we need it or not
984 if (isWriteAnonComplexType) {
985 metaInfHolder.setOwnClassName(javaClassName);
986 metaInfHolder.setOwnQname(generatedTypeName);
987 writeComplexType(complexType, metaInfHolder);
988 }
989
990 //since this is a special case (an unnamed complex type) we'll put the already processed
991 //metainf holder in a special map to be used later
992 this.processedAnonymousComplexTypesMap.put(elt, metaInfHolder);
993
994 }
995
996 /**
997 * handle the complex types which are named
998 *
999 * @param complexType
1000 */
1001 private void processNamedComplexSchemaType(XmlSchemaComplexType complexType,
1002 XmlSchema parentSchema) throws SchemaCompilationException {
1003
1004 if (processedTypemap.containsKey(complexType.getQName())
1005 || baseSchemaTypeMap.containsKey(complexType.getQName())) {
1006 return;
1007 }
1008
1009 // Must do this up front to support recursive types
1010 String fullyQualifiedClassName = writer.makeFullyQualifiedClassName(complexType.getQName());
1011 processedTypemap.put(complexType.getQName(), fullyQualifiedClassName);
1012
1013 //register that in the schema metainfo bag
1014 complexType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
1015 fullyQualifiedClassName);
1016
1017 BeanWriterMetaInfoHolder metaInfHolder = processComplexType(complexType.getQName(),complexType, parentSchema);
1018 //add this information to the metainfo holder
1019 metaInfHolder.setOwnQname(complexType.getQName());
1020 metaInfHolder.setOwnClassName(fullyQualifiedClassName);
1021 //write the class. This type mapping would have been populated right now
1022 //Note - We always write classes for named complex types
1023 writeComplexType(complexType, metaInfHolder);
1024
1025
1026 }
1027
1028 /**
1029 * Writes a complex type
1030 *
1031 * @param complexType
1032 * @param metaInfHolder
1033 * @throws SchemaCompilationException
1034 */
1035 private String writeComplexType(XmlSchemaComplexType complexType, BeanWriterMetaInfoHolder metaInfHolder)
1036 throws SchemaCompilationException {
1037 String javaClassName = writer.write(complexType.getQName(),
1038 processedTypemap, processedGroupTypeMap, metaInfHolder, complexType.isAbstract());
1039 processedTypeMetaInfoMap.put(complexType.getQName(), metaInfHolder);
1040 return javaClassName;
1041 }
1042
1043
1044 /**
1045 * Writes complex Sequence,Choice, all elements
1046 * @param qname complex type qname
1047 * @param metaInfHolder
1048 * @return written java class name
1049 * @throws SchemaCompilationException
1050 */
1051
1052
1053 private String writeComplexParticle(QName qname,BeanWriterMetaInfoHolder metaInfHolder)
1054 throws SchemaCompilationException {
1055 String javaClassName = writer.write(qname, processedTypemap, processedGroupTypeMap, metaInfHolder,false);
1056 processedTypeMetaInfoMap.put(qname, metaInfHolder);
1057 return javaClassName;
1058 }
1059
1060 /**
1061 * Writes a complex type
1062 *
1063 * @param simpleType
1064 * @param metaInfHolder
1065 * @throws SchemaCompilationException
1066 */
1067 private void writeSimpleType(XmlSchemaSimpleType simpleType, BeanWriterMetaInfoHolder metaInfHolder)
1068 throws SchemaCompilationException {
1069 writer.write(simpleType, processedTypemap, processedGroupTypeMap, metaInfHolder);
1070 processedTypeMetaInfoMap.put(simpleType.getQName(), metaInfHolder);
1071 }
1072
1073 private BeanWriterMetaInfoHolder processComplexType(
1074 QName parentElementQName,
1075 XmlSchemaComplexType complexType,
1076 XmlSchema parentSchema) throws SchemaCompilationException {
1077 XmlSchemaParticle particle = complexType.getParticle();
1078 BeanWriterMetaInfoHolder metaInfHolder = new BeanWriterMetaInfoHolder();
1079 if (particle != null) {
1080 //Process the particle
1081 processParticle(parentElementQName, particle, metaInfHolder, parentSchema);
1082 }
1083
1084 //process attributes - first look for the explicit attributes
1085 processAttributes(complexType.getAttributes(),metaInfHolder,parentSchema);
1086
1087 //process any attribute
1088 //somehow the xml schema parser does not seem to pickup the any attribute!!
1089 XmlSchemaAnyAttribute anyAtt = complexType.getAnyAttribute();
1090 if (anyAtt != null) {
1091 processAnyAttribute(metaInfHolder, anyAtt);
1092 }
1093
1094
1095 //process content ,either complex or simple
1096 if (complexType.getContentModel() != null) {
1097 processContentModel(complexType.getContentModel(),
1098 metaInfHolder,
1099 parentSchema);
1100 }
1101 return metaInfHolder;
1102 }
1103
1104 private void processAttributes(XmlSchemaObjectCollection attributes,
1105 BeanWriterMetaInfoHolder metaInfHolder,
1106 XmlSchema parentSchema) throws SchemaCompilationException {
1107 Iterator attribIterator = attributes.getIterator();
1108 while (attribIterator.hasNext()) {
1109 Object o = attribIterator.next();
1110 if (o instanceof XmlSchemaAttribute) {
1111 processAttribute((XmlSchemaAttribute) o, metaInfHolder, parentSchema);
1112 } else if (o instanceof XmlSchemaAttributeGroupRef){
1113 processAttributeGroupReference((XmlSchemaAttributeGroupRef)o,metaInfHolder,parentSchema);
1114 }
1115 }
1116 }
1117
1118 private void processAttributeGroupReference(XmlSchemaAttributeGroupRef attributeGroupRef,
1119 BeanWriterMetaInfoHolder metaInfHolder,
1120 XmlSchema parentSchema) throws SchemaCompilationException {
1121
1122 QName attributeGroupRefName = attributeGroupRef.getRefName();
1123 if (attributeGroupRefName != null){
1124 XmlSchema resolvedSchema = getParentSchema(parentSchema,attributeGroupRefName,COMPONENT_ATTRIBUTE_GROUP);
1125 if (resolvedSchema == null) {
1126 throw new SchemaCompilationException("can not find the attribute group reference name " +
1127 attributeGroupRefName + " from the parent schema " + parentSchema.getTargetNamespace());
1128 } else {
1129 XmlSchemaAttributeGroup xmlSchemaAttributeGroup =
1130 (XmlSchemaAttributeGroup) resolvedSchema.getAttributeGroups().getItem(attributeGroupRefName);
1131 if (xmlSchemaAttributeGroup != null) {
1132 processAttributes(xmlSchemaAttributeGroup.getAttributes(), metaInfHolder, resolvedSchema);
1133 } else {
1134 throw new SchemaCompilationException("Can not find an attribute group for group reference "
1135 + attributeGroupRefName.getLocalPart());
1136 }
1137 }
1138
1139 } else {
1140 throw new SchemaCompilationException("No group refernce has given");
1141 }
1142 }
1143
1144 /**
1145 * Process the content models. A content model is either simple type or a complex type
1146 * and included inside a complex content
1147 */
1148 private void processContentModel(XmlSchemaContentModel content,
1149 BeanWriterMetaInfoHolder metaInfHolder,
1150 XmlSchema parentSchema)
1151 throws SchemaCompilationException {
1152 if (content instanceof XmlSchemaComplexContent) {
1153 processComplexContent((XmlSchemaComplexContent) content, metaInfHolder, parentSchema);
1154 } else if (content instanceof XmlSchemaSimpleContent) {
1155 processSimpleContent((XmlSchemaSimpleContent) content, metaInfHolder, parentSchema);
1156 }
1157 }
1158
1159 /**
1160 * Prcess the complex content
1161 */
1162 private void processComplexContent(XmlSchemaComplexContent complexContent,
1163 BeanWriterMetaInfoHolder metaInfHolder,
1164 XmlSchema parentSchema)
1165 throws SchemaCompilationException {
1166 XmlSchemaContent content = complexContent.getContent();
1167
1168 if (content instanceof XmlSchemaComplexContentExtension) {
1169
1170 // to handle extension we need to attach the extended items to the base type
1171 // and create a new type
1172 XmlSchemaComplexContentExtension extension = (XmlSchemaComplexContentExtension)content;
1173
1174 //process the base type if it has not been processed yet
1175 if (!isAlreadyProcessed(extension.getBaseTypeName())) {
1176 //pick the relevant basetype from the schema and process it
1177 XmlSchema resolvedSchema = getParentSchema(parentSchema, extension.getBaseTypeName(), COMPONENT_TYPE);
1178 if (resolvedSchema == null) {
1179 throw new SchemaCompilationException("can not find the compley type " + extension.getBaseTypeName()
1180 + " from the parent type " + parentSchema.getTargetNamespace());
1181 } else {
1182 XmlSchemaType type = resolvedSchema.getTypeByName(extension.getBaseTypeName());
1183 if (type instanceof XmlSchemaComplexType) {
1184 XmlSchemaComplexType complexType = (XmlSchemaComplexType) type;
1185 if (complexType.getName() != null) {
1186 processNamedComplexSchemaType(complexType, resolvedSchema);
1187 } else {
1188 //this is not possible. The extension should always
1189 //have a name
1190 throw new SchemaCompilationException("Unnamed complex type used in extension");//Internationlize this
1191 }
1192 } else if (type instanceof XmlSchemaSimpleType) {
1193 //process simple type
1194 processSimpleSchemaType((XmlSchemaSimpleType) type, null, resolvedSchema, null);
1195 }
1196 }
1197
1198 }
1199
1200 // before actually processing this node, we need to recurse through the base types and add their
1201 // children (sometimes even preserving the order) to the metainfo holder of this type
1202 // the reason is that for extensions, the prefered way is to have the sequences of the base class
1203 //* before * the sequence of the child element.
1204 copyMetaInfoHierarchy(metaInfHolder, extension.getBaseTypeName(), parentSchema);
1205
1206 //process the particle of this node
1207 if (extension.getParticle() != null) {
1208 processParticle(extension.getBaseTypeName(),extension.getParticle(), metaInfHolder, parentSchema);
1209 }
1210
1211 // process attributes
1212 //process attributes - first look for the explicit attributes
1213 processAttributes(extension.getAttributes(),metaInfHolder,parentSchema);
1214
1215 //process any attribute
1216 //somehow the xml schema parser does not seem to pickup the any attribute!!
1217 XmlSchemaAnyAttribute anyAtt = extension.getAnyAttribute();
1218 if (anyAtt != null) {
1219 processAnyAttribute(metaInfHolder, anyAtt);
1220 }
1221 String className = findClassName(extension.getBaseTypeName(), false);
1222
1223 if (!writer.getDefaultClassName().equals(className)) {
1224 //the particle has been processed, However since this is an extension we need to
1225 //add the basetype as an extension to the complex type class.
1226 // The basetype has been processed already
1227 metaInfHolder.setExtension(true);
1228 metaInfHolder.setExtensionClassName(className);
1229 //Note - this is no array! so the array boolean is false
1230 }
1231 } else if (content instanceof XmlSchemaComplexContentRestriction) {
1232 XmlSchemaComplexContentRestriction restriction = (XmlSchemaComplexContentRestriction) content;
1233
1234 //process the base type if it has not been processed yet
1235 if (!isAlreadyProcessed(restriction.getBaseTypeName())) {
1236 //pick the relevant basetype from the schema and process it
1237 XmlSchema resolvedSchema = getParentSchema(parentSchema, restriction.getBaseTypeName(), COMPONENT_TYPE);
1238 if (resolvedSchema == null) {
1239 throw new SchemaCompilationException("can not find the complex type " + restriction.getBaseTypeName()
1240 + " from the parent type " + parentSchema.getTargetNamespace());
1241 } else {
1242 XmlSchemaType type = resolvedSchema.getTypeByName(restriction.getBaseTypeName());
1243 if (type instanceof XmlSchemaComplexType) {
1244 XmlSchemaComplexType complexType = (XmlSchemaComplexType) type;
1245 if (complexType.getName() != null) {
1246 processNamedComplexSchemaType(complexType, resolvedSchema);
1247 } else {
1248 //this is not possible. The restriction should always
1249 //have a name
1250 throw new SchemaCompilationException("Unnamed complex type used in restriction");//Internationlize this
1251 }
1252 } else if (type instanceof XmlSchemaSimpleType) {
1253 throw new SchemaCompilationException("Not a valid restriction, complex content restriction base type cannot be a simple type.");
1254 }
1255 }
1256 }
1257
1258 copyMetaInfoHierarchy(metaInfHolder, restriction.getBaseTypeName(), parentSchema);
1259
1260 //process the particle of this node
1261 processParticle(restriction.getBaseTypeName(),restriction.getParticle(), metaInfHolder, parentSchema);
1262
1263 //process attributes - first look for the explicit attributes
1264 processAttributes(restriction.getAttributes(),metaInfHolder,parentSchema);
1265
1266 //process any attribute
1267 //somehow the xml schema parser does not seem to pickup the any attribute!!
1268 XmlSchemaAnyAttribute anyAtt = restriction.getAnyAttribute();
1269 if (anyAtt != null) {
1270 processAnyAttribute(metaInfHolder, anyAtt);
1271 }
1272 String className = findClassName(restriction.getBaseTypeName(), false);
1273
1274 if (!writer.getDefaultClassName().equals(className)) {
1275 metaInfHolder.setRestriction(true);
1276 metaInfHolder.setRestrictionClassName(findClassName(restriction.getBaseTypeName(), false));
1277 //Note - this is no array! so the array boolean is false
1278 }
1279 }
1280 }
1281
1282 /**
1283 * Recursive method to populate the metainfo holders with info from the base types
1284 *
1285 * @param metaInfHolder
1286 * @param baseTypeName
1287 * @param parentSchema
1288 */
1289 private void copyMetaInfoHierarchy(BeanWriterMetaInfoHolder metaInfHolder,
1290 QName baseTypeName,
1291 XmlSchema parentSchema)
1292 throws SchemaCompilationException {
1293
1294 XmlSchema resolvedSchema = getParentSchema(parentSchema,baseTypeName,COMPONENT_TYPE);
1295 if (resolvedSchema == null) {
1296 throw new SchemaCompilationException("can not find type " + baseTypeName
1297 + " from the parent schema " + parentSchema.getTargetNamespace());
1298 } else {
1299 XmlSchemaType type = resolvedSchema.getTypeByName(baseTypeName);
1300 BeanWriterMetaInfoHolder baseMetaInfoHolder = (BeanWriterMetaInfoHolder)
1301 processedTypeMetaInfoMap.get(baseTypeName);
1302
1303
1304 if (baseMetaInfoHolder != null) {
1305
1306 // see whether this type is also extended from some other type first
1307 // if so proceed to set their parents as well.
1308 if (type instanceof XmlSchemaComplexType) {
1309 XmlSchemaComplexType complexType = (XmlSchemaComplexType) type;
1310 if (complexType.getContentModel() != null) {
1311 XmlSchemaContentModel content = complexType.getContentModel();
1312 if (content instanceof XmlSchemaComplexContent) {
1313 XmlSchemaComplexContent complexContent =
1314 (XmlSchemaComplexContent) content;
1315 if (complexContent.getContent() instanceof XmlSchemaComplexContentExtension) {
1316 XmlSchemaComplexContentExtension extension =
1317 (XmlSchemaComplexContentExtension) complexContent.getContent();
1318 //recursively call the copyMetaInfoHierarchy method
1319 copyMetaInfoHierarchy(baseMetaInfoHolder,
1320 extension.getBaseTypeName(),
1321 resolvedSchema);
1322
1323 } else if (complexContent.getContent() instanceof XmlSchemaComplexContentRestriction) {
1324
1325 XmlSchemaComplexContentRestriction restriction =
1326 (XmlSchemaComplexContentRestriction) complexContent.getContent();
1327 //recursively call the copyMetaInfoHierarchy method
1328 copyMetaInfoHierarchy(baseMetaInfoHolder,
1329 restriction.getBaseTypeName(),
1330 resolvedSchema);
1331
1332 } else {
1333 throw new SchemaCompilationException(
1334 SchemaCompilerMessages.getMessage("schema.unknowncontenterror"));
1335 }
1336
1337 } else if (content instanceof XmlSchemaSimpleContent) {
1338 throw new SchemaCompilationException(
1339 SchemaCompilerMessages.getMessage("schema.unsupportedcontenterror", "Simple Content"));
1340 } else {
1341 throw new SchemaCompilationException(
1342 SchemaCompilerMessages.getMessage("schema.unknowncontenterror"));
1343 }
1344 }
1345 //Do the actual parent setting
1346 metaInfHolder.setAsParent(baseMetaInfoHolder);
1347
1348 } else if (type instanceof XmlSchemaSimpleType) {
1349
1350 // we have to copy the uion data if the parent simple type restriction
1351 // is an union
1352 // this union attribute is copied from the child to parent to genrate the parent
1353 // code as union
1354 if (baseMetaInfoHolder.isUnion()) {
1355 metaInfHolder.setUnion(true);
1356 Map memberTypes = baseMetaInfoHolder.getMemberTypes();
1357 Object qname;
1358 for (Iterator iter = memberTypes.keySet().iterator(); iter.hasNext();) {
1359 qname = iter.next();
1360 metaInfHolder.addMemberType((QName) qname, (String) memberTypes.get(qname));
1361 }
1362 }
1363
1364 // we have to copy the list type data to parent if it is a list
1365 if (baseMetaInfoHolder.isList()) {
1366 metaInfHolder.setList(true);
1367 metaInfHolder.setItemTypeQName(baseMetaInfoHolder.getItemTypeQName());
1368 metaInfHolder.setItemTypeClassName(baseMetaInfoHolder.getItemTypeClassName());
1369 }
1370 metaInfHolder.setAsParent(baseMetaInfoHolder);
1371 }
1372
1373 }
1374 }
1375 }
1376
1377 /**
1378 * @param simpleContent
1379 * @param metaInfHolder
1380 * @throws SchemaCompilationException
1381 */
1382 private void processSimpleContent(XmlSchemaSimpleContent simpleContent, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema parentSchema)
1383 throws SchemaCompilationException {
1384 XmlSchemaContent content;
1385 content = simpleContent.getContent();
1386 if (content instanceof XmlSchemaSimpleContentExtension) {
1387 XmlSchemaSimpleContentExtension extension = (XmlSchemaSimpleContentExtension) content;
1388
1389 //process the base type if it has not been processed yet
1390 if (!isAlreadyProcessed(extension.getBaseTypeName())) {
1391 //pick the relevant basetype from the schema and process it
1392 XmlSchema resolvedSchema = getParentSchema(parentSchema, extension.getBaseTypeName(), COMPONENT_TYPE);
1393 if (resolvedSchema == null) {
1394 throw new SchemaCompilationException("can not find type " + extension.getBaseTypeName()
1395 + " from the parent schema " + parentSchema.getTargetNamespace());
1396 } else {
1397 XmlSchemaType type = resolvedSchema.getTypeByName(extension.getBaseTypeName());
1398 if (type instanceof XmlSchemaComplexType) {
1399 XmlSchemaComplexType complexType = (XmlSchemaComplexType) type;
1400 if (complexType.getName() != null) {
1401 processNamedComplexSchemaType(complexType, resolvedSchema);
1402 } else {
1403 //this is not possible. The extension should always
1404 //have a name
1405 throw new SchemaCompilationException("Unnamed complex type used in extension");//Internationlize this
1406 }
1407 } else if (type instanceof XmlSchemaSimpleType) {
1408 //process simple type
1409 processSimpleSchemaType((XmlSchemaSimpleType) type, null, resolvedSchema, null);
1410 }
1411 }
1412
1413 }
1414
1415 //process extension base type
1416 processSimpleExtensionBaseType(extension.getBaseTypeName(), metaInfHolder, parentSchema);
1417
1418 //process attributes
1419 XmlSchemaObjectCollection attribs = extension.getAttributes();
1420 Iterator attribIterator = attribs.getIterator();
1421 while (attribIterator.hasNext()) {
1422 Object attr = attribIterator.next();
1423 if (attr instanceof XmlSchemaAttribute) {
1424 processAttribute((XmlSchemaAttribute) attr, metaInfHolder, parentSchema);
1425
1426 }
1427 }
1428
1429 //process any attribute
1430 XmlSchemaAnyAttribute anyAtt = extension.getAnyAttribute();
1431 if (anyAtt != null) {
1432 processAnyAttribute(metaInfHolder, anyAtt);
1433 }
1434
1435 } else if (content instanceof XmlSchemaSimpleContentRestriction) {
1436 XmlSchemaSimpleContentRestriction restriction = (XmlSchemaSimpleContentRestriction) content;
1437
1438 //process the base type if it has not been processed yet
1439 if (!isAlreadyProcessed(restriction.getBaseTypeName())) {
1440 //pick the relevant basetype from the schema and process it
1441 XmlSchema resolvedSchema = getParentSchema(parentSchema, restriction.getBaseTypeName(), COMPONENT_TYPE);
1442 if (resolvedSchema == null) {
1443 throw new SchemaCompilationException("can not find type " + restriction.getBaseTypeName()
1444 + " from the parent schema " + parentSchema.getTargetNamespace());
1445 } else {
1446 XmlSchemaType type = resolvedSchema.getTypeByName(restriction.getBaseTypeName());
1447
1448 if (type instanceof XmlSchemaComplexType) {
1449 XmlSchemaComplexType complexType = (XmlSchemaComplexType) type;
1450 if (complexType.getName() != null) {
1451 processNamedComplexSchemaType(complexType, resolvedSchema);
1452 } else {
1453 //this is not possible. The extension should always
1454 //have a name
1455 throw new SchemaCompilationException("Unnamed complex type used in restriction");//Internationlize this
1456 }
1457 } else if (type instanceof XmlSchemaSimpleType) {
1458 //process simple type
1459 processSimpleSchemaType((XmlSchemaSimpleType) type, null, resolvedSchema, null);
1460 }
1461 }
1462
1463 }
1464 //process restriction base type
1465 processSimpleRestrictionBaseType(restriction.getBaseTypeName(),
1466 restriction.getBaseTypeName(),
1467 metaInfHolder,
1468 parentSchema);
1469 metaInfHolder.setSimple(true);
1470 }
1471 }
1472
1473 /**
1474 * Process Simple Extension Base Type.
1475 *
1476 * @param extBaseType
1477 * @param metaInfHolder
1478 */
1479 public void processSimpleExtensionBaseType(QName extBaseType,
1480 BeanWriterMetaInfoHolder metaInfHolder,
1481 XmlSchema parentSchema) throws SchemaCompilationException {
1482
1483 //find the class name
1484 String className = findClassName(extBaseType, false);
1485
1486 // if the base type is an primitive then we do not have to extend them
1487 // and it is considered as a property
1488 // on the otherhand if the base type is an generated class then we have to
1489 // extend from it
1490
1491 if (baseSchemaTypeMap.containsKey(extBaseType)) {
1492 //this means the schema type actually returns a different QName
1493 if (changedTypeMap.containsKey(extBaseType)) {
1494 metaInfHolder.registerMapping(extBaseType,
1495 (QName) changedTypeMap.get(extBaseType),
1496 className, SchemaConstants.ELEMENT_TYPE);
1497 } else {
1498 metaInfHolder.registerMapping(extBaseType,
1499 extBaseType,
1500 className, SchemaConstants.ELEMENT_TYPE);
1501 }
1502 metaInfHolder.setSimple(true);
1503 // we have already process when it comes to this place
1504 } else if (processedTypemap.containsKey(extBaseType)) {
1505 //set the extension base class name
1506 XmlSchema resolvedSchema = getParentSchema(parentSchema,extBaseType,COMPONENT_TYPE);
1507 if (resolvedSchema == null) {
1508 throw new SchemaCompilationException("can not find the type " + extBaseType
1509 + " from the parent schema " + parentSchema.getTargetNamespace());
1510 } else {
1511 XmlSchemaType type = resolvedSchema.getTypeByName(extBaseType);
1512 if (type instanceof XmlSchemaSimpleType) {
1513 metaInfHolder.setSimple(true);
1514 metaInfHolder.setExtension(true);
1515 metaInfHolder.setExtensionClassName(className);
1516
1517 copyMetaInfoHierarchy(metaInfHolder, extBaseType, resolvedSchema);
1518 } else if (type instanceof XmlSchemaComplexType) {
1519 XmlSchemaComplexType complexType = (XmlSchemaComplexType) type;
1520 if (complexType.getContentModel() == null) {
1521 // do not set as a simple type since we want to
1522 // print the element names
1523 metaInfHolder.setExtension(true);
1524 metaInfHolder.setExtensionClassName(className);
1525 copyMetaInfoHierarchy(metaInfHolder, extBaseType, resolvedSchema);
1526 }
1527 }
1528 }
1529
1530 } else {
1531 metaInfHolder.setSimple(true);
1532 }
1533
1534 //get the binary state and add that to the status map
1535 if (isBinary(extBaseType)) {
1536 metaInfHolder.addtStatus(extBaseType,
1537 SchemaConstants.BINARY_TYPE);
1538 }
1539 }
1540
1541 /**
1542 * Process Simple Restriction Base Type.
1543 *
1544 * @param resBaseType
1545 * @param metaInfHolder
1546 */
1547 public void processSimpleRestrictionBaseType(QName qName,
1548 QName resBaseType,
1549 BeanWriterMetaInfoHolder metaInfHolder,
1550 XmlSchema parentSchema) throws SchemaCompilationException {
1551
1552 //find the class name
1553 String className = findClassName(resBaseType, false);
1554
1555 //this means the schema type actually returns a different QName
1556 if (baseSchemaTypeMap.containsKey(resBaseType)) {
1557 if (changedTypeMap.containsKey(resBaseType)) {
1558 metaInfHolder.registerMapping(qName,
1559 (QName) changedTypeMap.get(resBaseType),
1560 className, SchemaConstants.ELEMENT_TYPE);
1561 } else {
1562 metaInfHolder.registerMapping(qName,
1563 resBaseType,
1564 className, SchemaConstants.ELEMENT_TYPE);
1565 }
1566 } else if (processedTypemap.containsKey(resBaseType)) {
1567 //this is not a standared type
1568 // so the parent class must extend it
1569 metaInfHolder.setSimple(true);
1570 metaInfHolder.setRestriction(true);
1571 metaInfHolder.setRestrictionClassName(className);
1572 copyMetaInfoHierarchy(metaInfHolder, resBaseType, parentSchema);
1573 }
1574
1575 metaInfHolder.setRestrictionBaseType(resBaseType);
1576
1577
1578 }
1579
1580 /**
1581 * Process Facets.
1582 *
1583 * @param metaInfHolder
1584 */
1585 private void processFacets(XmlSchemaSimpleTypeRestriction restriction,
1586 BeanWriterMetaInfoHolder metaInfHolder,
1587 XmlSchema parentSchema) {
1588
1589 XmlSchemaObjectCollection facets = restriction.getFacets();
1590 Iterator facetIterator = facets.getIterator();
1591
1592 while (facetIterator.hasNext()) {
1593 Object obj = facetIterator.next();
1594
1595 if (obj instanceof XmlSchemaPatternFacet) {
1596 XmlSchemaPatternFacet pattern = (XmlSchemaPatternFacet) obj;
1597 // some patterns contain \ so we have to replace them
1598 String patternString = pattern.getValue().toString();
1599 // replace backword slashes
1600 patternString = patternString.replaceAll("\\\\", "\\\\\\\\");
1601 if ((metaInfHolder.getPatternFacet() != null) &&
1602 (metaInfHolder.getPatternFacet().trim().length() > 0)){
1603 // i.e there is a pattern faceset
1604 patternString = metaInfHolder.getPatternFacet().trim() + "|" + patternString;
1605 }
1606 metaInfHolder.setPatternFacet(patternString);
1607 }
1608
1609 else if (obj instanceof XmlSchemaEnumerationFacet) {
1610 XmlSchemaEnumerationFacet enumeration = (XmlSchemaEnumerationFacet) obj;
1611 if (restriction.getBaseTypeName().equals(SchemaConstants.XSD_QNAME)) {
1612 // we have to process the qname here and shoud find the local part and namespace uri
1613 String value = enumeration.getValue().toString();
1614 String prefix = value.substring(0, value.indexOf(":"));
1615 String localPart = value.substring(value.indexOf(":") + 1);
1616
1617 String namespaceUri = parentSchema.getNamespaceContext().getNamespaceURI(prefix);
1618 // set the string to suite for the convertQname method
1619 String qNameString = value + "\", \"" + namespaceUri;
1620 metaInfHolder.addEnumFacet(qNameString);
1621 } else {
1622 metaInfHolder.addEnumFacet(enumeration.getValue().toString());
1623 }
1624
1625 }
1626
1627 else if (obj instanceof XmlSchemaLengthFacet) {
1628 XmlSchemaLengthFacet length = (XmlSchemaLengthFacet) obj;
1629 metaInfHolder.setLengthFacet(Integer.parseInt(length.getValue().toString()));
1630 }
1631
1632 else if (obj instanceof XmlSchemaMaxExclusiveFacet) {
1633 XmlSchemaMaxExclusiveFacet maxEx = (XmlSchemaMaxExclusiveFacet) obj;
1634 metaInfHolder.setMaxExclusiveFacet(maxEx.getValue().toString());
1635 }
1636
1637 else if (obj instanceof XmlSchemaMinExclusiveFacet) {
1638 XmlSchemaMinExclusiveFacet minEx = (XmlSchemaMinExclusiveFacet) obj;
1639 metaInfHolder.setMinExclusiveFacet(minEx.getValue().toString());
1640 }
1641
1642 else if (obj instanceof XmlSchemaMaxInclusiveFacet) {
1643 XmlSchemaMaxInclusiveFacet maxIn = (XmlSchemaMaxInclusiveFacet) obj;
1644 metaInfHolder.setMaxInclusiveFacet(maxIn.getValue().toString());
1645 }
1646
1647 else if (obj instanceof XmlSchemaMinInclusiveFacet) {
1648 XmlSchemaMinInclusiveFacet minIn = (XmlSchemaMinInclusiveFacet) obj;
1649 metaInfHolder.setMinInclusiveFacet(minIn.getValue().toString());
1650 }
1651
1652 else if (obj instanceof XmlSchemaMaxLengthFacet) {
1653 XmlSchemaMaxLengthFacet maxLen = (XmlSchemaMaxLengthFacet) obj;
1654 metaInfHolder.setMaxLengthFacet(Integer.parseInt(maxLen.getValue().toString()));
1655 }
1656
1657 else if (obj instanceof XmlSchemaMinLengthFacet) {
1658 XmlSchemaMinLengthFacet minLen = (XmlSchemaMinLengthFacet) obj;
1659 metaInfHolder.setMinLengthFacet(Integer.parseInt(minLen.getValue().toString()));
1660 }
1661 }
1662 }
1663
1664 /**
1665 * Handle any attribute
1666 *
1667 * @param metainf
1668 */
1669 private void processAnyAttribute(BeanWriterMetaInfoHolder metainf, XmlSchemaAnyAttribute anyAtt) {
1670
1671 //The best thing we can do here is to add a set of OMAttributes
1672 //since attributes do not have the notion of minoccurs/maxoccurs the
1673 //safest option here is to have an OMAttribute array
1674 QName qName = new QName(EXTRA_ATTRIBUTE_FIELD_NAME);
1675 metainf.registerMapping(qName,
1676 null,
1677 writer.getDefaultAttribArrayClassName(),//always generate an array of
1678 //OMAttributes
1679 SchemaConstants.ANY_TYPE);
1680 metainf.addtStatus(qName, SchemaConstants.ATTRIBUTE_TYPE);
1681 metainf.addtStatus(qName, SchemaConstants.ARRAY_TYPE);
1682
1683 }
1684
1685
1686 /**
1687 * Process the attribute
1688 *
1689 * @param att
1690 * @param metainf
1691 */
1692 public void processAttribute(XmlSchemaAttribute att, BeanWriterMetaInfoHolder metainf, XmlSchema parentSchema)
1693 throws SchemaCompilationException {
1694
1695 QName schemaTypeName = att.getSchemaTypeName();
1696 if (schemaTypeName != null) {
1697 if (att.getQName() != null) {
1698 if (baseSchemaTypeMap.containsKey(schemaTypeName)) {
1699
1700 metainf.registerMapping(att.getQName(), schemaTypeName,
1701 baseSchemaTypeMap.get(schemaTypeName).toString(), SchemaConstants.ATTRIBUTE_TYPE);
1702
1703 // add optional attribute status if set
1704 String use = att.getUse().getValue();
1705 if (USE_NONE.equals(use) || USE_OPTIONAL.equals(use)) {
1706 metainf.addtStatus(att.getQName(), SchemaConstants.OPTIONAL_TYPE);
1707 }
1708
1709 String className = findClassName(schemaTypeName, false);
1710
1711 att.addMetaInfo(
1712 SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
1713 className);
1714 // set the default value
1715 if (att.getDefaultValue() != null){
1716 metainf.registerDefaultValue(att.getQName(),att.getDefaultValue());
1717 }
1718 // after
1719 } else {
1720 XmlSchema resolvedSchema = getParentSchema(parentSchema,schemaTypeName,COMPONENT_TYPE);
1721 if (resolvedSchema == null) {
1722 throw new SchemaCompilationException("can not find the type " + schemaTypeName +
1723 " from the parent schema " + parentSchema.getTargetNamespace());
1724 } else {
1725 XmlSchemaType type = resolvedSchema.getTypeByName(schemaTypeName);
1726 if (type instanceof XmlSchemaSimpleType) {
1727 XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType) type;
1728
1729 if (simpleType != null) {
1730 if (!isAlreadyProcessed(schemaTypeName)) {
1731 //process simple type
1732 processSimpleSchemaType(simpleType, null, resolvedSchema, null);
1733 }
1734 metainf.registerMapping(att.getQName(),
1735 schemaTypeName,
1736 processedTypemap.get(schemaTypeName).toString(),
1737 SchemaConstants.ATTRIBUTE_TYPE);
1738 // add optional attribute status if set
1739 String use = att.getUse().getValue();
1740 if (USE_NONE.equals(use) || USE_OPTIONAL.equals(use)) {
1741 metainf.addtStatus(att.getQName(), SchemaConstants.OPTIONAL_TYPE);
1742 }
1743 }
1744
1745 }
1746 }
1747 }
1748 } else {
1749 // this attribute has a type but does not have a name, seems to be invalid
1750 }
1751
1752 } else if (att.getRefName() != null) {
1753
1754 XmlSchema resolvedSchema = getParentSchema(parentSchema,att.getRefName(),COMPONENT_ATTRIBUTE);
1755 if (resolvedSchema == null){
1756 throw new SchemaCompilationException("can not find the attribute " + att.getRefName() +
1757 " from the parent schema " + parentSchema.getTargetNamespace());
1758 } else {
1759 XmlSchemaAttribute xmlSchemaAttribute =
1760 (XmlSchemaAttribute) resolvedSchema.getAttributes().getItem(att.getRefName());
1761 if (xmlSchemaAttribute != null) {
1762 // call recursively to process the schema
1763 processAttribute(xmlSchemaAttribute, metainf, resolvedSchema);
1764 } else {
1765 throw new SchemaCompilationException("Attribute QName reference refer to an invalid attribute " +
1766 att.getRefName());
1767 }
1768 }
1769
1770 } else {
1771 // this attribute refers to a custom type, probably one of the extended simple types.
1772 // with the inline schema definition
1773 QName attributeQName = att.getQName();
1774 if (attributeQName != null) {
1775 XmlSchemaSimpleType attributeSimpleType = att.getSchemaType();
1776 XmlSchema resolvedSchema = parentSchema;
1777 if (attributeSimpleType == null) {
1778 // try to get the schema for using qname
1779 QName attributeSchemaQname = att.getSchemaTypeName();
1780 if (attributeSchemaQname != null) {
1781 resolvedSchema = getParentSchema(parentSchema,attributeSchemaQname,COMPONENT_TYPE);
1782 if (resolvedSchema == null){
1783 throw new SchemaCompilationException("can not find the type " + attributeSchemaQname
1784 + " from the parent schema " + parentSchema.getTargetNamespace());
1785 } else {
1786 attributeSimpleType = (XmlSchemaSimpleType)
1787 resolvedSchema.getTypeByName(attributeSchemaQname);
1788 }
1789 }
1790 }
1791
1792 if (attributeSimpleType != null) {
1793 QName schemaTypeQName = att.getSchemaTypeName();
1794 if (schemaTypeQName == null) {
1795 // set the parent schema target name space since attribute Qname uri is ""
1796 if (attributeSimpleType.getQName() != null) {
1797 schemaTypeQName = attributeSimpleType.getQName();
1798 } else {
1799 schemaTypeQName = new QName(parentSchema.getTargetNamespace(),
1800 attributeQName.getLocalPart() + getNextTypeSuffix(attributeQName.getLocalPart()));
1801
1802 }
1803 }
1804 if (!isAlreadyProcessed(schemaTypeQName)){
1805 // we have to process only if it has not processed
1806 processSimpleSchemaType(attributeSimpleType, null, resolvedSchema, schemaTypeQName);
1807 }
1808 metainf.registerMapping(att.getQName(),
1809 schemaTypeQName,
1810 processedTypemap.get(schemaTypeQName).toString(),
1811 SchemaConstants.ATTRIBUTE_TYPE);
1812 // add optional attribute status if set
1813 String use = att.getUse().getValue();
1814 if (USE_NONE.equals(use) || USE_OPTIONAL.equals(use)) {
1815 metainf.addtStatus(att.getQName(), SchemaConstants.OPTIONAL_TYPE);
1816 }
1817 } else {
1818 // TODO: handle the case when no attribute type specifed
1819 log.warn("No attribute type has defined to the Attribute " + attributeQName);
1820 }
1821
1822 } else {
1823 throw new SchemaCompilationException("Attribute QName reference refer to an invalid attribute " +
1824 attributeQName);
1825 }
1826
1827 }
1828 }
1829
1830 /**
1831 * Process a particle- A particle may be a sequence,all or a choice
1832 * @param parentElementQName - this can either be parent element QName or parent Complex type qname
1833 * @param particle - particle being processed
1834 * @param metainfHolder -
1835 * @param parentSchema
1836 * @throws SchemaCompilationException
1837 */
1838 private void processParticle(QName parentElementQName,
1839 XmlSchemaParticle particle,
1840 BeanWriterMetaInfoHolder metainfHolder
1841 , XmlSchema parentSchema) throws SchemaCompilationException {
1842
1843 if (particle instanceof XmlSchemaSequence) {
1844 XmlSchemaSequence xmlSchemaSequence = (XmlSchemaSequence) particle;
1845
1846 XmlSchemaObjectCollection items = xmlSchemaSequence.getItems();
1847 if ((xmlSchemaSequence.getMaxOccurs() > 1) && (parentElementQName != null)) {
1848 // we have to process many sequence types
1849 BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder();
1850 process(parentElementQName, items, beanWriterMetaInfoHolder, true, parentSchema);
1851 beanWriterMetaInfoHolder.setParticleClass(true);
1852 QName sequenceQName = new QName(parentElementQName.getNamespaceURI(),
1853 parentElementQName.getLocalPart() + "Sequence");
1854 String javaClassName = writeComplexParticle(sequenceQName,beanWriterMetaInfoHolder);
1855 processedTypemap.put(sequenceQName, javaClassName);
1856
1857 // add this as an array to the original class
1858 metainfHolder.registerMapping(sequenceQName,
1859 sequenceQName,
1860 findClassName(sequenceQName,true),
1861 SchemaConstants.ARRAY_TYPE);
1862 metainfHolder.setOrdered(true);
1863 metainfHolder.registerQNameIndex(sequenceQName,metainfHolder.getOrderStartPoint() + 1);
1864 metainfHolder.setHasParticleType(true);
1865 metainfHolder.addtStatus(sequenceQName,SchemaConstants.PARTICLE_TYPE_ELEMENT);
1866 metainfHolder.addMaxOccurs(sequenceQName,xmlSchemaSequence.getMaxOccurs());
1867 metainfHolder.addMinOccurs(sequenceQName,xmlSchemaSequence.getMinOccurs());
1868
1869
1870 } else {
1871 if (options.isBackwordCompatibilityMode()) {
1872 process(parentElementQName,items, metainfHolder, false, parentSchema);
1873 } else {
1874 process(parentElementQName,items, metainfHolder, true, parentSchema);
1875 }
1876 }
1877
1878 } else if (particle instanceof XmlSchemaAll) {
1879 XmlSchemaObjectCollection items = ((XmlSchemaAll) particle).getItems();
1880 process(parentElementQName,items, metainfHolder, false, parentSchema);
1881 } else if (particle instanceof XmlSchemaChoice) {
1882 XmlSchemaChoice xmlSchemaChoice = (XmlSchemaChoice) particle;
1883 XmlSchemaObjectCollection items = ((XmlSchemaChoice) particle).getItems();
1884
1885 if ((xmlSchemaChoice.getMaxOccurs() > 1)) {
1886 // we have to process many sequence types
1887 BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder();
1888 beanWriterMetaInfoHolder.setChoice(true);
1889 process(parentElementQName,items, beanWriterMetaInfoHolder, false, parentSchema);
1890 beanWriterMetaInfoHolder.setParticleClass(true);
1891 QName choiceQName = new QName(parentElementQName.getNamespaceURI(),
1892 parentElementQName.getLocalPart() + "Choice");
1893 String javaClassName = writeComplexParticle(choiceQName,beanWriterMetaInfoHolder);
1894 processedTypemap.put(choiceQName, javaClassName);
1895
1896 // add this as an array to the original class
1897 metainfHolder.registerMapping(choiceQName,
1898 choiceQName,
1899 findClassName(choiceQName,true),
1900 SchemaConstants.ARRAY_TYPE);
1901 metainfHolder.setOrdered(true);
1902 metainfHolder.setHasParticleType(true);
1903 metainfHolder.registerQNameIndex(choiceQName,metainfHolder.getOrderStartPoint() + 1);
1904 metainfHolder.addtStatus(choiceQName,SchemaConstants.PARTICLE_TYPE_ELEMENT);
1905 metainfHolder.addMaxOccurs(choiceQName,xmlSchemaChoice.getMaxOccurs());
1906 metainfHolder.addMinOccurs(choiceQName,xmlSchemaChoice.getMinOccurs());
1907
1908 } else {
1909 metainfHolder.setChoice(true);
1910 process(parentElementQName,items, metainfHolder, false, parentSchema);
1911 }
1912
1913
1914 } else if (particle instanceof XmlSchemaGroupRef){
1915
1916 XmlSchemaGroupRef xmlSchemaGroupRef = (XmlSchemaGroupRef) particle;
1917 QName groupQName = xmlSchemaGroupRef.getRefName();
1918 if (groupQName != null) {
1919 if (!processedGroupTypeMap.containsKey(groupQName)) {
1920 // processe the schema here
1921 XmlSchema resolvedParentSchema = getParentSchema(parentSchema,groupQName,COMPONENT_GROUP);
1922 if (resolvedParentSchema == null){
1923 throw new SchemaCompilationException("can not find the group " + groupQName
1924 + " from the parent schema " + parentSchema.getTargetNamespace());
1925 } else {
1926 XmlSchemaGroup xmlSchemaGroup = (XmlSchemaGroup)
1927 resolvedParentSchema.getGroups().getItem(groupQName);
1928 processGroup(xmlSchemaGroup, groupQName, resolvedParentSchema);
1929 }
1930 }
1931 } else {
1932 throw new SchemaCompilationException("Referenced name is null");
1933 }
1934 boolean isArray = xmlSchemaGroupRef.getMaxOccurs() > 1;
1935
1936 // add this as an array to the original class
1937 String groupClassName = (String) processedGroupTypeMap.get(groupQName);
1938 if (isArray){
1939 groupClassName = groupClassName + "[]";
1940 }
1941 metainfHolder.registerMapping(groupQName, groupQName, groupClassName);
1942 if (isArray) {
1943 metainfHolder.addtStatus(groupQName, SchemaConstants.ARRAY_TYPE);
1944 }
1945 metainfHolder.addtStatus(groupQName, SchemaConstants.PARTICLE_TYPE_ELEMENT);
1946 metainfHolder.addMaxOccurs(groupQName, xmlSchemaGroupRef.getMaxOccurs());
1947 metainfHolder.addMinOccurs(groupQName, xmlSchemaGroupRef.getMinOccurs());
1948 metainfHolder.setHasParticleType(true);
1949 metainfHolder.setOrdered(true);
1950 metainfHolder.registerQNameIndex(groupQName,metainfHolder.getOrderStartPoint() + 1);
1951
1952 }
1953 }
1954
1955 /**
1956 *
1957 * @param parentElementQName - this could either be the complex type parentElementQName or element parentElementQName
1958 * @param items
1959 * @param metainfHolder
1960 * @param order
1961 * @param parentSchema
1962 * @throws SchemaCompilationException
1963 */
1964 private void process(QName parentElementQName,
1965 XmlSchemaObjectCollection items,
1966 BeanWriterMetaInfoHolder metainfHolder,
1967 boolean order,
1968 XmlSchema parentSchema) throws SchemaCompilationException {
1969 int count = items.getCount();
1970 Map processedElementArrayStatusMap = new LinkedHashMap();
1971 Map processedElementTypeMap = new LinkedHashMap();
1972 List localNillableList = new ArrayList();
1973
1974 Map particleQNameMap = new HashMap();
1975
1976 // this list is used to keep the details of the
1977 // elements within a choice withing sequence
1978 List innerChoiceElementList = new ArrayList();
1979
1980 Map elementOrderMap = new HashMap();
1981
1982 int sequenceCounter = 0;
1983 for (int i = 0; i < count; i++) {
1984 XmlSchemaObject item = items.getItem(i);
1985
1986 if (item instanceof XmlSchemaElement) {
1987 //recursively process the element
1988 XmlSchemaElement xsElt = (XmlSchemaElement) item;
1989
1990 boolean isArray = isArray(xsElt);
1991 processElement(xsElt, processedElementTypeMap, localNillableList, parentSchema); //we know for sure this is not an outer type
1992 processedElementArrayStatusMap.put(xsElt, (isArray) ? Boolean.TRUE : Boolean.FALSE);
1993 if (order) {
1994 //we need to keep the order of the elements. So push the elements to another
1995 //hashmap with the order number
1996 elementOrderMap.put(xsElt, new Integer(sequenceCounter));
1997 }
1998
1999 //handle xsd:any ! We place an OMElement (or an array of OMElements) in the generated class
2000 } else if (item instanceof XmlSchemaAny) {
2001 XmlSchemaAny any = (XmlSchemaAny) item;
2002 processedElementTypeMap.put(new QName(ANY_ELEMENT_FIELD_NAME), any);
2003 //any can also be inside a sequence
2004 if (order) {
2005 elementOrderMap.put(any, new Integer(sequenceCounter));
2006 }
2007 //we do not register the array status for the any type
2008 processedElementArrayStatusMap.put(any, isArray(any) ? Boolean.TRUE : Boolean.FALSE);
2009 } else if (item instanceof XmlSchemaSequence) {
2010 // we have to process many sequence types
2011
2012 XmlSchemaSequence xmlSchemaSequence = (XmlSchemaSequence) item;
2013 if (xmlSchemaSequence.getItems().getCount() > 0) {
2014 BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder();
2015 process(parentElementQName, xmlSchemaSequence.getItems(), beanWriterMetaInfoHolder, true, parentSchema);
2016 beanWriterMetaInfoHolder.setParticleClass(true);
2017 String localName = parentElementQName.getLocalPart() + "Sequence";
2018 QName sequenceQName = new QName(parentElementQName.getNamespaceURI(),
2019 localName + getNextTypeSuffix(localName));
2020 String javaClassName = writeComplexParticle(sequenceQName, beanWriterMetaInfoHolder);
2021 processedTypemap.put(sequenceQName, javaClassName);
2022
2023 //put the partical to array
2024 Boolean isArray = xmlSchemaSequence.getMaxOccurs() > 1 ? Boolean.TRUE : Boolean.FALSE;
2025 processedElementArrayStatusMap.put(item, isArray);
2026 particleQNameMap.put(item, sequenceQName);
2027
2028 if (order) {
2029 elementOrderMap.put(item, new Integer(sequenceCounter));
2030 }
2031 }
2032
2033 } else if (item instanceof XmlSchemaChoice) {
2034 // we have to process many sequence types
2035
2036 XmlSchemaChoice xmlSchemaChoice = (XmlSchemaChoice) item;
2037 if (xmlSchemaChoice.getItems().getCount() > 0) {
2038 BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder();
2039 beanWriterMetaInfoHolder.setChoice(true);
2040 process(parentElementQName, xmlSchemaChoice.getItems(), beanWriterMetaInfoHolder, false, parentSchema);
2041 beanWriterMetaInfoHolder.setParticleClass(true);
2042 String localName = parentElementQName.getLocalPart() + "Choice";
2043 QName choiceQName = new QName(parentElementQName.getNamespaceURI(),
2044 localName + getNextTypeSuffix(localName));
2045 String javaClassName = writeComplexParticle(choiceQName, beanWriterMetaInfoHolder);
2046 processedTypemap.put(choiceQName, javaClassName);
2047
2048 //put the partical to array
2049 Boolean isArray = xmlSchemaChoice.getMaxOccurs() > 1 ? Boolean.TRUE : Boolean.FALSE;
2050 processedElementArrayStatusMap.put(item, isArray);
2051 particleQNameMap.put(item, choiceQName);
2052
2053 if (order) {
2054 elementOrderMap.put(item, new Integer(sequenceCounter));
2055 }
2056 }
2057
2058 } else if (item instanceof XmlSchemaGroupRef) {
2059
2060 XmlSchemaGroupRef xmlSchemaGroupRef = (XmlSchemaGroupRef) item;
2061 QName groupQName = xmlSchemaGroupRef.getRefName();
2062 if (groupQName != null){
2063 if (!processedGroupTypeMap.containsKey(groupQName)){
2064 // processe the schema here
2065 XmlSchema resolvedParentSchema = getParentSchema(parentSchema,groupQName,COMPONENT_GROUP);
2066 if (resolvedParentSchema == null){
2067 throw new SchemaCompilationException("Can not find the group with the qname" +
2068 groupQName + " from the parent schema " + parentSchema.getTargetNamespace());
2069 } else {
2070 XmlSchemaGroup xmlSchemaGroup =
2071 (XmlSchemaGroup) resolvedParentSchema.getGroups().getItem(groupQName);
2072 if (xmlSchemaGroup != null){
2073 processGroup(xmlSchemaGroup, groupQName, resolvedParentSchema);
2074 }
2075 }
2076 }
2077
2078 Boolean isArray = xmlSchemaGroupRef.getMaxOccurs() > 1 ? Boolean.TRUE : Boolean.FALSE;
2079 processedElementArrayStatusMap.put(item,isArray);
2080 particleQNameMap.put(item,groupQName);
2081
2082 if (order){
2083 elementOrderMap.put(item, new Integer(sequenceCounter));
2084 }
2085
2086 } else {
2087 throw new SchemaCompilationException("Referenced name is null");
2088 }
2089 } else {
2090 //there may be other types to be handled here. Add them
2091 //when we are ready
2092 }
2093 sequenceCounter++;
2094 }
2095
2096 // loop through the processed items and add them to the matainf object
2097 Iterator processedElementsIterator = processedElementArrayStatusMap.keySet().iterator();
2098 int startingItemNumberOrder = metainfHolder.getOrderStartPoint();
2099 while (processedElementsIterator.hasNext()) {
2100 Object child = processedElementsIterator.next();
2101
2102 // process the XmlSchemaElement
2103 if (child instanceof XmlSchemaElement) {
2104 XmlSchemaElement elt = (XmlSchemaElement) child;
2105 QName referencedQName = null;
2106
2107
2108 if (elt.getQName() != null) {
2109 referencedQName = elt.getQName();
2110 QName schemaTypeQName = elt.getSchemaType() != null ? elt.getSchemaType().getQName() : elt.getSchemaTypeName();
2111 if (schemaTypeQName != null) {
2112 String clazzName = (String) processedElementTypeMap.get(elt.getQName());
2113 metainfHolder.registerMapping(referencedQName,
2114 schemaTypeQName,
2115 clazzName,
2116 ((Boolean) processedElementArrayStatusMap.get(elt)).booleanValue() ?
2117 SchemaConstants.ARRAY_TYPE :
2118 SchemaConstants.ELEMENT_TYPE);
2119 if (innerChoiceElementList.contains(referencedQName)){
2120 metainfHolder.addtStatus(referencedQName,SchemaConstants.INNER_CHOICE_ELEMENT);
2121 }
2122 // register the default value as well
2123 if (elt.getDefaultValue() != null){
2124 metainfHolder.registerDefaultValue(referencedQName,elt.getDefaultValue());
2125 }
2126
2127 }
2128 }
2129
2130 if (elt.getRefName() != null) { //probably this is referenced
2131 referencedQName = elt.getRefName();
2132 boolean arrayStatus = ((Boolean) processedElementArrayStatusMap.get(elt)).booleanValue();
2133 String clazzName = findRefClassName(referencedQName, arrayStatus);
2134 if (clazzName == null) {
2135 clazzName = findClassName(referencedQName, arrayStatus);
2136 }
2137 XmlSchema resolvedParentSchema = getParentSchema(parentSchema,referencedQName,COMPONENT_ELEMENT);
2138 if (resolvedParentSchema == null) {
2139 throw new SchemaCompilationException("Can not find the element " + referencedQName +
2140 " from the parent schema " + parentSchema.getTargetNamespace());
2141 } else {
2142 XmlSchemaElement refElement = resolvedParentSchema.getElementByName(referencedQName);
2143
2144 // register the mapping if we found the referenced element
2145 // else throw an exception
2146 if (refElement != null) {
2147 metainfHolder.registerMapping(referencedQName,
2148 refElement.getSchemaTypeName()
2149 , clazzName,
2150 arrayStatus ?
2151 SchemaConstants.ARRAY_TYPE :
2152 SchemaConstants.ELEMENT_TYPE);
2153 } else {
2154 if (referencedQName.equals(SchemaConstants.XSD_SCHEMA)) {
2155 metainfHolder.registerMapping(referencedQName,
2156 null,
2157 writer.getDefaultClassName(),
2158 SchemaConstants.ANY_TYPE);
2159 } else {
2160 throw new SchemaCompilationException(SchemaCompilerMessages.getMessage("schema.referencedElementNotFound", referencedQName.toString()));
2161 }
2162 }
2163 }
2164 }
2165
2166 if (referencedQName == null) {
2167 throw new SchemaCompilationException(SchemaCompilerMessages.getMessage("schema.emptyName"));
2168 }
2169
2170 //register the occurence counts
2171 metainfHolder.addMaxOccurs(referencedQName, elt.getMaxOccurs());
2172 // if the strict validation off then we consider all elements have minOccurs zero on it
2173 if (this.options.isOffStrictValidation()){
2174 metainfHolder.addMinOccurs(referencedQName, 0);
2175 } else {
2176 metainfHolder.addMinOccurs(referencedQName, elt.getMinOccurs());
2177 }
2178 //we need the order to be preserved. So record the order also
2179 if (order) {
2180 //record the order in the metainf holder
2181 Integer integer = (Integer) elementOrderMap.get(elt);
2182 metainfHolder.registerQNameIndex(referencedQName,
2183 startingItemNumberOrder + integer.intValue());
2184 }
2185
2186 //get the nillable state and register that on the metainf holder
2187 if (localNillableList.contains(elt.getQName())) {
2188 metainfHolder.registerNillableQName(elt.getQName());
2189 }
2190
2191 //get the binary state and add that to the status map
2192 if (isBinary(elt)) {
2193 metainfHolder.addtStatus(elt.getQName(),
2194 SchemaConstants.BINARY_TYPE);
2195 }
2196 // process the XMLSchemaAny
2197 } else if (child instanceof XmlSchemaAny) {
2198 XmlSchemaAny any = (XmlSchemaAny) child;
2199
2200 //since there is only one element here it does not matter
2201 //for the constant. However the problem occurs if the users
2202 //uses the same name for an element decalration
2203 QName anyElementFieldName = new QName(ANY_ELEMENT_FIELD_NAME);
2204
2205 //this can be an array or a single element
2206 boolean isArray = ((Boolean) processedElementArrayStatusMap.get(any)).booleanValue();
2207 metainfHolder.registerMapping(anyElementFieldName,
2208 null,
2209 isArray ? writer.getDefaultClassArrayName() : writer.getDefaultClassName(),
2210 SchemaConstants.ANY_TYPE);
2211 //if it's an array register an extra status flag with the system
2212 if (isArray) {
2213 metainfHolder.addtStatus(anyElementFieldName,
2214 SchemaConstants.ARRAY_TYPE);
2215 }
2216 metainfHolder.addMaxOccurs(anyElementFieldName, any.getMaxOccurs());
2217 metainfHolder.addMinOccurs(anyElementFieldName, any.getMinOccurs());
2218
2219 if (order) {
2220 //record the order in the metainf holder for the any
2221 Integer integer = (Integer) elementOrderMap.get(any);
2222 metainfHolder.registerQNameIndex(anyElementFieldName,
2223 startingItemNumberOrder + integer.intValue());
2224 }
2225 } else if (child instanceof XmlSchemaSequence) {
2226 XmlSchemaSequence xmlSchemaSequence = (XmlSchemaSequence) child;
2227 QName sequenceQName = (QName) particleQNameMap.get(child);
2228 boolean isArray = xmlSchemaSequence.getMaxOccurs() > 1;
2229
2230 // add this as an array to the original class
2231 metainfHolder.registerMapping(sequenceQName,
2232 sequenceQName,
2233 findClassName(sequenceQName, isArray));
2234 if (isArray) {
2235 metainfHolder.addtStatus(sequenceQName, SchemaConstants.ARRAY_TYPE);
2236 }
2237 metainfHolder.addtStatus(sequenceQName, SchemaConstants.PARTICLE_TYPE_ELEMENT);
2238 metainfHolder.addMaxOccurs(sequenceQName, xmlSchemaSequence.getMaxOccurs());
2239 metainfHolder.addMinOccurs(sequenceQName, xmlSchemaSequence.getMinOccurs());
2240 metainfHolder.setHasParticleType(true);
2241
2242 if (order) {
2243 //record the order in the metainf holder for the any
2244 Integer integer = (Integer) elementOrderMap.get(child);
2245 metainfHolder.registerQNameIndex(sequenceQName,
2246 startingItemNumberOrder + integer.intValue());
2247 }
2248 } else if (child instanceof XmlSchemaChoice) {
2249 XmlSchemaChoice xmlSchemaChoice = (XmlSchemaChoice) child;
2250 QName choiceQName = (QName) particleQNameMap.get(child);
2251 boolean isArray = xmlSchemaChoice.getMaxOccurs() > 1;
2252
2253 // add this as an array to the original class
2254 metainfHolder.registerMapping(choiceQName,
2255 choiceQName,
2256 findClassName(choiceQName, isArray));
2257 if (isArray) {
2258 metainfHolder.addtStatus(choiceQName, SchemaConstants.ARRAY_TYPE);
2259 }
2260 metainfHolder.addtStatus(choiceQName, SchemaConstants.PARTICLE_TYPE_ELEMENT);
2261 metainfHolder.addMaxOccurs(choiceQName, xmlSchemaChoice.getMaxOccurs());
2262 metainfHolder.addMinOccurs(choiceQName, xmlSchemaChoice.getMinOccurs());
2263 metainfHolder.setHasParticleType(true);
2264
2265 if (order) {
2266 //record the order in the metainf holder for the any
2267 Integer integer = (Integer) elementOrderMap.get(child);
2268 metainfHolder.registerQNameIndex(choiceQName,
2269 startingItemNumberOrder + integer.intValue());
2270 }
2271 } else if (child instanceof XmlSchemaGroupRef) {
2272 XmlSchemaGroupRef xmlSchemaGroupRef = (XmlSchemaGroupRef) child;
2273 QName groupQName = (QName) particleQNameMap.get(child);
2274 boolean isArray = xmlSchemaGroupRef.getMaxOccurs() > 1;
2275
2276 // add this as an array to the original class
2277 String groupClassName = (String) processedGroupTypeMap.get(groupQName);
2278 if (isArray){
2279 groupClassName = groupClassName + "[]";
2280 }
2281 metainfHolder.registerMapping(groupQName,
2282 groupQName,
2283 groupClassName);
2284 if (isArray) {
2285 metainfHolder.addtStatus(groupQName, SchemaConstants.ARRAY_TYPE);
2286 }
2287 metainfHolder.addtStatus(groupQName, SchemaConstants.PARTICLE_TYPE_ELEMENT);
2288 metainfHolder.addMaxOccurs(groupQName, xmlSchemaGroupRef.getMaxOccurs());
2289 metainfHolder.addMinOccurs(groupQName, xmlSchemaGroupRef.getMinOccurs());
2290 metainfHolder.setHasParticleType(true);
2291
2292 if (order) {
2293 //record the order in the metainf holder for the any
2294 Integer integer = (Integer) elementOrderMap.get(child);
2295 metainfHolder.registerQNameIndex(groupQName,
2296 startingItemNumberOrder + integer.intValue());
2297 }
2298 }
2299 }
2300
2301 //set the ordered flag in the metainf holder
2302 metainfHolder.setOrdered(order);
2303 }
2304
2305 /**
2306 *
2307 * @param xmlSchemaGroup
2308 * @param schemaGroupQName- we have to pass this since xml schema does not provide
2309 * this properly
2310 * @param parentSchema
2311 * @throws SchemaCompilationException
2312 */
2313
2314 private void processGroup(XmlSchemaGroup xmlSchemaGroup,
2315 QName schemaGroupQName,
2316 XmlSchema parentSchema) throws SchemaCompilationException {
2317
2318 // find the group base item
2319 XmlSchemaGroupBase xmlSchemaGroupBase = xmlSchemaGroup.getParticle();
2320 if (xmlSchemaGroupBase != null){
2321 if (xmlSchemaGroupBase instanceof XmlSchemaSequence){
2322 XmlSchemaSequence xmlSchemaSequence = (XmlSchemaSequence) xmlSchemaGroupBase;
2323 if (xmlSchemaSequence.getItems().getCount() > 0) {
2324 BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder();
2325 process(schemaGroupQName, xmlSchemaSequence.getItems(), beanWriterMetaInfoHolder, true, parentSchema);
2326 beanWriterMetaInfoHolder.setParticleClass(true);
2327 String javaClassName = writeComplexParticle(schemaGroupQName, beanWriterMetaInfoHolder);
2328 processedGroupTypeMap.put(schemaGroupQName, javaClassName);
2329 // processedTypemap.put(schemaGroupQName, javaClassName);
2330 }
2331
2332 } else if (xmlSchemaGroupBase instanceof XmlSchemaChoice){
2333 XmlSchemaChoice xmlSchemaChoice = (XmlSchemaChoice) xmlSchemaGroupBase;
2334 if (xmlSchemaChoice.getItems().getCount() > 0) {
2335 BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder();
2336 beanWriterMetaInfoHolder.setChoice(true);
2337 process(schemaGroupQName, xmlSchemaChoice.getItems(), beanWriterMetaInfoHolder, false, parentSchema);
2338 beanWriterMetaInfoHolder.setParticleClass(true);
2339 String javaClassName = writeComplexParticle(schemaGroupQName, beanWriterMetaInfoHolder);
2340 processedGroupTypeMap.put(schemaGroupQName, javaClassName);
2341 // processedTypemap.put(schemaGroupQName, javaClassName);
2342 }
2343 }
2344 }
2345 }
2346
2347 /**
2348 * Checks whether a given element is a binary element
2349 *
2350 * @param elt
2351 */
2352 private boolean isBinary(XmlSchemaElement elt) {
2353 return elt.getSchemaType() != null &&
2354 SchemaConstants.XSD_BASE64.equals(elt.getSchemaType().getQName());
2355 }
2356
2357 /**
2358 * Checks whether a given qname is a binary
2359 *
2360 * @param qName
2361 */
2362 private boolean isBinary(QName qName) {
2363 return qName != null &&
2364 SchemaConstants.XSD_BASE64.equals(qName);
2365 }
2366
2367 /**
2368 * @param simpleType
2369 * @param xsElt
2370 * @param parentSchema
2371 * @param qname - fake Qname to use if the xsElt is null.
2372 * @throws SchemaCompilationException
2373 */
2374 private void processSimpleSchemaType(XmlSchemaSimpleType simpleType,
2375 XmlSchemaElement xsElt,
2376 XmlSchema parentSchema,
2377 QName qname) throws SchemaCompilationException {
2378
2379 String fullyQualifiedClassName = null;
2380 if (simpleType.getQName() != null) {
2381 if (processedTypemap.containsKey(simpleType.getQName())
2382 || baseSchemaTypeMap.containsKey(simpleType.getQName())) {
2383 return;
2384 }
2385
2386 // Must do this up front to support recursive types
2387 fullyQualifiedClassName = writer.makeFullyQualifiedClassName(simpleType.getQName());
2388 // we put the qname to processed type map it is only named type
2389 // otherwise we have to any way process that element.
2390 processedTypemap.put(simpleType.getQName(), fullyQualifiedClassName);
2391 } else {
2392
2393 QName fakeQname;
2394 if (xsElt != null) {
2395 fakeQname = new QName(xsElt.getQName().getNamespaceURI(), xsElt.getQName().getLocalPart() + getNextTypeSuffix(xsElt.getQName().getLocalPart()));
2396 // we have to set this otherwise the ours attribute would not set properly if refered to this simple
2397 // type from any other element
2398 xsElt.setSchemaTypeName(fakeQname);
2399 changedElementSet.add(xsElt);
2400
2401 } else {
2402 fakeQname = qname;
2403 }
2404 if (processedTypemap.containsKey(fakeQname)
2405 || baseSchemaTypeMap.containsKey(fakeQname)) {
2406 return;
2407 }
2408 fullyQualifiedClassName = writer.makeFullyQualifiedClassName(fakeQname);
2409 simpleType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.FAKE_QNAME, fakeQname);
2410
2411 // should put this to the processedTypemap to generate the code correctly
2412 processedTypemap.put(fakeQname, fullyQualifiedClassName);
2413 }
2414
2415 //register that in the schema metainfo bag
2416 simpleType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY,
2417 fullyQualifiedClassName);
2418
2419 BeanWriterMetaInfoHolder metaInfHolder = processSimpleType(simpleType, parentSchema);
2420 metaInfHolder.setSimple(true);
2421
2422 if (simpleType.getQName() == null) {
2423 this.processedAnonymousComplexTypesMap.put(xsElt, metaInfHolder);
2424 QName fakeQname;
2425 if (xsElt != null) {
2426 fakeQname = new QName(xsElt.getQName().getNamespaceURI(), xsElt.getQName().getLocalPart());
2427 } else {
2428 fakeQname = qname;
2429 simpleType.setName(fakeQname.getLocalPart());
2430 changedSimpleTypeSet.add(simpleType);
2431 simpleType.setSourceURI(fakeQname.getNamespaceURI());
2432 }
2433 simpleTypesMap.put(fakeQname, fullyQualifiedClassName);
2434 }
2435 //add this information to the metainfo holder
2436 metaInfHolder.setOwnQname(simpleType.getQName());
2437 if (fullyQualifiedClassName != null) {
2438 metaInfHolder.setOwnClassName(fullyQualifiedClassName);
2439 }
2440 //write the class. This type mapping would have been populated right now
2441 //Note - We always write classes for named complex types
2442 writeSimpleType(simpleType, metaInfHolder);
2443 }
2444
2445 private BeanWriterMetaInfoHolder processSimpleType(XmlSchemaSimpleType simpleType, XmlSchema parentSchema) throws SchemaCompilationException {
2446 BeanWriterMetaInfoHolder metaInfHolder = new BeanWriterMetaInfoHolder();
2447
2448 // handle the restriction
2449 XmlSchemaSimpleTypeContent content = simpleType.getContent();
2450 QName parentSimpleTypeQname = simpleType.getQName();
2451 if (parentSimpleTypeQname == null) {
2452 parentSimpleTypeQname = (QName) simpleType.getMetaInfoMap().get(SchemaConstants.SchemaCompilerInfoHolder.FAKE_QNAME);
2453 }
2454 if (content != null) {
2455 if (content instanceof XmlSchemaSimpleTypeRestriction) {
2456 XmlSchemaSimpleTypeRestriction restriction = (XmlSchemaSimpleTypeRestriction) content;
2457
2458 QName baseTypeName = restriction.getBaseTypeName();
2459 //check whether the base type is one of the base schema types
2460
2461 if (baseSchemaTypeMap.containsKey(baseTypeName)) {
2462 //process restriction base type
2463
2464 processSimpleRestrictionBaseType(parentSimpleTypeQname, restriction.getBaseTypeName(), metaInfHolder, parentSchema);
2465 //process facets
2466 if (!SchemaConstants.XSD_BOOLEAN.equals(baseTypeName)){
2467 processFacets(restriction, metaInfHolder, parentSchema);
2468 }
2469 } else {
2470 //recurse
2471 // this must be a xmlschema bug
2472 // it should return the schematype for restriction.getBaseType():
2473 XmlSchema resolvedSchema = getParentSchema(parentSchema, baseTypeName, COMPONENT_TYPE);
2474 if (resolvedSchema == null) {
2475 throw new SchemaCompilationException("can not find the type " + baseTypeName +
2476 " from the parent schema " + parentSchema.getTargetNamespace());
2477 } else {
2478 XmlSchemaType restrictionBaseType = resolvedSchema.getTypeByName(baseTypeName);
2479 if (restrictionBaseType instanceof XmlSchemaSimpleType) {
2480 if ((restrictionBaseType != null) && (!isAlreadyProcessed(baseTypeName))) {
2481 processSimpleSchemaType((XmlSchemaSimpleType) restrictionBaseType,
2482 null, resolvedSchema, null);
2483 }
2484 // process restriction
2485 processSimpleRestrictionBaseType(parentSimpleTypeQname,
2486 restriction.getBaseTypeName(), metaInfHolder, resolvedSchema);
2487 }
2488 }
2489
2490 }
2491 } else if (content instanceof XmlSchemaSimpleTypeUnion) {
2492 XmlSchemaSimpleTypeUnion simpleTypeUnion = (XmlSchemaSimpleTypeUnion) content;
2493 QName[] qnames = simpleTypeUnion.getMemberTypesQNames();
2494 if (qnames != null) {
2495 QName qname;
2496 for (int i = 0; i < qnames.length; i++) {
2497 qname = qnames[i];
2498 if (baseSchemaTypeMap.containsKey(qname)) {
2499 metaInfHolder.addMemberType(qname, (String) baseSchemaTypeMap.get(qname));
2500 } else {
2501 XmlSchema resolvedSchema = getParentSchema(parentSchema, qname, COMPONENT_TYPE);
2502 if (resolvedSchema == null) {
2503 throw new SchemaCompilationException("can not find the type " + qname +
2504 " from the parent schema " + parentSchema.getTargetNamespace());
2505 } else {
2506 XmlSchemaType type = resolvedSchema.getTypeByName(qname);
2507 if (type instanceof XmlSchemaSimpleType) {
2508 XmlSchemaSimpleType memberSimpleType = (XmlSchemaSimpleType) type;
2509 if (!isAlreadyProcessed(qname)) {
2510 processSimpleSchemaType(memberSimpleType, null, resolvedSchema, null);
2511 }
2512 metaInfHolder.addMemberType(qname, (String) processedTypemap.get(qname));
2513 } else {
2514 throw new SchemaCompilationException("Unions can not have complex types as a member type");
2515 }
2516 }
2517 }
2518 }
2519 } else {
2520 XmlSchemaObjectCollection xmlSchemaObjectCollection = simpleTypeUnion.getBaseTypes();
2521 XmlSchemaObject xmlSchemaObject;
2522 QName childQname;
2523 int i = 1;
2524 for (Iterator iter = xmlSchemaObjectCollection.getIterator(); iter.hasNext();) {
2525 xmlSchemaObject = (XmlSchemaObject) iter.next();
2526 i++;
2527 if (xmlSchemaObject instanceof XmlSchemaSimpleType) {
2528 XmlSchemaSimpleType unionSimpleType = (XmlSchemaSimpleType) xmlSchemaObject;
2529 childQname = unionSimpleType.getQName();
2530 if (childQname == null) {
2531 // we create a fake Qname for all these simple types since most propably they don't have one
2532 childQname = new QName(parentSimpleTypeQname.getNamespaceURI(), parentSimpleTypeQname.getLocalPart() + getNextTypeSuffix(parentSimpleTypeQname.getLocalPart()));
2533 }
2534 // this is an inner simple type of the union so it shold not have
2535 // processed
2536 processSimpleSchemaType(unionSimpleType, null, parentSchema, childQname);
2537 metaInfHolder.addMemberType(childQname, (String) processedTypemap.get(childQname));
2538 }
2539
2540 }
2541 }
2542
2543 metaInfHolder.setUnion(true);
2544
2545 } else if (content instanceof XmlSchemaSimpleTypeList) {
2546 XmlSchemaSimpleTypeList simpleTypeList = (XmlSchemaSimpleTypeList) content;
2547 QName itemTypeQName = simpleTypeList.getItemTypeName();
2548
2549 if (itemTypeQName != null) {
2550 if (!isAlreadyProcessed(itemTypeQName)) {
2551 XmlSchema resolvedSchema = getParentSchema(parentSchema, itemTypeQName, COMPONENT_TYPE);
2552 if (resolvedSchema == null) {
2553 throw new SchemaCompilationException("can not find the type " + itemTypeQName +
2554 " from the parent type " + parentSchema.getTargetNamespace());
2555 } else {
2556 XmlSchemaType simpleSchemaType = resolvedSchema.getTypeByName(itemTypeQName);
2557 if (simpleSchemaType instanceof XmlSchemaSimpleType) {
2558 processSimpleSchemaType((XmlSchemaSimpleType) simpleSchemaType, null, resolvedSchema, null);
2559 }
2560 }
2561 }
2562 } else {
2563 XmlSchemaSimpleType listSimpleType = simpleTypeList.getItemType();
2564 itemTypeQName = listSimpleType.getQName();
2565 if (itemTypeQName == null) {
2566 // we create a fake Qname for all these simple types since most propably they don't have one
2567 itemTypeQName = new QName(parentSimpleTypeQname.getNamespaceURI(), parentSimpleTypeQname.getLocalPart() + "_type0");
2568 }
2569 processSimpleSchemaType(listSimpleType, null, parentSchema, itemTypeQName);
2570
2571 }
2572
2573 String className = findClassName(itemTypeQName, false);
2574 metaInfHolder.setList(true);
2575 metaInfHolder.setItemTypeQName(itemTypeQName);
2576 metaInfHolder.setItemTypeClassName(className);
2577
2578 }
2579 }
2580 return metaInfHolder;
2581 }
2582
2583
2584 /**
2585 * Find whether a given particle is an array. The logic for deciding
2586 * whether a given particle is an array is depending on their minOccurs
2587 * and maxOccurs counts. If Maxoccurs is greater than one (1) then the
2588 * content is an array.
2589 * Also no higher level element will have the maxOccurs greater than one
2590 *
2591 * @param particle
2592 * @throws SchemaCompilationException
2593 */
2594 private boolean isArray(XmlSchemaParticle particle) throws SchemaCompilationException {
2595 long minOccurs = particle.getMinOccurs();
2596 long maxOccurs = particle.getMaxOccurs();
2597
2598 if (maxOccurs < minOccurs) {
2599 throw new SchemaCompilationException();
2600 } else {
2601 return (maxOccurs > 1);
2602 }
2603
2604 }
2605
2606 HashMap mapTypeCount = new HashMap();
2607 private String getNextTypeSuffix(String localName) {
2608 Integer typeCounter = (Integer) mapTypeCount.get(localName);
2609 int count = 0;
2610 if (typeCounter != null) {
2611 if(typeCounter.intValue() == Integer.MAX_VALUE) {
2612 count = 0;
2613 } else {
2614 count = typeCounter.intValue();
2615 }
2616 }
2617 mapTypeCount.put(localName, new Integer(count+1));
2618 return ("_type" + count);
2619 }
2620
2621 /**
2622 * returns the parent schema of the componet having QName compoentTypeQName.
2623 * withe the componet type.
2624 * @param parentSchema - parent schema of the given componet
2625 * @param componentQName - qname of the componet, of which we want to get the parent schema
2626 * @param componetType - type of the componet. this can either be type,element,attribute or attribute group
2627 * @return parent schema.
2628 */
2629
2630 private XmlSchema getParentSchema(XmlSchema parentSchema,
2631 QName componentQName,
2632 int componetType) throws SchemaCompilationException {
2633 // if the componet do not have a propernamesapce or
2634 // it is equals to the xsd schema namesapce
2635 // we do not have to do any thing.
2636 if ((componentQName == null) ||
2637 (componentQName.getNamespaceURI() == null) ||
2638 Constants.URI_2001_SCHEMA_XSD.equals(componentQName.getNamespaceURI())){
2639 return parentSchema;
2640 }
2641
2642 List visitedSchemas = new ArrayList();
2643 visitedSchemas.add(parentSchema);
2644 XmlSchema newParentSchema = getParentSchemaFromIncludes(parentSchema,
2645 componentQName,componetType,visitedSchemas);
2646 if (newParentSchema == null){
2647 String targetNamespace = componentQName.getNamespaceURI();
2648 if (loadedSchemaMap.containsKey(targetNamespace)){
2649 XmlSchema tempSchema = (XmlSchema) loadedSchemaMap.get(targetNamespace);
2650 if (isComponetExists(tempSchema,componentQName,componetType)){
2651 newParentSchema = tempSchema;
2652 }
2653 } else if (availableSchemaMap.containsKey(targetNamespace)){
2654 XmlSchema tempSchema = (XmlSchema) availableSchemaMap.get(targetNamespace);
2655 if (isComponetExists(tempSchema,componentQName,componetType)){
2656 compile(tempSchema);
2657 newParentSchema = tempSchema;
2658 }
2659 }
2660 }
2661 return newParentSchema;
2662 }
2663
2664 private XmlSchema getParentSchemaFromIncludes(XmlSchema parentSchema,
2665 QName componentQName,
2666 int componetType,
2667 List visitedSchemas) throws SchemaCompilationException {
2668
2669 XmlSchema newParentSchema = null;
2670 if (isComponetExists(parentSchema, componentQName, componetType)) {
2671 newParentSchema = parentSchema;
2672 } else {
2673 // this componet must either be in a import or and include
2674 XmlSchemaObjectCollection includes = parentSchema.getIncludes();
2675 if (includes != null) {
2676 Object externalComponet = null;
2677 XmlSchema externalSchema = null;
2678 for (Iterator iter = includes.getIterator(); iter.hasNext();) {
2679 externalComponet = iter.next();
2680 if (externalComponet instanceof XmlSchemaExternal) {
2681 externalSchema = ((XmlSchemaExternal) externalComponet).getSchema();
2682
2683 // if this is an inline import without a schema location
2684 // xmlschema does not load the schema.
2685 // so we try to figure out it either from the available schemas
2686 // or from the laded schemas.
2687 if ((externalSchema == null) && externalComponet instanceof XmlSchemaImport){
2688 XmlSchemaImport xmlSchemaImport = (XmlSchemaImport) externalComponet;
2689 String importNamespce = xmlSchemaImport.getNamespace();
2690 if ((importNamespce != null) && !importNamespce.equals(Constants.URI_2001_SCHEMA_XSD)) {
2691 if (loadedSchemaMap.containsKey(importNamespce)) {
2692 externalSchema = (XmlSchema) loadedSchemaMap.get(importNamespce);
2693 } else if (availableSchemaMap.containsKey(importNamespce)) {
2694 XmlSchema tempSchema = (XmlSchema) availableSchemaMap.get(importNamespce);
2695 compile(tempSchema);
2696 externalSchema = tempSchema;
2697 }
2698 }
2699 }
2700 if (externalSchema != null) {
2701 // find the componet in the new external schema.
2702 if (!visitedSchemas.contains(externalSchema)){
2703 visitedSchemas.add(externalSchema);
2704 newParentSchema = getParentSchemaFromIncludes(externalSchema,
2705 componentQName, componetType, visitedSchemas);
2706 }
2707 }
2708 if (newParentSchema != null) {
2709 // i.e we have found the schema
2710 break;
2711 }
2712 }
2713 }
2714 }
2715 }
2716 return newParentSchema;
2717 }
2718
2719 private boolean isComponetExists(XmlSchema schema,
2720 QName componentQName,
2721 int componetType) {
2722 boolean isExists = false;
2723 if (!schema.getTargetNamespace().equals(componentQName.getNamespaceURI())){
2724 return false;
2725 }
2726 switch (componetType) {
2727 case COMPONENT_TYPE : {
2728 isExists = (schema.getTypeByName(componentQName.getLocalPart()) != null);
2729 break;
2730 }
2731 case COMPONENT_ELEMENT : {
2732 isExists = (schema.getElementByName(componentQName.getLocalPart()) != null);
2733 break;
2734 }
2735 case COMPONENT_ATTRIBUTE : {
2736 isExists = (schema.getAttributes().getItem(componentQName) != null);
2737 break;
2738 }
2739 case COMPONENT_ATTRIBUTE_GROUP : {
2740 isExists = (schema.getAttributeGroups().getItem(componentQName) != null);
2741 break;
2742 }
2743 case COMPONENT_GROUP : {
2744 isExists = (schema.getGroups().getItem(componentQName) != null);
2745 break;
2746 }
2747 }
2748 return isExists;
2749 }
2750 }