blob: 6bc917255cf424b8b5fba520d09a4a55a706a2b9 [file] [log] [blame]
/*
* 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;
}
}