/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.axis2.schema; import org.apache.axis2.namespace.Constants; import org.apache.axis2.schema.i18n.SchemaCompilerMessages; import org.apache.axis2.schema.util.PrimitiveTypeFinder; import org.apache.axis2.schema.util.PrimitiveTypeWrapper; import org.apache.axis2.schema.util.SchemaPropertyLoader; import org.apache.axis2.schema.writer.BeanWriter; import org.apache.axis2.util.SchemaUtil; import org.apache.axis2.util.URLProcessor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ws.commons.schema.*; import org.apache.ws.commons.schema.utils.XmlSchemaObjectBase; import org.xml.sax.InputSource; import javax.xml.namespace.QName; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; /** * Schema compiler for ADB. Based on WS-Commons schema object model. */ public class SchemaCompiler { public static final int COMPONENT_TYPE = 1; public static final int COMPONENT_ELEMENT = 2; public static final int COMPONENT_ATTRIBUTE = 3; public static final int COMPONENT_ATTRIBUTE_GROUP = 4; public static final int COMPONENT_GROUP = 5; private static final Log log = LogFactory.getLog(SchemaCompiler.class); private CompilerOptions options; private HashMap<QName, String> processedTypemap; // have to keep a seperate group type map since same // name can be used to group and complextype private HashMap<QName, String> processedGroupTypeMap; //the list of processedElements for the outer elements private HashMap<QName, String> processedElementMap; //need to use IdentityHashMap to store processedAnonymousComplexTypes //because the key used with the map, XmlSchemaElement, is not immutable private IdentityHashMap<XmlSchemaElement, BeanWriterMetaInfoHolder> processedAnonymousComplexTypesMap; //we need this map to keep the referenced elements. these elements need to be kept seperate //to avoid conflicts private HashMap<QName, String> processedElementRefMap; private HashMap<QName, String> simpleTypesMap; private HashMap<QName, QName> changedTypeMap; private HashSet<XmlSchemaSimpleType> changedSimpleTypeSet; private HashSet<XmlSchemaComplexType> changedComplexTypeSet; private HashSet<XmlSchemaElement> changedElementSet; // this map is necessary to retain the metainformation of types. The reason why these // meta info 'bags' would be useful later is to cater for the extensions and restrictions // of types private HashMap<QName, BeanWriterMetaInfoHolder> processedTypeMetaInfoMap; // private ArrayList<QName> processedElementList; //a list of nillable elements - used to generate code //for nillable elements private List<QName> nillableElementList; // writee reference private BeanWriter writer = null; private Map<QName, String> baseSchemaTypeMap = null; //a map for keeping the already loaded schemas //the key is the targetnamespace and the value is the schema object private Map<String, XmlSchema> loadedSchemaMap = new HashMap<String, XmlSchema>(); // A map keeping the available schemas //the key is the targetnamespace and the value is the schema object //this map will be populated when multiple schemas //are fed to the schema compiler! private Map<String, XmlSchema> availableSchemaMap = new HashMap<String, XmlSchema>(); private Map<String, String> loadedSourceURI = new HashMap<String, String>(); // a list of externally identified QNames to be processed. This becomes // useful when only a list of external elements need to be processed public static final String ANY_ELEMENT_FIELD_NAME = "extraElement"; public static final String EXTRA_ATTRIBUTE_FIELD_NAME = "extraAttributes"; public static final String USE_OPTIONAL = "optional"; public static final String USE_REQUIRED = "required"; public static final String USE_NONE = "none"; /** * @return the processes element map * includes the Qname of the element as the key and a * String representing the fully qualified class name */ public HashMap<QName, String> getProcessedElementMap() { return processedElementMap; } /** * @return a map of Qname vs models. A model can be anything, * ranging from a DOM document to a stream. This is taken from the * writer and the schema compiler has no control over it */ public Map getProcessedModelMap() { return writer.getModelMap(); } /** * Constructor - Accepts a options bean * * @param options */ public SchemaCompiler(CompilerOptions options) throws SchemaCompilationException { if (options == null) { //create an empty options object this.options = new CompilerOptions(); } else { this.options = options; } Map<String, String> nsp2PackageMap = this.options.getNs2PackageMap(); if (nsp2PackageMap == null) { nsp2PackageMap = new HashMap(); this.options.setNs2PackageMap(nsp2PackageMap); } if (!nsp2PackageMap.containsKey("")) { nsp2PackageMap.put("", "axis2.apache.org"); } //instantiate the maps processedTypemap = new HashMap<QName, String>(); processedGroupTypeMap = new HashMap<QName, String>(); processedElementMap = new HashMap<QName, String>(); simpleTypesMap = new HashMap<QName, String>(); processedElementList = new ArrayList<QName>(); processedAnonymousComplexTypesMap = new IdentityHashMap<XmlSchemaElement, BeanWriterMetaInfoHolder>(); changedTypeMap = new HashMap<QName, QName>(); processedTypeMetaInfoMap = new HashMap<QName, BeanWriterMetaInfoHolder>(); processedElementRefMap = new HashMap<QName, String>(); nillableElementList = new ArrayList<QName>(); changedComplexTypeSet = new HashSet<XmlSchemaComplexType>(); changedSimpleTypeSet = new HashSet<XmlSchemaSimpleType>(); changedElementSet = new HashSet<XmlSchemaElement>(); //load the writer and initiliaze the base types writer = SchemaPropertyLoader.getBeanWriterInstance(); writer.init(this.options); //load the base types baseSchemaTypeMap = SchemaPropertyLoader.getTypeMapperInstance().getTypeMap(); } /** * Compile a list of schemas * This actually calls the compile (XmlSchema s) method repeatedly * * @param schemalist * @throws SchemaCompilationException * @see #compile(org.apache.ws.commons.schema.XmlSchema) */ public void compile(List<XmlSchema> schemalist) throws SchemaCompilationException { try { if (schemalist.isEmpty()) { return; } //clear the loaded and available maps loadedSchemaMap.clear(); availableSchemaMap.clear(); // first round - populate the avaialble map for (XmlSchema schema : schemalist) { availableSchemaMap.put( schema.getTargetNamespace(), schema); } //set a mapper package if not avaialable if (writer.getExtensionMapperPackageName() == null) { String nsp = null; //get the first schema from the list and take that namespace as the //mapper namespace for (XmlSchema schema : schemalist) { nsp = schema.getTargetNamespace(); if ((nsp != null) && !nsp.equals("")) { break; } XmlSchema[] schemas = SchemaUtil.getAllSchemas(schema); for (int j = 0; schemas != null && j < schemas.length; j++) { nsp = schemas[j].getTargetNamespace(); if (nsp != null) { break; } } } if (nsp == null) { nsp = URLProcessor.DEFAULT_PACKAGE; } // if this name space exists in the ns2p list then we use it. if ((options.getNs2PackageMap() != null) && (options.getNs2PackageMap().containsKey(nsp))) { writer.registerExtensionMapperPackageName(options.getNs2PackageMap().get(nsp)); } else { writer.registerExtensionMapperPackageName(nsp == null ? null : URLProcessor.makePackageName(nsp)); } } // second round - call the schema compiler one by one for (XmlSchema schema : schemalist) { compile(schema, true); } //finish up finalizeSchemaCompilation(); } catch (SchemaCompilationException e) { throw e; } catch (Exception e) { throw new SchemaCompilationException(e); } } /** * Compile (rather codegen) a single schema element * * @param schema * @throws SchemaCompilationException */ public void compile(XmlSchema schema) throws SchemaCompilationException { compile(schema, false); } /** * Compile (rather codegen) a single schema element * * @param schema * @param isPartofGroup * @throws SchemaCompilationException */ private void compile(XmlSchema schema, boolean isPartofGroup) throws SchemaCompilationException { // some documents explicitly imports the schema of built in types. We don't actually need to compile // the built-in types. So check the target namespace here and ignore it. if (Constants.URI_2001_SCHEMA_XSD.equals(schema.getTargetNamespace())) { return; } //register the package from this namespace as the mapper classes package if (!isPartofGroup) { //set a mapper package if not avaialable if (writer.getExtensionMapperPackageName() == null) { String ns = schema.getTargetNamespace(); if (ns == null) { ns = URLProcessor.DEFAULT_PACKAGE; } // if this name space exists in the ns2p list then we use it. if ((options.getNs2PackageMap() != null) && (options.getNs2PackageMap().containsKey(ns))) { writer.registerExtensionMapperPackageName(options.getNs2PackageMap().get(ns)); } else { writer.registerExtensionMapperPackageName(URLProcessor.makePackageName(ns)); } } } //First look for the schemas that are imported and process them //Note that these are processed recursively! //add the schema to the loaded schema list if (!loadedSchemaMap.containsKey(schema.getTargetNamespace())) { loadedSchemaMap.put(schema.getTargetNamespace(), schema); // when the target name space is not given schema.getTargetNamesapce returns null. // but when importing import namesapce location is given as "". // this causese a problem in finding reference elements. see AXIS2-3029 // kept the null entry as well to safe gaurd any thing which acess using null if (schema.getTargetNamespace() == null) { loadedSchemaMap.put("", schema); } } // If we have/are loading a schema with a specific targetnamespace from a certain URI, // then just return back to the caller to avoid recursion. if (schema.getSourceURI() != null) { String key = schema.getTargetNamespace() + ":" + schema.getSourceURI(); if (loadedSourceURI.containsKey(key)) { return; } loadedSourceURI.put(key, key); } for (XmlSchemaObject object : schema.getExternals()) { if (object instanceof XmlSchemaImport) { XmlSchemaImport schemaImport = (XmlSchemaImport) object; XmlSchema schema1 = schemaImport.getSchema(); if (schema1 != null) { compile(schema1, isPartofGroup); } else if (schemaImport.getNamespace().equals(Constants.NS_URI_XML)) { // AXIS2-3229: some Web services (e.g. MS Exchange) assume that // http://www.w3.org/XML/1998/namespace is a known namespace and that // no schemaLocation is required when importing it. Load a local copy of // the schema in that case. schema1 = new XmlSchemaCollection().read(new InputSource( SchemaCompiler.class.getResource("namespace.xsd").toExternalForm())); schemaImport.setSchema(schema1); compile(schema1, isPartofGroup); } else if (!schemaImport.getNamespace().equals(Constants.URI_2001_SCHEMA_XSD)) { // Give the user a hint why the schema compilation fails... log.warn("No schemaLocation for import of " + schemaImport.getNamespace() + "; compilation may fail"); } } if (object instanceof XmlSchemaInclude) { XmlSchema schema1 = ((XmlSchemaInclude) object).getSchema(); if (schema1 != null) { if (schema1.getTargetNamespace() == null) { // the target namespace of an included shchema should be same // as the parent schema however if the schema uses the chemalon pattern // target namespace can be null. so set it here. // http://www.xfront.com/ZeroOneOrManyNamespaces.html#mixed schema1.setTargetNamespace(schema.getTargetNamespace()); } compile(schema1, isPartofGroup); } } } //select all the elements. We generate the code for types //only if the elements refer them!!! regardless of the fact that //we have a list of elementnames, we'll need to process all the elements for (XmlSchemaElement element : schema.getElements().values()) { //this is the set of outer elements so we need to generate classes //The outermost elements do not contain occurence counts (!) so we do not need //to check for arraytypes processElement(element, schema); } // re-iterate through the elements and write them one by one // if the mode is unpack this process will not really write the // classes but will accumilate the models for a final single shot // write for (XmlSchemaElement element : schema.getElements().values()) { //this is the set of outer elements so we need to generate classes writeElement(element); } if (options.isGenerateAll()) { for (XmlSchemaType schemaType : schema.getSchemaTypes().values()) { if (this.isAlreadyProcessed(schemaType.getQName())) { continue; } if (schemaType instanceof XmlSchemaComplexType) { //write classes for complex types XmlSchemaComplexType complexType = (XmlSchemaComplexType) schemaType; if (complexType.getName() != null) { processNamedComplexSchemaType(complexType, schema); } } else if (schemaType instanceof XmlSchemaSimpleType) { //process simple type processSimpleSchemaType((XmlSchemaSimpleType) schemaType, null, schema, null); } } } if (!isPartofGroup) { //complete the compilation finalizeSchemaCompilation(); } } /** * Completes the schema compilation process by writing the * mappers and the classes in a batch if needed * * @throws SchemaCompilationException */ private void finalizeSchemaCompilation() throws SchemaCompilationException { //write the extension mapping class writer.writeExtensionMapper( processedTypeMetaInfoMap.values().toArray( new BeanWriterMetaInfoHolder[processedTypeMetaInfoMap.size()])); if (options.isWrapClasses()) { writer.writeBatch(); } // resets the changed types for (XmlSchemaComplexType xmlSchemaComplexType : changedComplexTypeSet) { xmlSchemaComplexType.setName(null); } for (XmlSchemaSimpleType xmlSchemaSimpleType : changedSimpleTypeSet) { xmlSchemaSimpleType.setName(null); } for (XmlSchemaElement xmlSchemaElement : changedElementSet) { xmlSchemaElement.setSchemaTypeName(null); } } /** * @return the property map of the schemacompiler. * In this case it would be the property map loaded from * the configuration file */ public Properties getCompilerProperties() { return SchemaPropertyLoader.getPropertyMap(); } /** * Writes the element * * @param xsElt * @throws SchemaCompilationException */ private void writeElement(XmlSchemaElement xsElt) throws SchemaCompilationException { if (this.processedElementMap.containsKey(xsElt.getQName())) { return; } XmlSchemaType schemaType = xsElt.getSchemaType(); BeanWriterMetaInfoHolder metainf = new BeanWriterMetaInfoHolder(); if (schemaType != null && schemaType.getName() != null) { //this is a named type QName qName = schemaType.getQName(); //find the class name String className = findClassName(qName, isArray(xsElt)); // element declared at the top level and have simple types may // use primitive type if we do not add this check if (options.isUseWrapperClasses() && PrimitiveTypeFinder.isPrimitive(className)) { className = PrimitiveTypeWrapper.getWrapper(className); } //this means the schema type actually returns a different QName if (changedTypeMap.containsKey(qName)) { metainf.registerMapping(xsElt.getQName(), changedTypeMap.get(qName), className); } else { metainf.registerMapping(xsElt.getQName(), qName, className); } // register the default value if present if (xsElt.getDefaultValue() != null) { metainf.registerDefaultValue(xsElt.getQName(), xsElt.getDefaultValue()); } // register the fixed value if present if (xsElt.getFixedValue() != null) { metainf.registerDefaultValue(xsElt.getQName(), xsElt.getFixedValue()); metainf.registerFixedQName(xsElt.getQName()); } if (isBinary(xsElt)) { metainf.addtStatus(xsElt.getQName(), SchemaConstants.BINARY_TYPE); } } else if (xsElt.getRef().getTargetQName() != null) { // Since top level elements would not have references // and we only write toplevel elements, this should // not be a problem , atleast should not occur in a legal schema } else if (xsElt.getSchemaTypeName() != null) { QName qName = xsElt.getSchemaTypeName(); String className = findClassName(qName, isArray(xsElt)); metainf.registerMapping(xsElt.getQName(), qName, className); } else if (schemaType != null) { //the named type should have been handled already //we are going to special case the anonymous complex type. Our algorithm for dealing //with it is to generate a single object that has the complex content inside. Really the //intent of the user when he declares the complexType anonymously is to use it privately //First copy the schema types content into the metainf holder metainf = this.processedAnonymousComplexTypesMap.get(xsElt); metainf.setAnonymous(true); } else { //this means we did not find any schema type associated with the particular element. log.warn(SchemaCompilerMessages.getMessage("schema.elementWithNoType", xsElt.getQName().toString())); metainf.registerMapping(xsElt.getQName(), null, writer.getDefaultClassName(), SchemaConstants.ANY_TYPE); } if (nillableElementList.contains(xsElt.getQName())) { metainf.registerNillableQName(xsElt.getQName()); } String writtenClassName = writer.write(xsElt, processedTypemap, processedGroupTypeMap, metainf); //register the class name xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, writtenClassName); processedElementMap.put(xsElt.getQName(), writtenClassName); } /** * For inner elements * * @param xsElt * @param innerElementMap * @param parentSchema * @throws SchemaCompilationException */ private void processElement(XmlSchemaElement xsElt, Map<QName, String> innerElementMap, List<QName> localNillableList, XmlSchema parentSchema) throws SchemaCompilationException { processElement(xsElt, false, innerElementMap, localNillableList, parentSchema); } /** * For outer elements * * @param xsElt * @param parentSchema * @throws SchemaCompilationException */ private void processElement(XmlSchemaElement xsElt, XmlSchema parentSchema) throws SchemaCompilationException { processElement(xsElt, true, null, null, parentSchema); } /** * Process and Element * * @param xsElt * @param isOuter We need to know this since the treatment of outer elements is different that * inner elements * @throws SchemaCompilationException */ private void processElement(XmlSchemaElement xsElt, boolean isOuter, Map<QName, String> innerElementMap, List<QName> localNillableList, XmlSchema parentSchema) throws SchemaCompilationException { //if the element is null, which usually happens when the qname is not //proper, throw an exceptions if (xsElt == null) { throw new SchemaCompilationException( SchemaCompilerMessages.getMessage("schema.elementNull")); } //The processing element logic seems to be quite simple. Look at the relevant schema type //for each and every element and process that accordingly. //this means that any unused type definitions would not be generated! if (isOuter && processedElementList.contains(xsElt.getQName())) { return; } XmlSchemaType schemaType = xsElt.getSchemaType(); if (schemaType != null) { processSchema(xsElt, schemaType, parentSchema, false); //at this time it is not wise to directly write the class for the element //so we push the complete element to an arraylist and let the process //pass through. We'll be iterating through the elements writing them //later if (!isOuter) { if (schemaType.getName() != null) { // this element already has a name. Which means we can directly // register it String className = findClassName(schemaType.getQName(), isArray(xsElt)); innerElementMap.put(xsElt.getWireName(), className); // always store the class name in the element meta Info itself // this details only needed by the unwrappig to set the complex type if (options.isUseWrapperClasses() && PrimitiveTypeFinder.isPrimitive(className)) { className = PrimitiveTypeWrapper.getWrapper(className); } schemaType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, className); xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, className); if (baseSchemaTypeMap.containsValue(className)) { schemaType.addMetaInfo( SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_PRIMITVE_KEY, Boolean.TRUE); } //since this is a inner element we should add it to the inner element map } else { //this is an anon type. This should have been already processed and registered at //the anon map. we've to write it just like we treat a referenced type(giving due //care that this is meant to be an attribute in some class) QName generatedTypeName = generateTypeQName(xsElt.getWireName(), parentSchema); if (schemaType instanceof XmlSchemaComplexType) { //set a name schemaType.setName(generatedTypeName.getLocalPart()); changedComplexTypeSet.add((XmlSchemaComplexType) schemaType); // Must do this up front to support recursive types String fullyQualifiedClassName = writer. makeFullyQualifiedClassName(schemaType.getQName()); processedTypemap.put(schemaType.getQName(), fullyQualifiedClassName); BeanWriterMetaInfoHolder metaInfHolder = processedAnonymousComplexTypesMap.get(xsElt); metaInfHolder.setOwnQname(schemaType.getQName()); metaInfHolder.setOwnClassName(fullyQualifiedClassName); writeComplexType((XmlSchemaComplexType) schemaType, metaInfHolder); //remove the reference from the anon list since we named the type processedAnonymousComplexTypesMap.remove(xsElt); String className = findClassName(schemaType.getQName(), isArray(xsElt)); innerElementMap.put( xsElt.getWireName(), className); //store in the schema map to retrive in the unwrapping xsElt.addMetaInfo( SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, className); } else if (schemaType instanceof XmlSchemaSimpleType) { //set a name schemaType.setName(generatedTypeName.getLocalPart()); changedSimpleTypeSet.add((XmlSchemaSimpleType) schemaType); // Must do this up front to support recursive types String fullyQualifiedClassName = writer. makeFullyQualifiedClassName(schemaType.getQName()); processedTypemap.put(schemaType.getQName(), fullyQualifiedClassName); BeanWriterMetaInfoHolder metaInfHolder = processedAnonymousComplexTypesMap.get(xsElt); metaInfHolder.setOwnQname(schemaType.getQName()); metaInfHolder.setOwnClassName(fullyQualifiedClassName); writeSimpleType((XmlSchemaSimpleType) schemaType, metaInfHolder); //remove the reference from the anon list since we named the type processedAnonymousComplexTypesMap.remove(xsElt); String className = findClassName(schemaType.getQName(), isArray(xsElt)); innerElementMap.put( xsElt.getWireName(), className); //store in the schema map xsElt.addMetaInfo( SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, className); } } } else { // set the binary status of this element this.processedElementList.add(xsElt.getQName()); } //referenced name } else if (xsElt.getRef().getTargetQName() != null) { if (xsElt.getRef().getTargetQName().equals(SchemaConstants.XSD_SCHEMA)) { innerElementMap.put(xsElt.getQName(), writer.getDefaultClassName()); return; } //process the referenced type. It could be thought that the referenced element replaces this //element XmlSchema resolvedSchema = getParentSchema(parentSchema, xsElt.getRef().getTargetQName(), COMPONENT_ELEMENT); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the element " + xsElt.getRef().getTargetQName() + " from the parent schema " + parentSchema.getTargetNamespace()); } XmlSchemaElement referencedElement = resolvedSchema. getElementByName(xsElt.getRef().getTargetQName()); if (referencedElement == null) { throw new SchemaCompilationException( SchemaCompilerMessages. getMessage("schema.referencedElementNotFound", xsElt.getRef().getTargetQName().toString())); } // here what we want is to set the schema type name for the element if ((referencedElement.getSchemaType() != null) && (referencedElement.getSchemaType().getQName() != null)) { // i.e this element refers to an complex type name if (!this.processedElementRefMap.containsKey(referencedElement.getQName())) { if (this.baseSchemaTypeMap.containsKey(referencedElement.getSchemaTypeName())) { this.processedElementRefMap.put(referencedElement.getQName(), this.baseSchemaTypeMap. get(referencedElement. getSchemaTypeName())); } else { XmlSchema resolvedTypeSchema = getParentSchema(resolvedSchema, referencedElement. getSchemaTypeName(), COMPONENT_TYPE); XmlSchemaType xmlSchemaType = resolvedTypeSchema.getTypeByName( referencedElement.getSchemaTypeName().getLocalPart()); processSchema(referencedElement, xmlSchemaType, resolvedTypeSchema, true); this.processedElementRefMap.put(referencedElement.getQName(), this.processedTypemap. get(referencedElement. getSchemaTypeName())); } } String javaClassName; if (this.baseSchemaTypeMap.containsKey(referencedElement.getSchemaTypeName())) { // here we have to do nothing since we do not generate a name } else { javaClassName = this.processedTypemap.get(referencedElement.getSchemaTypeName()); referencedElement.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder. CLASSNAME_KEY, javaClassName); xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, javaClassName); } } else if (referencedElement.getSchemaType() != null) { if (!this.processedElementRefMap.containsKey(referencedElement.getQName())) { processSchema(referencedElement, referencedElement.getSchemaType(), resolvedSchema, true); // if this is an anonomous complex type we have to set this this.processedElementRefMap.put(referencedElement.getQName(), this.processedTypemap.get(referencedElement. getSchemaTypeName())); } String javaClassName = this.processedTypemap. get(referencedElement.getSchemaTypeName()); referencedElement.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, javaClassName); xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, javaClassName); } else if (referencedElement.getSchemaTypeName() != null) { QName schemaTypeName = referencedElement.getSchemaTypeName(); XmlSchema newResolvedSchema = getParentSchema(resolvedSchema, schemaTypeName, COMPONENT_TYPE); XmlSchemaType xmlSchemaType = newResolvedSchema.getTypeByName(schemaTypeName); if (xmlSchemaType != null) { if (!this.processedElementRefMap.containsKey(referencedElement.getQName())) { // we know this is a named complex type processSchema(referencedElement, xmlSchemaType, newResolvedSchema, false); // if this is an anonomous complex type we have to set this this.processedElementRefMap.put(referencedElement.getQName(), this.processedTypemap.get(schemaTypeName)); } String javaClassName = this.processedTypemap.get(referencedElement. getSchemaTypeName()); referencedElement.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder. CLASSNAME_KEY, javaClassName); xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, javaClassName); } else { throw new SchemaCompilationException(" Can not find the schema type with name " + schemaTypeName); } } // schema type name is present but not the schema type object } else if (xsElt.getSchemaTypeName() != null) { //There can be instances where the SchemaType is null but the schemaTypeName is not! //this specifically happens with xsd:anyType. QName schemaTypeName = xsElt.getSchemaTypeName(); XmlSchema resolvedSchema = getParentSchema(parentSchema, schemaTypeName, COMPONENT_TYPE); XmlSchemaType typeByName = null; if (resolvedSchema != null) { typeByName = resolvedSchema.getTypeByName(schemaTypeName); } if (typeByName != null) { //this type is found in the schema so we can process it processSchema(xsElt, typeByName, resolvedSchema, false); if (!isOuter) { String className = findClassName(schemaTypeName, isArray(xsElt)); //since this is a inner element we should add it to the inner element map innerElementMap.put(xsElt.getWireName(), className); // set the class name to be used in unwrapping xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, className); } else { this.processedElementList.add(xsElt.getQName()); } } else { //this type is not found at all. we'll just register it with whatever the class name we can comeup with if (!isOuter) { String className = findClassName(schemaTypeName, isArray(xsElt)); innerElementMap.put(xsElt.getWireName(), className); // set the class name to be used in unwrapping xsElt.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, className); } else { this.processedElementList.add(xsElt.getQName()); } } } //add this elements QName to the nillable group if it has the nillable attribute if (xsElt.isNillable()) { if (isOuter) { this.nillableElementList.add(xsElt.getQName()); } else { localNillableList.add(xsElt.getWireName()); } } } /** * Generate a unique type Qname using an element name * * @param referenceEltQName * @param parentSchema */ private QName generateTypeQName(QName referenceEltQName, XmlSchema parentSchema) { QName generatedTypeName = new QName(referenceEltQName.getNamespaceURI(), referenceEltQName.getLocalPart() + getNextTypeSuffix(referenceEltQName.getLocalPart())); while (parentSchema.getTypeByName(generatedTypeName) != null) { generatedTypeName = new QName(referenceEltQName.getNamespaceURI(), referenceEltQName.getLocalPart() + getNextTypeSuffix(referenceEltQName.getLocalPart())); } return generatedTypeName; } /** * Finds whether a given class is already made * * @param qName */ private boolean isAlreadyProcessed(QName qName) { return processedTypemap.containsKey(qName) || simpleTypesMap.containsKey(qName) || baseSchemaTypeMap.containsKey(qName) || processedGroupTypeMap.containsKey(qName); } /** * A method to pick the ref class name * * @param name * @param isArray */ private String findRefClassName(QName name, boolean isArray) { String className = null; if (processedElementRefMap.get(name) != null) { className = processedElementRefMap.get(name); if (isArray) { //append the square braces that say this is an array //hope this works for all cases!!!!!!! //todo this however is a thing that needs to be //todo fixed to get complete language support className = className + "[]"; } } return className; } /** * Finds a class name from the given Qname * * @param qName * @param isArray * @return FQCN */ private String findClassName(QName qName, boolean isArray) throws SchemaCompilationException { //find the class name String className; if (processedTypemap.containsKey(qName)) { className = processedTypemap.get(qName); } else if (simpleTypesMap.containsKey(qName)) { className = simpleTypesMap.get(qName); } else if (baseSchemaTypeMap.containsKey(qName)) { className = baseSchemaTypeMap.get(qName); } else { if (isSOAP_ENC(qName.getNamespaceURI())) { throw new SchemaCompilationException(SchemaCompilerMessages. getMessage("schema.soapencoding.error", qName.toString())); } // We seem to have failed in finding a class name for the //contained schema type. We better set the default then //however it's better if the default can be set through the //property file className = writer.getDefaultClassName(); log.warn(SchemaCompilerMessages .getMessage("schema.typeMissing", qName.toString())); } if (isArray) { //append the square braces that say this is an array //hope this works for all cases!!!!!!! //todo this however is a thing that needs to be //todo fixed to get complete language support className = className + "[]"; } return className; } /** * Returns true if SOAP_ENC Namespace. * * @param s a string representing the URI to check * @return true if <code>s</code> matches a SOAP ENCODING namespace URI, * false otherwise */ public static boolean isSOAP_ENC(String s) { if (s.equals(Constants.URI_SOAP11_ENC)) { return true; } return s.equals(Constants.URI_SOAP12_ENC); } /** * Process a schema element which has been refered to by an element * * @param schemaType * @throws SchemaCompilationException */ private void processSchema(XmlSchemaElement xsElt, XmlSchemaType schemaType, XmlSchema parentSchema, boolean isWriteAnonComplexType) throws SchemaCompilationException { if (schemaType instanceof XmlSchemaComplexType) { //write classes for complex types XmlSchemaComplexType complexType = (XmlSchemaComplexType) schemaType; // complex type name may not be null if we have set it if (complexType.getName() != null && !this.changedComplexTypeSet.contains(schemaType)) { // here complex type may be in another shcema so we have to find the // correct parent schema. XmlSchema resolvedSchema = getParentSchema(parentSchema, complexType.getQName(), COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the parent schema for the " + "complex type " + complexType.getQName() + " from the parent schema " + parentSchema.getTargetNamespace()); } else { processNamedComplexSchemaType(complexType, resolvedSchema); } } else { processAnonymousComplexSchemaType(xsElt, complexType, parentSchema, isWriteAnonComplexType); } } else if (schemaType instanceof XmlSchemaSimpleType) { //process simple type processSimpleSchemaType((XmlSchemaSimpleType) schemaType, xsElt, parentSchema, null); } } /** * @param complexType * @throws SchemaCompilationException */ private void processAnonymousComplexSchemaType(XmlSchemaElement elt, XmlSchemaComplexType complexType, XmlSchema parentSchema, boolean isWriteAnonComplexType) throws SchemaCompilationException { //here we have a problem when processing the circulare element // references if we differ this processing // generate a name to the complex type and register it here QName generatedTypeName = null; String javaClassName = null; if (isWriteAnonComplexType) { generatedTypeName = generateTypeQName(elt.getQName(), parentSchema); if (elt.getSchemaTypeName() == null) { elt.setSchemaTypeName(generatedTypeName); this.changedElementSet.add(elt); } //set a name complexType.setName(generatedTypeName.getLocalPart()); this.changedComplexTypeSet.add(complexType); javaClassName = writer.makeFullyQualifiedClassName(generatedTypeName); processedTypemap.put(generatedTypeName, javaClassName); this.processedElementRefMap.put(elt.getQName(), javaClassName); complexType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, javaClassName); } BeanWriterMetaInfoHolder metaInfHolder = processComplexType(elt.getQName(), complexType, parentSchema); // here the only difference is that we generate the class // irrespective of where we need it or not if (isWriteAnonComplexType) { metaInfHolder.setOwnClassName(javaClassName); metaInfHolder.setOwnQname(generatedTypeName); writeComplexType(complexType, metaInfHolder); } //since this is a special case (an unnamed complex type) we'll put the already processed //metainf holder in a special map to be used later this.processedAnonymousComplexTypesMap.put(elt, metaInfHolder); } /** * handle the complex types which are named * * @param complexType */ private void processNamedComplexSchemaType(XmlSchemaComplexType complexType, XmlSchema parentSchema) throws SchemaCompilationException { if (processedTypemap.containsKey(complexType.getQName()) || baseSchemaTypeMap.containsKey(complexType.getQName())) { return; } // Must do this up front to support recursive types String fullyQualifiedClassName = writer.makeFullyQualifiedClassName(complexType.getQName()); processedTypemap.put(complexType.getQName(), fullyQualifiedClassName); //register that in the schema metainfo bag complexType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, fullyQualifiedClassName); BeanWriterMetaInfoHolder metaInfHolder = processComplexType(complexType.getQName(), complexType, parentSchema); //add this information to the metainfo holder metaInfHolder.setOwnQname(complexType.getQName()); metaInfHolder.setOwnClassName(fullyQualifiedClassName); //write the class. This type mapping would have been populated right now //Note - We always write classes for named complex types writeComplexType(complexType, metaInfHolder); } /** * Writes a complex type * * @param complexType * @param metaInfHolder * @throws SchemaCompilationException */ private String writeComplexType(XmlSchemaComplexType complexType, BeanWriterMetaInfoHolder metaInfHolder) throws SchemaCompilationException { String javaClassName = writer.write(complexType.getQName(), processedTypemap, processedGroupTypeMap, metaInfHolder, complexType.isAbstract()); processedTypeMetaInfoMap.put(complexType.getQName(), metaInfHolder); return javaClassName; } /** * Writes complex Sequence,Choice, all elements * * @param qname complex type qname * @param metaInfHolder * @return written java class name * @throws SchemaCompilationException */ private String writeComplexParticle(QName qname, BeanWriterMetaInfoHolder metaInfHolder) throws SchemaCompilationException { String javaClassName = writer.write(qname, processedTypemap, processedGroupTypeMap, metaInfHolder, false); processedTypeMetaInfoMap.put(qname, metaInfHolder); return javaClassName; } /** * Writes a complex type * * @param simpleType * @param metaInfHolder * @throws SchemaCompilationException */ private void writeSimpleType(XmlSchemaSimpleType simpleType, BeanWriterMetaInfoHolder metaInfHolder) throws SchemaCompilationException { writer.write(simpleType, processedTypemap, processedGroupTypeMap, metaInfHolder); processedTypeMetaInfoMap.put(simpleType.getQName(), metaInfHolder); } private BeanWriterMetaInfoHolder processComplexType( QName parentElementQName, XmlSchemaComplexType complexType, XmlSchema parentSchema) throws SchemaCompilationException { XmlSchemaParticle particle = complexType.getParticle(); BeanWriterMetaInfoHolder metaInfHolder = new BeanWriterMetaInfoHolder(); if (particle != null) { //Process the particle processParticle(parentElementQName, particle, metaInfHolder, parentSchema); } if (complexType.isMixed()) { throw new SchemaCompilationException("XSD complexType with mix content not " + "supported in ADB"); } //process attributes - first look for the explicit attributes processAttributes(complexType.getAttributes(), metaInfHolder, parentSchema); //process any attribute //somehow the xml schema parser does not seem to pickup the any attribute!! XmlSchemaAnyAttribute anyAtt = complexType.getAnyAttribute(); if (anyAtt != null) { processAnyAttribute(metaInfHolder, anyAtt); } //process content ,either complex or simple if (complexType.getContentModel() != null) { processContentModel(complexType.getContentModel(), metaInfHolder, parentSchema); } return metaInfHolder; } private void processAttributes(List<XmlSchemaAttributeOrGroupRef> attributes, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema parentSchema) throws SchemaCompilationException { for (XmlSchemaObject object : attributes) { if (object instanceof XmlSchemaAttribute) { processAttribute((XmlSchemaAttribute) object, metaInfHolder, parentSchema); } else if (object instanceof XmlSchemaAttributeGroupRef) { processAttributeGroupReference((XmlSchemaAttributeGroupRef) object, metaInfHolder, parentSchema); } } } private void processGroupAttributes(List<XmlSchemaAttributeGroupMember> attributes, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema resolvedSchema) throws SchemaCompilationException { for (XmlSchemaAttributeGroupMember member : attributes) { if (member instanceof XmlSchemaAttribute) { processAttribute((XmlSchemaAttribute) member, metaInfHolder, resolvedSchema); } else if (member instanceof XmlSchemaAttributeGroupRef) { processAttributeGroupReference((XmlSchemaAttributeGroupRef) member, metaInfHolder, resolvedSchema); } } } private void processAttributeGroupReference(XmlSchemaAttributeGroupRef attributeGroupRef, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema parentSchema) throws SchemaCompilationException { QName attributeGroupRefName = attributeGroupRef.getRef().getTargetQName(); if (attributeGroupRefName != null) { XmlSchema resolvedSchema = getParentSchema(parentSchema, attributeGroupRefName, COMPONENT_ATTRIBUTE_GROUP); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the attribute group reference name " + attributeGroupRefName + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaAttributeGroup xmlSchemaAttributeGroup = resolvedSchema.getAttributeGroups().get(attributeGroupRefName); if (xmlSchemaAttributeGroup != null) { processGroupAttributes(xmlSchemaAttributeGroup.getAttributes(), metaInfHolder, resolvedSchema); } else { throw new SchemaCompilationException("Can not find an attribute group for group reference " + attributeGroupRefName.getLocalPart()); } } } else { throw new SchemaCompilationException("No group refernce has given"); } } /** * Process the content models. A content model is either simple type or a complex type * and included inside a complex content */ private void processContentModel(XmlSchemaContentModel content, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema parentSchema) throws SchemaCompilationException { if (content instanceof XmlSchemaComplexContent) { processComplexContent((XmlSchemaComplexContent) content, metaInfHolder, parentSchema); } else if (content instanceof XmlSchemaSimpleContent) { processSimpleContent((XmlSchemaSimpleContent) content, metaInfHolder, parentSchema); } } /** * Prcess the complex content */ private void processComplexContent(XmlSchemaComplexContent complexContent, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema parentSchema) throws SchemaCompilationException { XmlSchemaContent content = complexContent.getContent(); if (content instanceof XmlSchemaComplexContentExtension) { // to handle extension we need to attach the extended items to the base type // and create a new type XmlSchemaComplexContentExtension extension = (XmlSchemaComplexContentExtension) content; //process the base type if it has not been processed yet if (!isAlreadyProcessed(extension.getBaseTypeName())) { //pick the relevant basetype from the schema and process it XmlSchema resolvedSchema = getParentSchema(parentSchema, extension.getBaseTypeName(), COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the compley type " + extension.getBaseTypeName() + " from the parent type " + parentSchema.getTargetNamespace()); } else { XmlSchemaType type = resolvedSchema.getTypeByName(extension.getBaseTypeName()); if (type instanceof XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType) type; if (complexType.getName() != null) { processNamedComplexSchemaType(complexType, resolvedSchema); } else { //this is not possible. The extension should always //have a name throw new SchemaCompilationException("Unnamed complex type used in extension");//Internationlize this } } else if (type instanceof XmlSchemaSimpleType) { //process simple type processSimpleSchemaType((XmlSchemaSimpleType) type, null, resolvedSchema, null); } } } // before actually processing this node, we need to recurse through the base types and add their // children (sometimes even preserving the order) to the metainfo holder of this type // the reason is that for extensions, the prefered way is to have the sequences of the base class //* before * the sequence of the child element. copyMetaInfoHierarchy(metaInfHolder, extension.getBaseTypeName(), parentSchema); //process the particle of this node if (extension.getParticle() != null) { processParticle(extension.getBaseTypeName(), extension.getParticle(), metaInfHolder, parentSchema); } // process attributes //process attributes - first look for the explicit attributes processAttributes(extension.getAttributes(), metaInfHolder, parentSchema); //process any attribute //somehow the xml schema parser does not seem to pickup the any attribute!! XmlSchemaAnyAttribute anyAtt = extension.getAnyAttribute(); if (anyAtt != null) { processAnyAttribute(metaInfHolder, anyAtt); } String className = findClassName(extension.getBaseTypeName(), false); if (!writer.getDefaultClassName().equals(className)) { //the particle has been processed, However since this is an extension we need to //add the basetype as an extension to the complex type class. // The basetype has been processed already metaInfHolder.setExtension(true); metaInfHolder.setExtensionClassName(className); //Note - this is no array! so the array boolean is false } } else if (content instanceof XmlSchemaComplexContentRestriction) { XmlSchemaComplexContentRestriction restriction = (XmlSchemaComplexContentRestriction) content; //process the base type if it has not been processed yet if (!isAlreadyProcessed(restriction.getBaseTypeName())) { //pick the relevant basetype from the schema and process it XmlSchema resolvedSchema = getParentSchema(parentSchema, restriction.getBaseTypeName(), COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the complex type " + restriction.getBaseTypeName() + " from the parent type " + parentSchema.getTargetNamespace()); } else { XmlSchemaType type = resolvedSchema.getTypeByName(restriction.getBaseTypeName()); if (type instanceof XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType) type; if (complexType.getName() != null) { processNamedComplexSchemaType(complexType, resolvedSchema); } else { //this is not possible. The restriction should always //have a name throw new SchemaCompilationException("Unnamed complex type used in restriction");//Internationlize this } } else if (type instanceof XmlSchemaSimpleType) { throw new SchemaCompilationException("Not a valid restriction, " + "complex content restriction base type cannot be a simple type."); } } } copyMetaInfoHierarchy(metaInfHolder, restriction.getBaseTypeName(), parentSchema); //process the particle of this node processParticle(restriction.getBaseTypeName(), restriction.getParticle(), metaInfHolder, parentSchema); //process attributes - first look for the explicit attributes processAttributes(restriction.getAttributes(), metaInfHolder, parentSchema); //process any attribute //somehow the xml schema parser does not seem to pickup the any attribute!! XmlSchemaAnyAttribute anyAtt = restriction.getAnyAttribute(); if (anyAtt != null) { processAnyAttribute(metaInfHolder, anyAtt); } String className = findClassName(restriction.getBaseTypeName(), false); if (!writer.getDefaultClassName().equals(className)) { metaInfHolder.setRestriction(true); metaInfHolder.setRestrictionClassName(findClassName(restriction.getBaseTypeName(), false)); //Note - this is no array! so the array boolean is false } } } /** * Recursive method to populate the metainfo holders with info from the base types * * @param metaInfHolder * @param baseTypeName * @param parentSchema */ private void copyMetaInfoHierarchy(BeanWriterMetaInfoHolder metaInfHolder, QName baseTypeName, XmlSchema parentSchema) throws SchemaCompilationException { XmlSchema resolvedSchema = getParentSchema(parentSchema, baseTypeName, COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find type " + baseTypeName + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaType type = resolvedSchema.getTypeByName(baseTypeName); BeanWriterMetaInfoHolder baseMetaInfoHolder = processedTypeMetaInfoMap.get(baseTypeName); if (baseMetaInfoHolder != null) { // see whether this type is also extended from some other type first // if so proceed to set their parents as well. if (type instanceof XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType) type; if (complexType.getContentModel() != null) { XmlSchemaContentModel content = complexType.getContentModel(); if (content instanceof XmlSchemaComplexContent) { XmlSchemaComplexContent complexContent = (XmlSchemaComplexContent) content; if (complexContent.getContent() instanceof XmlSchemaComplexContentExtension) { XmlSchemaComplexContentExtension extension = (XmlSchemaComplexContentExtension) complexContent.getContent(); //recursively call the copyMetaInfoHierarchy method copyMetaInfoHierarchy(baseMetaInfoHolder, extension.getBaseTypeName(), resolvedSchema); } else if (complexContent.getContent() instanceof XmlSchemaComplexContentRestriction) { XmlSchemaComplexContentRestriction restriction = (XmlSchemaComplexContentRestriction) complexContent.getContent(); //recursively call the copyMetaInfoHierarchy method copyMetaInfoHierarchy(baseMetaInfoHolder, restriction.getBaseTypeName(), resolvedSchema); } else { throw new SchemaCompilationException( SchemaCompilerMessages. getMessage("schema.unknowncontenterror")); } } else if (content instanceof XmlSchemaSimpleContent) { XmlSchemaSimpleContent simpleContent = (XmlSchemaSimpleContent) content; if (simpleContent.getContent() instanceof XmlSchemaSimpleContentExtension) { XmlSchemaSimpleContentExtension extension = (XmlSchemaSimpleContentExtension) simpleContent .getContent(); // recursively call the copyMetaInfoHierarchy // method copyMetaInfoHierarchy(baseMetaInfoHolder, extension.getBaseTypeName(), resolvedSchema); } else if (simpleContent.getContent() instanceof XmlSchemaSimpleContentRestriction) { XmlSchemaSimpleContentRestriction restriction = (XmlSchemaSimpleContentRestriction) simpleContent .getContent(); // recursively call the copyMetaInfoHierarchy // method copyMetaInfoHierarchy(baseMetaInfoHolder, restriction.getBaseTypeName(), resolvedSchema); } } else { throw new SchemaCompilationException( SchemaCompilerMessages.getMessage("schema.unknowncontenterror")); } } //Do the actual parent setting metaInfHolder.setAsParent(baseMetaInfoHolder); } else if (type instanceof XmlSchemaSimpleType) { // we have to copy the uion data if the parent simple type restriction // is an union // this union attribute is copied from the child to parent to genrate the parent // code as union if (baseMetaInfoHolder.isUnion()) { metaInfHolder.setUnion(true); for (Map.Entry<QName, String> entry : baseMetaInfoHolder.getMemberTypes().entrySet()) { metaInfHolder.addMemberType(entry.getKey(), entry.getValue()); } } // we have to copy the list type data to parent if it is a list if (baseMetaInfoHolder.isList()) { metaInfHolder.setList(true); metaInfHolder.setItemTypeQName(baseMetaInfoHolder.getItemTypeQName()); metaInfHolder.setItemTypeClassName(baseMetaInfoHolder.getItemTypeClassName()); } metaInfHolder.setAsParent(baseMetaInfoHolder); } } } } /** * @param simpleContent * @param metaInfHolder * @throws SchemaCompilationException */ private void processSimpleContent(XmlSchemaSimpleContent simpleContent, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema parentSchema) throws SchemaCompilationException { XmlSchemaContent content; content = simpleContent.getContent(); if (content instanceof XmlSchemaSimpleContentExtension) { XmlSchemaSimpleContentExtension extension = (XmlSchemaSimpleContentExtension) content; //process the base type if it has not been processed yet if (!isAlreadyProcessed(extension.getBaseTypeName())) { //pick the relevant basetype from the schema and process it XmlSchema resolvedSchema = getParentSchema(parentSchema, extension.getBaseTypeName(), COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find type " + extension.getBaseTypeName() + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaType type = resolvedSchema.getTypeByName(extension.getBaseTypeName()); if (type instanceof XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType) type; if (complexType.getName() != null) { processNamedComplexSchemaType(complexType, resolvedSchema); } else { //this is not possible. The extension should always //have a name throw new SchemaCompilationException("Unnamed complex type used in extension");//Internationlize this } } else if (type instanceof XmlSchemaSimpleType) { //process simple type processSimpleSchemaType((XmlSchemaSimpleType) type, null, resolvedSchema, null); } } } //process extension base type processSimpleExtensionBaseType(extension.getBaseTypeName(), metaInfHolder, parentSchema); //process attributes for (XmlSchemaAttributeOrGroupRef attr : extension.getAttributes()) { if (attr instanceof XmlSchemaAttribute) { processAttribute((XmlSchemaAttribute) attr, metaInfHolder, parentSchema); } } //process any attribute XmlSchemaAnyAttribute anyAtt = extension.getAnyAttribute(); if (anyAtt != null) { processAnyAttribute(metaInfHolder, anyAtt); } } else if (content instanceof XmlSchemaSimpleContentRestriction) { XmlSchemaSimpleContentRestriction restriction = (XmlSchemaSimpleContentRestriction) content; //process the base type if it has not been processed yet if (!isAlreadyProcessed(restriction.getBaseTypeName())) { //pick the relevant basetype from the schema and process it XmlSchema resolvedSchema = getParentSchema(parentSchema, restriction.getBaseTypeName(), COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find type " + restriction.getBaseTypeName() + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaType type = resolvedSchema.getTypeByName(restriction.getBaseTypeName()); if (type instanceof XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType) type; if (complexType.getName() != null) { processNamedComplexSchemaType(complexType, resolvedSchema); } else { //this is not possible. The extension should always //have a name throw new SchemaCompilationException("Unnamed complex type used in restriction");//Internationlize this } } else if (type instanceof XmlSchemaSimpleType) { //process simple type processSimpleSchemaType((XmlSchemaSimpleType) type, null, resolvedSchema, null); } } } //process restriction base type processSimpleRestrictionBaseType(restriction.getBaseTypeName(), restriction.getBaseTypeName(), metaInfHolder, parentSchema); metaInfHolder.setSimple(true); if (!SchemaConstants.XSD_BOOLEAN.equals(restriction.getBaseTypeName())) { processFacets(restriction.getFacets(), restriction.getBaseTypeName(), metaInfHolder, parentSchema); } } } /** * Process Simple Extension Base Type. * * @param extBaseType * @param metaInfHolder */ public void processSimpleExtensionBaseType(QName extBaseType, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema parentSchema) throws SchemaCompilationException { //find the class name String className = findClassName(extBaseType, false); // if the base type is an primitive then we do not have to extend them // and it is considered as a property // on the otherhand if the base type is an generated class then we have to // extend from it if (baseSchemaTypeMap.containsKey(extBaseType)) { //this means the schema type actually returns a different QName if (changedTypeMap.containsKey(extBaseType)) { metaInfHolder.registerMapping(extBaseType, changedTypeMap.get(extBaseType), className, SchemaConstants.ELEMENT_TYPE); } else { metaInfHolder.registerMapping(extBaseType, extBaseType, className, SchemaConstants.ELEMENT_TYPE); } metaInfHolder.setSimple(true); // we have already process when it comes to this place } else if (processedTypemap.containsKey(extBaseType)) { //set the extension base class name XmlSchema resolvedSchema = getParentSchema(parentSchema, extBaseType, COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the type " + extBaseType + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaType type = resolvedSchema.getTypeByName(extBaseType); if (type instanceof XmlSchemaSimpleType) { metaInfHolder.setSimple(true); metaInfHolder.setExtension(true); metaInfHolder.setExtensionClassName(className); copyMetaInfoHierarchy(metaInfHolder, extBaseType, resolvedSchema); } else if (type instanceof XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType) type; // do not set as a simple type since we want to // print the element names metaInfHolder.setExtension(true); metaInfHolder.setExtensionClassName(className); copyMetaInfoHierarchy(metaInfHolder, extBaseType, resolvedSchema); XmlSchemaContentModel typeContent = complexType.getContentModel(); if (typeContent != null && typeContent instanceof XmlSchemaSimpleContent) { metaInfHolder.setSimple(true); } } } } else { metaInfHolder.setSimple(true); } //get the binary state and add that to the status map if (isBinary(extBaseType)) { metaInfHolder.addtStatus(extBaseType, SchemaConstants.BINARY_TYPE); } } /** * Process Simple Restriction Base Type. * * @param resBaseType * @param metaInfHolder */ public void processSimpleRestrictionBaseType(QName qName, QName resBaseType, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema parentSchema) throws SchemaCompilationException { //find the class name String className = findClassName(resBaseType, false); //this means the schema type actually returns a different QName if (baseSchemaTypeMap.containsKey(resBaseType)) { if (changedTypeMap.containsKey(resBaseType)) { metaInfHolder.registerMapping(qName, changedTypeMap.get(resBaseType), className, SchemaConstants.ELEMENT_TYPE); } else { metaInfHolder.registerMapping(qName, resBaseType, className, SchemaConstants.ELEMENT_TYPE); } } else if (processedTypemap.containsKey(resBaseType)) { //this is not a standared type // so the parent class must extend it metaInfHolder.setSimple(true); metaInfHolder.setRestriction(true); metaInfHolder.setRestrictionClassName(className); copyMetaInfoHierarchy(metaInfHolder, resBaseType, parentSchema); } metaInfHolder.setRestrictionBaseType(resBaseType); } /** * Process Facets. * * @param metaInfHolder * @param facets */ private void processFacets(List<XmlSchemaFacet> facets, QName restrictionName, BeanWriterMetaInfoHolder metaInfHolder, XmlSchema parentSchema) { for (XmlSchemaFacet facet : facets) { if (facet instanceof XmlSchemaPatternFacet) { XmlSchemaPatternFacet pattern = (XmlSchemaPatternFacet) facet; // some patterns contain \ so we have to replace them String patternString = pattern.getValue().toString(); // replace backword slashes patternString = patternString.replaceAll("\\\\", "\\\\\\\\"); patternString = patternString.replaceAll("\"", "\\\\\""); if ((metaInfHolder.getPatternFacet() != null) && (metaInfHolder.getPatternFacet().trim().length() > 0)) { // i.e there is a pattern faceset patternString = metaInfHolder.getPatternFacet().trim() + "|" + patternString; } metaInfHolder.setPatternFacet(patternString); } else if (facet instanceof XmlSchemaEnumerationFacet) { XmlSchemaEnumerationFacet enumeration = (XmlSchemaEnumerationFacet) facet; if (restrictionName.equals(SchemaConstants.XSD_QNAME)) { // we have to process the qname here and shoud find the local part and namespace uri String value = enumeration.getValue().toString(); String prefix = value.substring(0, value.indexOf(":")); String localPart = value.substring(value.indexOf(":") + 1); String namespaceUri = parentSchema.getNamespaceContext().getNamespaceURI(prefix); // set the string to suite for the convertQname method String qNameString = value + "\", \"" + namespaceUri; metaInfHolder.addEnumFacet(qNameString); } else { metaInfHolder.addEnumFacet(enumeration.getValue().toString()); } } else if (facet instanceof XmlSchemaLengthFacet) { XmlSchemaLengthFacet length = (XmlSchemaLengthFacet) facet; metaInfHolder.setLengthFacet(Integer.parseInt(length.getValue().toString())); } else if (facet instanceof XmlSchemaTotalDigitsFacet) { XmlSchemaTotalDigitsFacet totalDigits = (XmlSchemaTotalDigitsFacet) facet; metaInfHolder.setTotalDigitsFacet(totalDigits.getValue().toString()); } else if (facet instanceof XmlSchemaMaxExclusiveFacet) { XmlSchemaMaxExclusiveFacet maxEx = (XmlSchemaMaxExclusiveFacet) facet; metaInfHolder.setMaxExclusiveFacet(maxEx.getValue().toString()); } else if (facet instanceof XmlSchemaMinExclusiveFacet) { XmlSchemaMinExclusiveFacet minEx = (XmlSchemaMinExclusiveFacet) facet; metaInfHolder.setMinExclusiveFacet(minEx.getValue().toString()); } else if (facet instanceof XmlSchemaMaxInclusiveFacet) { XmlSchemaMaxInclusiveFacet maxIn = (XmlSchemaMaxInclusiveFacet) facet; metaInfHolder.setMaxInclusiveFacet(maxIn.getValue().toString()); } else if (facet instanceof XmlSchemaMinInclusiveFacet) { XmlSchemaMinInclusiveFacet minIn = (XmlSchemaMinInclusiveFacet) facet; metaInfHolder.setMinInclusiveFacet(minIn.getValue().toString()); } else if (facet instanceof XmlSchemaMaxLengthFacet) { XmlSchemaMaxLengthFacet maxLen = (XmlSchemaMaxLengthFacet) facet; metaInfHolder.setMaxLengthFacet(Integer.parseInt(maxLen.getValue().toString())); } else if (facet instanceof XmlSchemaMinLengthFacet) { XmlSchemaMinLengthFacet minLen = (XmlSchemaMinLengthFacet) facet; metaInfHolder.setMinLengthFacet(Integer.parseInt(minLen.getValue().toString())); } } } /** * Handle any attribute * * @param metainf */ private void processAnyAttribute(BeanWriterMetaInfoHolder metainf, XmlSchemaAnyAttribute anyAtt) { //The best thing we can do here is to add a set of OMAttributes //since attributes do not have the notion of minoccurs/maxoccurs the //safest option here is to have an OMAttribute array QName qName = new QName(EXTRA_ATTRIBUTE_FIELD_NAME); metainf.registerMapping(qName, null, writer.getDefaultAttribArrayClassName(),//always generate an array of //OMAttributes SchemaConstants.ANY_TYPE); metainf.addtStatus(qName, SchemaConstants.ATTRIBUTE_TYPE); metainf.addtStatus(qName, SchemaConstants.ARRAY_TYPE); } /** * Process the attribute * * @param att * @param metainf */ public void processAttribute(XmlSchemaAttribute att, BeanWriterMetaInfoHolder metainf, XmlSchema parentSchema) throws SchemaCompilationException { QName schemaTypeName = att.getSchemaTypeName(); if (schemaTypeName != null) { if (att.getWireName() != null) { if (baseSchemaTypeMap.containsKey(schemaTypeName)) { metainf.registerMapping(att.getWireName(), schemaTypeName, baseSchemaTypeMap.get(schemaTypeName).toString(), SchemaConstants.ATTRIBUTE_TYPE); // add optional attribute status if set String use = att.getUse().toString(); if (USE_NONE.equals(use) || USE_OPTIONAL.equals(use)) { metainf.addtStatus(att.getWireName(), SchemaConstants.OPTIONAL_TYPE); } String className = findClassName(schemaTypeName, false); att.addMetaInfo( SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, className); // set the default value if (att.getDefaultValue() != null) { metainf.registerDefaultValue(att.getWireName(), att.getDefaultValue()); } if (att.getFixedValue() != null) { metainf.registerDefaultValue(att.getWireName(), att.getFixedValue()); metainf.registerFixedQName(att.getWireName()); } // after } else { XmlSchema resolvedSchema = getParentSchema(parentSchema, schemaTypeName, COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the type " + schemaTypeName + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaType type = resolvedSchema.getTypeByName(schemaTypeName); if (type instanceof XmlSchemaSimpleType) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType) type; if (simpleType != null) { if (!isAlreadyProcessed(schemaTypeName)) { //process simple type processSimpleSchemaType(simpleType, null, resolvedSchema, null); } metainf.registerMapping(att.getWireName(), schemaTypeName, processedTypemap.get(schemaTypeName).toString(), SchemaConstants.ATTRIBUTE_TYPE); // add optional attribute status if set String use = att.getUse().toString(); if (USE_NONE.equals(use) || USE_OPTIONAL.equals(use)) { metainf.addtStatus(att.getWireName(), SchemaConstants.OPTIONAL_TYPE); } } } } } } else { // this attribute has a type but does not have a name, seems to be invalid } } else if (att.getRef().getTargetQName() != null) { XmlSchema resolvedSchema = getParentSchema(parentSchema, att.getRef().getTargetQName(), COMPONENT_ATTRIBUTE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the attribute " + att.getRef().getTargetQName() + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaAttribute xmlSchemaAttribute = resolvedSchema.getAttributes().get(att.getRef().getTargetQName()); if (xmlSchemaAttribute != null) { // call recursively to process the schema processAttribute(xmlSchemaAttribute, metainf, resolvedSchema); } else { throw new SchemaCompilationException("Attribute QName reference refer to an invalid attribute " + att.getRef().getTargetQName()); } } } else { // this attribute refers to a custom type, probably one of the extended simple types. // with the inline schema definition QName attributeQName = att.getWireName(); if (attributeQName != null) { XmlSchemaSimpleType attributeSimpleType = att.getSchemaType(); XmlSchema resolvedSchema = parentSchema; if (attributeSimpleType == null) { // try to get the schema for using qname QName attributeSchemaQname = att.getSchemaTypeName(); if (attributeSchemaQname != null) { resolvedSchema = getParentSchema(parentSchema, attributeSchemaQname, COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the type " + attributeSchemaQname + " from the parent schema " + parentSchema.getTargetNamespace()); } else { attributeSimpleType = (XmlSchemaSimpleType) resolvedSchema.getTypeByName(attributeSchemaQname); } } } if (attributeSimpleType != null) { QName schemaTypeQName = att.getSchemaTypeName(); if (schemaTypeQName == null) { // set the parent schema target name space since attribute Qname uri is "" if (attributeSimpleType.getQName() != null) { schemaTypeQName = attributeSimpleType.getQName(); } else { schemaTypeQName = new QName(parentSchema.getTargetNamespace(), attributeQName.getLocalPart() + getNextTypeSuffix(attributeQName.getLocalPart())); } } if (!isAlreadyProcessed(schemaTypeQName)) { // we have to process only if it has not processed processSimpleSchemaType(attributeSimpleType, null, resolvedSchema, schemaTypeQName); } metainf.registerMapping(att.getWireName(), schemaTypeQName, processedTypemap.get(schemaTypeQName).toString(), SchemaConstants.ATTRIBUTE_TYPE); // add optional attribute status if set String use = att.getUse().toString(); if (USE_NONE.equals(use) || USE_OPTIONAL.equals(use)) { metainf.addtStatus(att.getWireName(), SchemaConstants.OPTIONAL_TYPE); } } else { // TODO: handle the case when no attribute type specifed log.warn("No attribute type has defined to the Attribute " + attributeQName); } } else { throw new SchemaCompilationException("Attribute QName reference refer to an invalid attribute " + attributeQName); } } } /** * Process a particle- A particle may be a sequence,all or a choice * * @param parentElementQName - this can either be parent element QName or parent Complex type qname * @param particle - particle being processed * @param metainfHolder - * @param parentSchema * @throws SchemaCompilationException */ private void processParticle(QName parentElementQName, XmlSchemaParticle particle, BeanWriterMetaInfoHolder metainfHolder , XmlSchema parentSchema) throws SchemaCompilationException { if (particle instanceof XmlSchemaSequence) { XmlSchemaSequence xmlSchemaSequence = (XmlSchemaSequence) particle; List<XmlSchemaSequenceMember> items = xmlSchemaSequence.getItems(); if ((xmlSchemaSequence.getMaxOccurs() > 1) && (parentElementQName != null)) { // we have to process many sequence types BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder(); process(parentElementQName, items, beanWriterMetaInfoHolder, true, parentSchema); beanWriterMetaInfoHolder.setParticleClass(true); QName sequenceQName = new QName(parentElementQName.getNamespaceURI(), parentElementQName.getLocalPart() + "Sequence"); String javaClassName = writeComplexParticle(sequenceQName, beanWriterMetaInfoHolder); processedTypemap.put(sequenceQName, javaClassName); // add this as an array to the original class metainfHolder.registerMapping(sequenceQName, sequenceQName, findClassName(sequenceQName, true), SchemaConstants.ARRAY_TYPE); metainfHolder.setOrdered(true); metainfHolder.registerQNameIndex(sequenceQName, metainfHolder.getOrderStartPoint() + 1); metainfHolder.setHasParticleType(true); metainfHolder.addtStatus(sequenceQName, SchemaConstants.PARTICLE_TYPE_ELEMENT); metainfHolder.addMaxOccurs(sequenceQName, xmlSchemaSequence.getMaxOccurs()); metainfHolder.addMinOccurs(sequenceQName, xmlSchemaSequence.getMinOccurs()); } else { if (options.isBackwordCompatibilityMode()) { process(parentElementQName, items, metainfHolder, false, parentSchema); } else { process(parentElementQName, items, metainfHolder, true, parentSchema); } } } else if (particle instanceof XmlSchemaAll) { List<XmlSchemaAllMember> items = ((XmlSchemaAll) particle).getItems(); processSchemaAllItems(parentElementQName, items, metainfHolder, false, parentSchema); } else if (particle instanceof XmlSchemaChoice) { XmlSchemaChoice xmlSchemaChoice = (XmlSchemaChoice) particle; List<XmlSchemaChoiceMember> items = ((XmlSchemaChoice) particle).getItems(); if ((xmlSchemaChoice.getMaxOccurs() > 1)) { // we have to process many sequence types BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder(); beanWriterMetaInfoHolder.setChoice(true); processChoiceItems(parentElementQName, items, beanWriterMetaInfoHolder, false, parentSchema); beanWriterMetaInfoHolder.setParticleClass(true); QName choiceQName = new QName(parentElementQName.getNamespaceURI(), parentElementQName.getLocalPart() + "Choice"); String javaClassName = writeComplexParticle(choiceQName, beanWriterMetaInfoHolder); processedTypemap.put(choiceQName, javaClassName); // add this as an array to the original class metainfHolder.registerMapping(choiceQName, choiceQName, findClassName(choiceQName, true), SchemaConstants.ARRAY_TYPE); metainfHolder.setOrdered(true); metainfHolder.setHasParticleType(true); metainfHolder.registerQNameIndex(choiceQName, metainfHolder.getOrderStartPoint() + 1); metainfHolder.addtStatus(choiceQName, SchemaConstants.PARTICLE_TYPE_ELEMENT); metainfHolder.addMaxOccurs(choiceQName, xmlSchemaChoice.getMaxOccurs()); metainfHolder.addMinOccurs(choiceQName, xmlSchemaChoice.getMinOccurs()); } else { metainfHolder.setChoice(true); processChoiceItems(parentElementQName, items, metainfHolder, false, parentSchema); } } else if (particle instanceof XmlSchemaGroupRef) { XmlSchemaGroupRef xmlSchemaGroupRef = (XmlSchemaGroupRef) particle; QName groupQName = xmlSchemaGroupRef.getRefName(); if (groupQName != null) { if (!processedGroupTypeMap.containsKey(groupQName)) { // processe the schema here XmlSchema resolvedParentSchema = getParentSchema(parentSchema, groupQName, COMPONENT_GROUP); if (resolvedParentSchema == null) { throw new SchemaCompilationException("can not find the group " + groupQName + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaGroup xmlSchemaGroup = resolvedParentSchema.getGroups().get(groupQName); processGroup(xmlSchemaGroup, groupQName, resolvedParentSchema); } } } else { throw new SchemaCompilationException("Referenced name is null"); } boolean isArray = xmlSchemaGroupRef.getMaxOccurs() > 1; // add this as an array to the original class String groupClassName = processedGroupTypeMap.get(groupQName); if (isArray) { groupClassName = groupClassName + "[]"; } metainfHolder.registerMapping(groupQName, groupQName, groupClassName); if (isArray) { metainfHolder.addtStatus(groupQName, SchemaConstants.ARRAY_TYPE); } metainfHolder.addtStatus(groupQName, SchemaConstants.PARTICLE_TYPE_ELEMENT); metainfHolder.addMaxOccurs(groupQName, xmlSchemaGroupRef.getMaxOccurs()); metainfHolder.addMinOccurs(groupQName, xmlSchemaGroupRef.getMinOccurs()); metainfHolder.setHasParticleType(true); metainfHolder.setOrdered(true); metainfHolder.registerQNameIndex(groupQName, metainfHolder.getOrderStartPoint() + 1); } } /** * @param parentElementQName - this could either be the complex type parentElementQName or element parentElementQName * @param items * @param metainfHolder * @param order * @param parentSchema * @throws SchemaCompilationException */ private void process(QName parentElementQName, List<XmlSchemaSequenceMember> items, BeanWriterMetaInfoHolder metainfHolder, boolean order, XmlSchema parentSchema) throws SchemaCompilationException { Map<XmlSchemaObjectBase, Boolean> processedElementArrayStatusMap = new LinkedHashMap<XmlSchemaObjectBase, Boolean>(); Map processedElementTypeMap = new LinkedHashMap(); // TODO: not sure what is the correct generic type here List<QName> localNillableList = new ArrayList<QName>(); Map<XmlSchemaObjectBase, QName> particleQNameMap = new HashMap<XmlSchemaObjectBase, QName>(); // this list is used to keep the details of the // elements within a choice withing sequence List<QName> innerChoiceElementList = new ArrayList<QName>(); Map<XmlSchemaObjectBase, Integer> elementOrderMap = new HashMap<XmlSchemaObjectBase, Integer>(); int sequenceCounter = 0; for (XmlSchemaSequenceMember member : items) { XmlSchemaObject item = (XmlSchemaObject) member; //recursively process the element processElements(parentElementQName, item, processedElementArrayStatusMap, processedElementTypeMap, elementOrderMap, localNillableList, particleQNameMap, order, sequenceCounter, parentSchema); sequenceCounter++; } addProcessedItemsToMetaInfoHolder(processedElementArrayStatusMap, processedElementTypeMap, innerChoiceElementList, elementOrderMap, localNillableList, particleQNameMap, metainfHolder, order, parentSchema); } private void processChoiceItems(QName parentElementQName, List<XmlSchemaChoiceMember> items, BeanWriterMetaInfoHolder metainfHolder, boolean order, XmlSchema parentSchema) throws SchemaCompilationException { Map<XmlSchemaObjectBase, Boolean> processedElementArrayStatusMap = new LinkedHashMap<XmlSchemaObjectBase, Boolean>(); Map processedElementTypeMap = new LinkedHashMap(); // TODO: not sure what is the correct generic type here List<QName> localNillableList = new ArrayList<QName>(); Map<XmlSchemaObjectBase, QName> particleQNameMap = new HashMap<XmlSchemaObjectBase, QName>(); // this list is used to keep the details of the // elements within a choice withing sequence List<QName> innerChoiceElementList = new ArrayList<QName>(); Map<XmlSchemaObjectBase, Integer> elementOrderMap = new HashMap<XmlSchemaObjectBase, Integer>(); int sequenceCounter = 0; for (XmlSchemaChoiceMember item : items) { //recursively process the element processElements(parentElementQName, item, processedElementArrayStatusMap, processedElementTypeMap, elementOrderMap, localNillableList, particleQNameMap, order, sequenceCounter, parentSchema); sequenceCounter++; } addProcessedItemsToMetaInfoHolder(processedElementArrayStatusMap, processedElementTypeMap, innerChoiceElementList, elementOrderMap, localNillableList, particleQNameMap, metainfHolder, order, parentSchema); } private void processSchemaAllItems(QName parentElementQName, List<XmlSchemaAllMember> items, BeanWriterMetaInfoHolder metainfHolder, boolean order, XmlSchema parentSchema) throws SchemaCompilationException { Map<XmlSchemaObjectBase, Boolean> processedElementArrayStatusMap = new LinkedHashMap<XmlSchemaObjectBase, Boolean>(); Map processedElementTypeMap = new LinkedHashMap(); // TODO: not sure what is the correct generic type here List<QName> localNillableList = new ArrayList<QName>(); Map<XmlSchemaObjectBase, QName> particleQNameMap = new HashMap<XmlSchemaObjectBase, QName>(); // this list is used to keep the details of the // elements within a choice withing sequence List<QName> innerChoiceElementList = new ArrayList<QName>(); Map<XmlSchemaObjectBase, Integer> elementOrderMap = new HashMap<XmlSchemaObjectBase, Integer>(); int sequenceCounter = 0; for (XmlSchemaAllMember item : items) { //recursively process the element processElements(parentElementQName, item, processedElementArrayStatusMap, processedElementTypeMap, elementOrderMap, localNillableList, particleQNameMap, order, sequenceCounter, parentSchema); sequenceCounter++; } addProcessedItemsToMetaInfoHolder(processedElementArrayStatusMap, processedElementTypeMap, innerChoiceElementList, elementOrderMap, localNillableList, particleQNameMap, metainfHolder, order, parentSchema); } private void addProcessedItemsToMetaInfoHolder( Map<XmlSchemaObjectBase, Boolean> processedElementArrayStatusMap, Map processedElementTypeMap, List<QName> innerChoiceElementList, Map<XmlSchemaObjectBase, Integer> elementOrderMap, List<QName> localNillableList, Map<XmlSchemaObjectBase, QName> particleQNameMap, BeanWriterMetaInfoHolder metainfHolder, boolean order, XmlSchema parentSchema) throws SchemaCompilationException { // loop through the processed items and add them to the matainf object int startingItemNumberOrder = metainfHolder.getOrderStartPoint(); for (XmlSchemaObjectBase child : processedElementArrayStatusMap.keySet()) { // process the XmlSchemaElement if (child instanceof XmlSchemaElement) { XmlSchemaElement elt = (XmlSchemaElement) child; QName referencedQName = null; if (elt.getWireName() != null) { referencedQName = elt.getWireName(); QName schemaTypeQName = elt.getSchemaType() != null ? elt.getSchemaType().getQName() : elt.getSchemaTypeName(); if (schemaTypeQName != null) { String clazzName = (String) processedElementTypeMap.get(elt.getWireName()); metainfHolder.registerMapping(referencedQName, schemaTypeQName, clazzName, processedElementArrayStatusMap.get(elt) ? SchemaConstants.ARRAY_TYPE : SchemaConstants.ELEMENT_TYPE); if (innerChoiceElementList.contains(referencedQName)) { metainfHolder.addtStatus(referencedQName, SchemaConstants.INNER_CHOICE_ELEMENT); } // register the default value as well if (elt.getDefaultValue() != null) { metainfHolder.registerDefaultValue(referencedQName, elt.getDefaultValue()); } // register the default value as well if (elt.getFixedValue() != null) { metainfHolder.registerDefaultValue(referencedQName, elt.getFixedValue()); metainfHolder.registerFixedQName(referencedQName); } } } if (elt.getRef().getTargetQName() != null) { //probably this is referenced referencedQName = elt.getRef().getTargetQName(); boolean arrayStatus = processedElementArrayStatusMap.get(elt); String clazzName = findRefClassName(referencedQName, arrayStatus); if (clazzName == null) { clazzName = findClassName(referencedQName, arrayStatus); } XmlSchema resolvedParentSchema = getParentSchema(parentSchema, referencedQName, COMPONENT_ELEMENT); if (resolvedParentSchema == null) { throw new SchemaCompilationException("Can not find the element " + referencedQName + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaElement refElement = resolvedParentSchema.getElementByName(referencedQName); // register the mapping if we found the referenced element // else throw an exception if (refElement != null) { metainfHolder.registerMapping(referencedQName, refElement.getSchemaTypeName() , clazzName, arrayStatus ? SchemaConstants.ARRAY_TYPE : SchemaConstants.ELEMENT_TYPE); } else { if (referencedQName.equals(SchemaConstants.XSD_SCHEMA)) { metainfHolder.registerMapping(referencedQName, null, writer.getDefaultClassName(), SchemaConstants.ANY_TYPE); } else { throw new SchemaCompilationException(SchemaCompilerMessages. getMessage("schema.referencedElementNotFound", referencedQName.toString())); } } } } if (referencedQName == null) { throw new SchemaCompilationException(SchemaCompilerMessages. getMessage("schema.emptyName")); } //register the occurence counts metainfHolder.addMaxOccurs(referencedQName, elt.getMaxOccurs()); // if the strict validation off then we consider all elements have minOccurs zero on it if (this.options.isOffStrictValidation()) { metainfHolder.addMinOccurs(referencedQName, 0); } else { metainfHolder.addMinOccurs(referencedQName, elt.getMinOccurs()); } //we need the order to be preserved. So record the order also if (order) { //record the order in the metainf holder metainfHolder.registerQNameIndex(referencedQName, startingItemNumberOrder + elementOrderMap.get(elt)); } //get the nillable state and register that on the metainf holder if (localNillableList.contains(elt.getWireName())) { metainfHolder.registerNillableQName(elt.getWireName()); } //get the binary state and add that to the status map if (isBinary(elt)) { metainfHolder.addtStatus(elt.getWireName(), SchemaConstants.BINARY_TYPE); } // process the XMLSchemaAny } else if (child instanceof XmlSchemaAny) { XmlSchemaAny any = (XmlSchemaAny) child; //since there is only one element here it does not matter //for the constant. However the problem occurs if the users //uses the same name for an element decalration QName anyElementFieldName = new QName(ANY_ELEMENT_FIELD_NAME); //this can be an array or a single element boolean isArray = processedElementArrayStatusMap.get(any); metainfHolder.registerMapping(anyElementFieldName, null, isArray ? writer.getDefaultClassArrayName() : writer. getDefaultClassName(), SchemaConstants.ANY_TYPE); //if it's an array register an extra status flag with the system if (isArray) { metainfHolder.addtStatus(anyElementFieldName, SchemaConstants.ARRAY_TYPE); } metainfHolder.addMaxOccurs(anyElementFieldName, any.getMaxOccurs()); metainfHolder.addMinOccurs(anyElementFieldName, any.getMinOccurs()); if (order) { //record the order in the metainf holder for the any metainfHolder.registerQNameIndex(anyElementFieldName, startingItemNumberOrder + elementOrderMap.get(any)); } } else if (child instanceof XmlSchemaSequence) { XmlSchemaSequence xmlSchemaSequence = (XmlSchemaSequence) child; QName sequenceQName = particleQNameMap.get(child); boolean isArray = xmlSchemaSequence.getMaxOccurs() > 1; // add this as an array to the original class metainfHolder.registerMapping(sequenceQName, sequenceQName, findClassName(sequenceQName, isArray)); if (isArray) { metainfHolder.addtStatus(sequenceQName, SchemaConstants.ARRAY_TYPE); } metainfHolder.addtStatus(sequenceQName, SchemaConstants.PARTICLE_TYPE_ELEMENT); metainfHolder.addMaxOccurs(sequenceQName, xmlSchemaSequence.getMaxOccurs()); metainfHolder.addMinOccurs(sequenceQName, xmlSchemaSequence.getMinOccurs()); metainfHolder.setHasParticleType(true); if (order) { //record the order in the metainf holder for the any metainfHolder.registerQNameIndex(sequenceQName, startingItemNumberOrder + elementOrderMap.get(child)); } } else if (child instanceof XmlSchemaChoice) { XmlSchemaChoice xmlSchemaChoice = (XmlSchemaChoice) child; QName choiceQName = particleQNameMap.get(child); boolean isArray = xmlSchemaChoice.getMaxOccurs() > 1; // add this as an array to the original class metainfHolder.registerMapping(choiceQName, choiceQName, findClassName(choiceQName, isArray)); if (isArray) { metainfHolder.addtStatus(choiceQName, SchemaConstants.ARRAY_TYPE); } metainfHolder.addtStatus(choiceQName, SchemaConstants.PARTICLE_TYPE_ELEMENT); metainfHolder.addMaxOccurs(choiceQName, xmlSchemaChoice.getMaxOccurs()); metainfHolder.addMinOccurs(choiceQName, xmlSchemaChoice.getMinOccurs()); metainfHolder.setHasParticleType(true); if (order) { //record the order in the metainf holder for the any metainfHolder.registerQNameIndex(choiceQName, startingItemNumberOrder + elementOrderMap.get(child)); } } else if (child instanceof XmlSchemaGroupRef) { XmlSchemaGroupRef xmlSchemaGroupRef = (XmlSchemaGroupRef) child; QName groupQName = particleQNameMap.get(child); boolean isArray = xmlSchemaGroupRef.getMaxOccurs() > 1; // add this as an array to the original class String groupClassName = processedGroupTypeMap.get(groupQName); if (isArray) { groupClassName = groupClassName + "[]"; } metainfHolder.registerMapping(groupQName, groupQName, groupClassName); if (isArray) { metainfHolder.addtStatus(groupQName, SchemaConstants.ARRAY_TYPE); } metainfHolder.addtStatus(groupQName, SchemaConstants.PARTICLE_TYPE_ELEMENT); metainfHolder.addMaxOccurs(groupQName, xmlSchemaGroupRef.getMaxOccurs()); metainfHolder.addMinOccurs(groupQName, xmlSchemaGroupRef.getMinOccurs()); metainfHolder.setHasParticleType(true); if (order) { //record the order in the metainf holder for the any metainfHolder.registerQNameIndex(groupQName, startingItemNumberOrder + elementOrderMap.get(child)); } } } //set the ordered flag in the metainf holder metainfHolder.setOrdered(order); } private void processElements(QName parentElementQName, XmlSchemaObjectBase item, Map<XmlSchemaObjectBase, Boolean> processedElementArrayStatusMap, Map processedElementTypeMap, Map<XmlSchemaObjectBase, Integer> elementOrderMap, List<QName> localNillableList, Map<XmlSchemaObjectBase, QName> particleQNameMap, boolean order, int sequenceCounter, XmlSchema parentSchema) throws SchemaCompilationException { if (item instanceof XmlSchemaElement) { //recursively process the element XmlSchemaElement xsElt = (XmlSchemaElement) item; boolean isArray = isArray(xsElt); processElement(xsElt, processedElementTypeMap, localNillableList, parentSchema); //we know for sure this is not an outer type processedElementArrayStatusMap.put(xsElt, isArray); if (order) { //we need to keep the order of the elements. So push the elements to another //hashmap with the order number elementOrderMap.put(xsElt, sequenceCounter); } //handle xsd:any ! We place an OMElement (or an array of OMElements) in the generated class } else if (item instanceof XmlSchemaAny) { XmlSchemaAny any = (XmlSchemaAny) item; processedElementTypeMap.put(new QName(ANY_ELEMENT_FIELD_NAME), any); //any can also be inside a sequence if (order) { elementOrderMap.put(any, new Integer(sequenceCounter)); } //we do not register the array status for the any type processedElementArrayStatusMap.put(any, isArray(any)); } else if (item instanceof XmlSchemaSequence) { // we have to process many sequence types XmlSchemaSequence xmlSchemaSequence = (XmlSchemaSequence) item; if (xmlSchemaSequence.getItems().size() > 0) { BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder(); process(parentElementQName, xmlSchemaSequence.getItems(), beanWriterMetaInfoHolder, true, parentSchema); beanWriterMetaInfoHolder.setParticleClass(true); String localName = parentElementQName.getLocalPart() + "Sequence"; QName sequenceQName = new QName(parentElementQName.getNamespaceURI(), localName + getNextTypeSuffix(localName)); String javaClassName = writeComplexParticle(sequenceQName, beanWriterMetaInfoHolder); processedTypemap.put(sequenceQName, javaClassName); //put the partical to array Boolean isArray = xmlSchemaSequence.getMaxOccurs() > 1 ? Boolean.TRUE : Boolean.FALSE; processedElementArrayStatusMap.put(item, isArray); particleQNameMap.put(item, sequenceQName); if (order) { elementOrderMap.put(item, new Integer(sequenceCounter)); } } } else if (item instanceof XmlSchemaChoice) { // we have to process many sequence types XmlSchemaChoice xmlSchemaChoice = (XmlSchemaChoice) item; if (xmlSchemaChoice.getItems().size() > 0) { BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder(); beanWriterMetaInfoHolder.setChoice(true); processChoiceItems(parentElementQName, xmlSchemaChoice.getItems(), beanWriterMetaInfoHolder, false, parentSchema); beanWriterMetaInfoHolder.setParticleClass(true); String localName = parentElementQName.getLocalPart() + "Choice"; QName choiceQName = new QName(parentElementQName.getNamespaceURI(), localName + getNextTypeSuffix(localName)); String javaClassName = writeComplexParticle(choiceQName, beanWriterMetaInfoHolder); processedTypemap.put(choiceQName, javaClassName); //put the partical to array Boolean isArray = xmlSchemaChoice.getMaxOccurs() > 1 ? Boolean.TRUE : Boolean.FALSE; processedElementArrayStatusMap.put(item, isArray); particleQNameMap.put(item, choiceQName); if (order) { elementOrderMap.put(item, new Integer(sequenceCounter)); } } } else if (item instanceof XmlSchemaGroupRef) { XmlSchemaGroupRef xmlSchemaGroupRef = (XmlSchemaGroupRef) item; QName groupQName = xmlSchemaGroupRef.getRefName(); if (groupQName != null) { if (!processedGroupTypeMap.containsKey(groupQName)) { // processe the schema here XmlSchema resolvedParentSchema = getParentSchema(parentSchema, groupQName, COMPONENT_GROUP); if (resolvedParentSchema == null) { throw new SchemaCompilationException("Can not find the group with the qname" + groupQName + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaGroup xmlSchemaGroup = (XmlSchemaGroup) resolvedParentSchema.getGroups().get(groupQName); if (xmlSchemaGroup != null) { processGroup(xmlSchemaGroup, groupQName, resolvedParentSchema); } } } Boolean isArray = xmlSchemaGroupRef.getMaxOccurs() > 1 ? Boolean.TRUE : Boolean.FALSE; processedElementArrayStatusMap.put(item, isArray); particleQNameMap.put(item, groupQName); if (order) { elementOrderMap.put(item, new Integer(sequenceCounter)); } } else { throw new SchemaCompilationException("Referenced name is null"); } } else { //there may be other types to be handled here. Add them //when we are ready } } /** * @param xmlSchemaGroup * @param schemaGroupQName- we have to pass this since xml schema does not provide * this properly * @param parentSchema * @throws SchemaCompilationException */ private void processGroup(XmlSchemaGroup xmlSchemaGroup, QName schemaGroupQName, XmlSchema parentSchema) throws SchemaCompilationException { // find the group base item XmlSchemaGroupParticle xmlSchemaGroupParticle = xmlSchemaGroup.getParticle(); if (xmlSchemaGroupParticle != null) { if (xmlSchemaGroupParticle instanceof XmlSchemaSequence) { XmlSchemaSequence xmlSchemaSequence = (XmlSchemaSequence) xmlSchemaGroupParticle; if (xmlSchemaSequence.getItems().size() > 0) { BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder(); process(schemaGroupQName, xmlSchemaSequence.getItems(), beanWriterMetaInfoHolder, true, parentSchema); beanWriterMetaInfoHolder.setParticleClass(true); String javaClassName = writeComplexParticle(schemaGroupQName, beanWriterMetaInfoHolder); processedGroupTypeMap.put(schemaGroupQName, javaClassName); // processedTypemap.put(schemaGroupQName, javaClassName); } } else if (xmlSchemaGroupParticle instanceof XmlSchemaChoice) { XmlSchemaChoice xmlSchemaChoice = (XmlSchemaChoice) xmlSchemaGroupParticle; if (xmlSchemaChoice.getItems().size() > 0) { BeanWriterMetaInfoHolder beanWriterMetaInfoHolder = new BeanWriterMetaInfoHolder(); beanWriterMetaInfoHolder.setChoice(true); processChoiceItems(schemaGroupQName, xmlSchemaChoice.getItems(), beanWriterMetaInfoHolder, false, parentSchema); beanWriterMetaInfoHolder.setParticleClass(true); String javaClassName = writeComplexParticle(schemaGroupQName, beanWriterMetaInfoHolder); processedGroupTypeMap.put(schemaGroupQName, javaClassName); // processedTypemap.put(schemaGroupQName, javaClassName); } } } } /** * Checks whether a given element is a binary element * * @param elt */ private boolean isBinary(XmlSchemaElement elt) { return elt.getSchemaType() != null && SchemaConstants.XSD_BASE64.equals(elt.getSchemaType().getQName()); } /** * Checks whether a given qname is a binary * * @param qName */ private boolean isBinary(QName qName) { return qName != null && SchemaConstants.XSD_BASE64.equals(qName); } /** * @param simpleType * @param xsElt * @param parentSchema * @param qname - fake Qname to use if the xsElt is null. * @throws SchemaCompilationException */ private void processSimpleSchemaType(XmlSchemaSimpleType simpleType, XmlSchemaElement xsElt, XmlSchema parentSchema, QName qname) throws SchemaCompilationException { String fullyQualifiedClassName = null; if (simpleType.getQName() != null) { if (processedTypemap.containsKey(simpleType.getQName()) || baseSchemaTypeMap.containsKey(simpleType.getQName())) { return; } // Must do this up front to support recursive types fullyQualifiedClassName = writer.makeFullyQualifiedClassName(simpleType.getQName()); // we put the qname to processed type map it is only named type // otherwise we have to any way process that element. processedTypemap.put(simpleType.getQName(), fullyQualifiedClassName); } else { QName fakeQname; if (xsElt != null) { fakeQname = new QName(xsElt.getQName().getNamespaceURI(), xsElt.getQName().getLocalPart() + getNextTypeSuffix(xsElt.getQName().getLocalPart())); // we have to set this otherwise the ours attribute would not set properly if refered to this simple // type from any other element xsElt.setSchemaTypeName(fakeQname); changedElementSet.add(xsElt); } else { fakeQname = qname; } if (processedTypemap.containsKey(fakeQname) || baseSchemaTypeMap.containsKey(fakeQname)) { return; } fullyQualifiedClassName = writer.makeFullyQualifiedClassName(fakeQname); simpleType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.FAKE_QNAME, fakeQname); // should put this to the processedTypemap to generate the code correctly processedTypemap.put(fakeQname, fullyQualifiedClassName); } //register that in the schema metainfo bag simpleType.addMetaInfo(SchemaConstants.SchemaCompilerInfoHolder.CLASSNAME_KEY, fullyQualifiedClassName); BeanWriterMetaInfoHolder metaInfHolder = processSimpleType(simpleType, parentSchema); metaInfHolder.setSimple(true); if (simpleType.getQName() == null) { this.processedAnonymousComplexTypesMap.put(xsElt, metaInfHolder); QName fakeQname; if (xsElt != null) { fakeQname = new QName(xsElt.getQName().getNamespaceURI(), xsElt.getQName().getLocalPart()); } else { fakeQname = qname; simpleType.setName(fakeQname.getLocalPart()); changedSimpleTypeSet.add(simpleType); simpleType.setSourceURI(fakeQname.getNamespaceURI()); } simpleTypesMap.put(fakeQname, fullyQualifiedClassName); } //add this information to the metainfo holder metaInfHolder.setOwnQname(simpleType.getQName()); if (fullyQualifiedClassName != null) { metaInfHolder.setOwnClassName(fullyQualifiedClassName); } //write the class. This type mapping would have been populated right now //Note - We always write classes for named complex types writeSimpleType(simpleType, metaInfHolder); } private BeanWriterMetaInfoHolder processSimpleType(XmlSchemaSimpleType simpleType, XmlSchema parentSchema) throws SchemaCompilationException { BeanWriterMetaInfoHolder metaInfHolder = new BeanWriterMetaInfoHolder(); // handle the restriction XmlSchemaSimpleTypeContent content = simpleType.getContent(); QName parentSimpleTypeQname = simpleType.getQName(); if (parentSimpleTypeQname == null) { parentSimpleTypeQname = (QName) simpleType.getMetaInfoMap(). get(SchemaConstants.SchemaCompilerInfoHolder.FAKE_QNAME); } if (content != null) { if (content instanceof XmlSchemaSimpleTypeRestriction) { XmlSchemaSimpleTypeRestriction restriction = (XmlSchemaSimpleTypeRestriction) content; QName baseTypeName = restriction.getBaseTypeName(); //check whether the base type is one of the base schema types if (baseSchemaTypeMap.containsKey(baseTypeName)) { //process restriction base type processSimpleRestrictionBaseType(parentSimpleTypeQname, restriction.getBaseTypeName(), metaInfHolder, parentSchema); //process facets if (!SchemaConstants.XSD_BOOLEAN.equals(baseTypeName)) { processFacets(restriction.getFacets(), restriction.getBaseTypeName(), metaInfHolder, parentSchema); } } else { //recurse // this must be a xmlschema bug // it should return the schematype for restriction.getBaseType(): XmlSchema resolvedSchema = getParentSchema(parentSchema, baseTypeName, COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the type " + baseTypeName + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaType restrictionBaseType = resolvedSchema.getTypeByName(baseTypeName); if (restrictionBaseType instanceof XmlSchemaSimpleType) { if ((restrictionBaseType != null) && (!isAlreadyProcessed(baseTypeName))) { processSimpleSchemaType((XmlSchemaSimpleType) restrictionBaseType, null, resolvedSchema, null); } // process restriction processSimpleRestrictionBaseType(parentSimpleTypeQname, restriction.getBaseTypeName(), metaInfHolder, resolvedSchema); } } } } else if (content instanceof XmlSchemaSimpleTypeUnion) { XmlSchemaSimpleTypeUnion simpleTypeUnion = (XmlSchemaSimpleTypeUnion) content; QName[] qnames = simpleTypeUnion.getMemberTypesQNames(); if (qnames != null) { QName qname; for (int i = 0; i < qnames.length; i++) { qname = qnames[i]; if (baseSchemaTypeMap.containsKey(qname)) { metaInfHolder.addMemberType(qname, baseSchemaTypeMap.get(qname)); } else { XmlSchema resolvedSchema = getParentSchema(parentSchema, qname, COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the type " + qname + " from the parent schema " + parentSchema.getTargetNamespace()); } else { XmlSchemaType type = resolvedSchema.getTypeByName(qname); if (type instanceof XmlSchemaSimpleType) { XmlSchemaSimpleType memberSimpleType = (XmlSchemaSimpleType) type; if (!isAlreadyProcessed(qname)) { processSimpleSchemaType(memberSimpleType, null, resolvedSchema, null); } metaInfHolder.addMemberType(qname, processedTypemap.get(qname)); } else { throw new SchemaCompilationException("Unions can not have complex types as a member type"); } } } } } else { QName childQname; int i = 1; for (XmlSchemaSimpleType xmlSchemaObject : simpleTypeUnion.getBaseTypes()) { i++; XmlSchemaSimpleType unionSimpleType = xmlSchemaObject; childQname = unionSimpleType.getQName(); if (childQname == null) { // we create a fake Qname for all these simple types since most propably they don't have one childQname = new QName(parentSimpleTypeQname.getNamespaceURI(), parentSimpleTypeQname.getLocalPart() + getNextTypeSuffix(parentSimpleTypeQname. getLocalPart())); } // this is an inner simple type of the union so it shold not have // processed processSimpleSchemaType(unionSimpleType, null, parentSchema, childQname); metaInfHolder.addMemberType(childQname, processedTypemap.get(childQname)); } } metaInfHolder.setUnion(true); } else if (content instanceof XmlSchemaSimpleTypeList) { XmlSchemaSimpleTypeList simpleTypeList = (XmlSchemaSimpleTypeList) content; QName itemTypeQName = simpleTypeList.getItemTypeName(); if (itemTypeQName != null) { if (!isAlreadyProcessed(itemTypeQName)) { XmlSchema resolvedSchema = getParentSchema(parentSchema, itemTypeQName, COMPONENT_TYPE); if (resolvedSchema == null) { throw new SchemaCompilationException("can not find the type " + itemTypeQName + " from the parent type " + parentSchema.getTargetNamespace()); } else { XmlSchemaType simpleSchemaType = resolvedSchema. getTypeByName(itemTypeQName); if (simpleSchemaType instanceof XmlSchemaSimpleType) { processSimpleSchemaType((XmlSchemaSimpleType) simpleSchemaType, null, resolvedSchema, null); } } } } else { XmlSchemaSimpleType listSimpleType = simpleTypeList.getItemType(); itemTypeQName = listSimpleType.getQName(); if (itemTypeQName == null) { // we create a fake Qname for all these simple types since most propably they don't have one itemTypeQName = new QName(parentSimpleTypeQname.getNamespaceURI(), parentSimpleTypeQname.getLocalPart() + "_type0"); } processSimpleSchemaType(listSimpleType, null, parentSchema, itemTypeQName); } String className = findClassName(itemTypeQName, false); metaInfHolder.setList(true); metaInfHolder.setItemTypeQName(itemTypeQName); metaInfHolder.setItemTypeClassName(className); } } return metaInfHolder; } /** * Find whether a given particle is an array. The logic for deciding * whether a given particle is an array is depending on their minOccurs * and maxOccurs counts. If Maxoccurs is greater than one (1) then the * content is an array. * Also no higher level element will have the maxOccurs greater than one * * @param particle * @throws SchemaCompilationException */ private boolean isArray(XmlSchemaParticle particle) throws SchemaCompilationException { long minOccurs = particle.getMinOccurs(); long maxOccurs = particle.getMaxOccurs(); if (maxOccurs < minOccurs) { throw new SchemaCompilationException(); } else { return (maxOccurs > 1); } } HashMap<String, Integer> mapTypeCount = new HashMap<String, Integer>(); private String getNextTypeSuffix(String localName) { Integer typeCounter = mapTypeCount.get(localName); int count = 0; if (typeCounter != null) { if (typeCounter.intValue() == Integer.MAX_VALUE) { count = 0; } else { count = typeCounter.intValue(); } } mapTypeCount.put(localName, count + 1); return ("_type" + count); } /** * returns the parent schema of the componet having QName compoentTypeQName. * withe the componet type. * * @param parentSchema - parent schema of the given componet * @param componentQName - qname of the componet, of which we want to get the parent schema * @param componetType - type of the componet. this can either be type,element,attribute or attribute group * @return parent schema. */ private XmlSchema getParentSchema(XmlSchema parentSchema, QName componentQName, int componetType) throws SchemaCompilationException { // if the componet do not have a propernamesapce or // it is equals to the xsd schema namesapce // we do not have to do any thing. if ((componentQName == null) || (componentQName.getNamespaceURI() == null) || Constants.URI_2001_SCHEMA_XSD.equals(componentQName.getNamespaceURI())) { return parentSchema; } List<XmlSchema> visitedSchemas = new ArrayList<XmlSchema>(); visitedSchemas.add(parentSchema); XmlSchema newParentSchema = getParentSchemaFromIncludes(parentSchema, componentQName, componetType, visitedSchemas); if (newParentSchema == null) { String targetNamespace = componentQName.getNamespaceURI(); if (loadedSchemaMap.containsKey(targetNamespace)) { XmlSchema tempSchema = loadedSchemaMap.get(targetNamespace); if (isComponetExists(tempSchema, componentQName, componetType)) { newParentSchema = tempSchema; } } else if (availableSchemaMap.containsKey(targetNamespace)) { XmlSchema tempSchema = availableSchemaMap.get(targetNamespace); if (isComponetExists(tempSchema, componentQName, componetType)) { newParentSchema = tempSchema; } } } return newParentSchema; } private XmlSchema getParentSchemaFromIncludes(XmlSchema parentSchema, QName componentQName, int componetType, List<XmlSchema> visitedSchemas) throws SchemaCompilationException { XmlSchema newParentSchema = null; if (isComponetExists(parentSchema, componentQName, componetType)) { newParentSchema = parentSchema; } else { // this componet must either be in a import or and include XmlSchema externalSchema = null; for (XmlSchemaExternal externalComponent : parentSchema.getExternals()) { externalSchema = externalComponent.getSchema(); // if this is an inline import without a schema location // xmlschema does not load the schema. // so we try to figure out it either from the available schemas // or from the laded schemas. if ((externalSchema == null) && externalComponent instanceof XmlSchemaImport) { XmlSchemaImport xmlSchemaImport = (XmlSchemaImport) externalComponent; String importNamespce = xmlSchemaImport.getNamespace(); if ((importNamespce != null) && !importNamespce. equals(Constants.URI_2001_SCHEMA_XSD)) { if (loadedSchemaMap.containsKey(importNamespce)) { externalSchema = loadedSchemaMap.get(importNamespce); } else if (availableSchemaMap.containsKey(importNamespce)) { XmlSchema tempSchema = availableSchemaMap.get(importNamespce); compile(tempSchema); externalSchema = tempSchema; } } } if (externalSchema != null) { // find the componet in the new external schema. if (!visitedSchemas.contains(externalSchema)) { visitedSchemas.add(externalSchema); newParentSchema = getParentSchemaFromIncludes(externalSchema, componentQName, componetType, visitedSchemas); } } if (newParentSchema != null) { // i.e we have found the schema break; } } } return newParentSchema; } private boolean isComponetExists(XmlSchema schema, QName componentQName, int componetType) { //first we need to check whether we checking the correct schema. if ((schema.getTargetNamespace() != null) && (!schema.getTargetNamespace().equals(componentQName.getNamespaceURI()))) { return false; } boolean isExists = false; switch (componetType) { case COMPONENT_TYPE: { isExists = (schema.getTypeByName(componentQName.getLocalPart()) != null); break; } case COMPONENT_ELEMENT: { isExists = (schema.getElementByName(componentQName.getLocalPart()) != null); break; } case COMPONENT_ATTRIBUTE: { isExists = (schema.getAttributes().get(componentQName) != null); break; } case COMPONENT_ATTRIBUTE_GROUP: { isExists = (schema.getAttributeGroups().get(componentQName) != null); break; } case COMPONENT_GROUP: { isExists = (schema.getGroups().get(componentQName) != null); break; } } return isExists; } public Map<String, XmlSchema> getLoadedSchemaMap() { return this.loadedSchemaMap; } }