/*******************************************************************************
* Copyright (c) 1998, 2009 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.jaxb.compiler;
import java.beans.Introspector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlList;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.namespace.QName;
import org.eclipse.persistence.jaxb.javamodel.Helper;
import org.eclipse.persistence.jaxb.javamodel.JavaClass;
import org.eclipse.persistence.internal.oxm.schema.model.*;
import org.eclipse.persistence.oxm.XMLConstants;
/**
* INTERNAL:
* <p><b>Purpose:</b>To generate Schema objects based on a map of TypeInfo objects, and some
* additional information gathered by the AnnotationsProcessing phase.
* <p><b>Responsibilities:</b><ul>
* <li>Create and maintain a collection of Schema objects based on the provided TypeInfo objects</li>
* <li>Add additional global elements to the schema based on an optional map (for WS integration)</li>
* <li>Should create a schema for each namespace encountered during generation.</li>
* </ul>
* <p>This class is used by the Generator to handle the generation of Schemas. The
* Generator passes in a map of TypeInfo objects, generated by the Annotations processor.
* The generated Schemas are stored in a map of keyed on Target Namespace.
* @see org.eclipse.persistence.jaxb.compiler.TypeInfo
* @see org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor
* @see org.eclipse.persistence.jaxb.compiler.Generator
* @since Oracle TopLink 11.1.1.0.0
* @author mmacivor
*/
public class SchemaGenerator {
private HashMap<String, Schema> schemaForNamespace;
private Schema schema;
private int schemaCount;
private Helper helper;
private HashMap<String, TypeInfo> typeInfo;
private HashMap<String, NamespaceInfo> packageToNamespaceMappings;
private HashMap<String, SchemaTypeInfo> schemaTypeInfo;
private HashMap<String, QName> userDefinedSchemaTypes;
public SchemaGenerator(Helper helper) {
this.helper = helper;
}
public Schema generateSchema(ArrayList<JavaClass> typeInfoClasses, HashMap<String, TypeInfo> typeInfo, HashMap<String, QName> userDefinedSchemaTypes, HashMap<String, NamespaceInfo> packageToNamespaceMappings, HashMap<QName, ElementDeclaration> additionalGlobalElements) {
this.typeInfo = typeInfo;
this.userDefinedSchemaTypes = userDefinedSchemaTypes;
this.packageToNamespaceMappings = packageToNamespaceMappings;
this.schemaCount = 0;
this.schemaTypeInfo = new HashMap<String, SchemaTypeInfo>(typeInfo.size());
for (JavaClass javaClass : typeInfoClasses) {
addSchemaComponents(javaClass);
}
populateSchemaTypes();
if (additionalGlobalElements != null) {
addGlobalElements(additionalGlobalElements);
}
return schema;
}
public void addSchemaComponents(JavaClass myClass) {
// first check for type
String myClassName = myClass.getQualifiedName();
Element rootElement = null;
TypeInfo info = (TypeInfo)typeInfo.get(myClassName);
SchemaTypeInfo schemaTypeInfo = new SchemaTypeInfo();
schemaTypeInfo.setSchemaTypeName(new QName(info.getClassNamespace(), info.getSchemaTypeName()));
this.schemaTypeInfo.put(myClass.getQualifiedName(), schemaTypeInfo);
NamespaceInfo namespaceInfo = this.packageToNamespaceMappings.get(myClass.getPackage().getQualifiedName());
Schema schema = getSchemaForNamespace(info.getClassNamespace());
info.setSchema(schema);
String typeName = info.getSchemaTypeName();
String[] propOrder = info.getPropOrder();
String pfx = "";
Property valueField = null;
if (helper.isAnnotationPresent(myClass, XmlRootElement.class)) {
//Create the root element and add it to the schema
XmlRootElement rootElemAnnotation = (XmlRootElement) helper.getAnnotation(myClass, XmlRootElement.class);
rootElement = new Element();
String elementName = rootElemAnnotation.name();
if (elementName.equals("##default") || elementName.equals("")) {
if (myClassName.indexOf("$") != -1) {
elementName = Introspector.decapitalize(myClassName.substring(myClassName.lastIndexOf('$') + 1));
} else {
elementName = Introspector.decapitalize(myClassName.substring(myClassName.lastIndexOf('.') + 1));
}
// TODO - remove this TCK hack...
if (elementName.length() >= 3) {
int idx = elementName.length()-1;
char ch = elementName.charAt(idx-1);
if (Character.isDigit(ch)) {
char lastCh = Character.toUpperCase(elementName.charAt(idx));
elementName = elementName.substring(0, idx) + lastCh;
}
}
}
rootElement.setName(elementName);
String rootNamespace = rootElemAnnotation.namespace();
if (rootNamespace.equals("##default")) {
getSchemaForNamespace(namespaceInfo.getNamespace()).addTopLevelElement(rootElement);
schemaTypeInfo.getGlobalElementDeclarations().add(new QName(namespaceInfo.getNamespace(), rootNamespace));
rootNamespace = namespaceInfo.getNamespace();
} else {
getSchemaForNamespace(rootNamespace).addTopLevelElement(rootElement);
schemaTypeInfo.getGlobalElementDeclarations().add(new QName(rootNamespace, elementName));
}
// handle root-level imports/includes [schema = the type's schema]
Schema rootSchema = getSchemaForNamespace(rootNamespace);
if (schema != rootSchema) {
Import schemaImport = new Import();
schemaImport.setNamespace(schema.getTargetNamespace());
schemaImport.setSchemaLocation(schema.getName());
rootSchema.getImports().add(schemaImport);
}
// setup a prefix, if necessary
if (!info.getClassNamespace().equals("")) {
pfx = getPrefixForNamespace(info.getClassNamespace(), rootSchema.getNamespaceResolver());
if (pfx == null) {
pfx = rootSchema.getNamespaceResolver().generatePrefix();
rootSchema.getNamespaceResolver().put(pfx, info.getClassNamespace());
}
pfx += ":";
}
}
ArrayList<String> propertyNames = info.getPropertyNames();
if (info.isEnumerationType() || (propertyNames.size() == 1 && helper.isAnnotationPresent(info.getProperties().get(propertyNames.get(0)).getElement(), XmlValue.class))) {
SimpleType type = new SimpleType();
//simple type case, we just need the name and namespace info
//TODO: add namespace support
if (typeName.equals("")) {
//In this case, it should be a type under
//A root elem or locally defined whenever used
if(rootElement != null) {
rootElement.setSimpleType(type);
}
} else {
type.setName(typeName);
schema.addTopLevelSimpleTypes(type);
if (rootElement != null) {
rootElement.setType(pfx+type.getName());
}
}
//Figure out schema type and set it as Restriction
QName restrictionType = null;
Restriction restriction = new Restriction();
if (info.isEnumerationType()) {
restrictionType = ((EnumTypeInfo)info).getRestrictionBase();
restriction.setEnumerationFacets(this.getEnumerationFacetsFor((EnumTypeInfo)info));
restriction.setBaseType(XMLConstants.SCHEMA_PREFIX + ":" + restrictionType.getLocalPart());
type.setRestriction(restriction);
} else {
valueField = info.getProperties().get(propertyNames.get(0));
QName baseType = getSchemaTypeFor(valueField.getType());
if (helper.isAnnotationPresent(valueField.getElement(), XmlList.class)) {
//generate a list instead of a restriction
List list = new List();
list.setItemType(XMLConstants.SCHEMA_PREFIX + ":" + baseType.getLocalPart());
type.setList(list);
} else {
if (helper.isAnnotationPresent(valueField.getElement(), XmlSchemaType.class)) {
XmlSchemaType schemaType = (XmlSchemaType) helper.getAnnotation(valueField.getElement(), XmlSchemaType.class);
baseType = new QName(XMLConstants.SCHEMA_INSTANCE_URL, schemaType.name());
}
restriction.setBaseType(XMLConstants.SCHEMA_PREFIX + ":" + baseType.getLocalPart());
type.setRestriction(restriction);
}
}
info.setSimpleType(type);
} else if ((valueField = this.getXmlValueFieldForSimpleContent(info.getPropertyList())) != null) {
ComplexType type = new ComplexType();
SimpleContent content = new SimpleContent();
if (typeName.equals("")) {
if(rootElement != null) {
rootElement.setComplexType(type);
}
info.setComplexType(type);
} else {
type.setName(typeName);
schema.addTopLevelComplexTypes(type);
if(rootElement != null) {
rootElement.setType(pfx+type.getName());
}
}
QName extensionType = getSchemaTypeFor(valueField.getType());
if (helper.isAnnotationPresent(valueField.getElement(), XmlSchemaType.class)) {
XmlSchemaType schemaType = (XmlSchemaType) helper.getAnnotation(valueField.getElement(), XmlSchemaType.class);
extensionType = new QName(XMLConstants.SCHEMA_INSTANCE_URL, schemaType.name());
}
Extension extension = new Extension();
extension.setBaseType(XMLConstants.SCHEMA_PREFIX + ":" + extensionType.getLocalPart());
content.setExtension(extension);
type.setSimpleContent(content);
info.setComplexType(type);
} else {
ComplexType type = new ComplexType();
JavaClass superClass = (JavaClass) myClass.getSuperclass();
TypeInfo parentTypeInfo = this.typeInfo.get(superClass.getQualifiedName());
Extension extension = null;
if (parentTypeInfo != null) {
extension = new Extension();
// may need to qualify the type
String parentPrefix = getPrefixForNamespace(parentTypeInfo.getClassNamespace(), namespaceInfo.getNamespaceResolver());
if (parentPrefix != null) {
extension.setBaseType(parentPrefix + ":" + parentTypeInfo.getSchemaTypeName());
} else {
extension.setBaseType(parentTypeInfo.getSchemaTypeName());
}
ComplexContent content = new ComplexContent();
content.setExtension(extension);
type.setComplexContent(content);
}
TypeDefParticle compositor = null;
if (propOrder.length == 0) {
// TODO: needed to hack for TCK - spec requires an 'all' to be
// generated in cases where propOrder == 0, however, the TCK
// requires the extension case to use sequences
if(info.hasElementRefs()) {
//needs to be a sequence
compositor = new Sequence();
if(extension != null) {
extension.setSequence((Sequence)compositor);
} else {
type.setSequence((Sequence)compositor);
}
} else if (extension != null) {
//compositor = new Sequence();
//extension.setSequence((Sequence)compositor);
compositor = new All();
extension.setAll((All)compositor);
} else {
compositor = new All();
type.setAll((All)compositor);
}
} else {
compositor = new Sequence();
if (extension != null) {
extension.setSequence((Sequence)compositor);
} else {
type.setSequence((Sequence)compositor);
}
}
if (typeName.equals("")) {
if (rootElement != null) {
rootElement.setComplexType(type);
}
info.setComplexType(type);
info.setCompositor(compositor);
} else {
type.setName(typeName);
if(rootElement != null) {
rootElement.setType(pfx+type.getName());
}
schema.addTopLevelComplexTypes(type);
info.setComplexType(type);
info.setCompositor(compositor);
}
info.setPropOrder(propOrder);
}
}
public void addToSchemaType(ArrayList<Property> properties, TypeDefParticle compositor, ComplexType type, Schema schema) {
for (Property next : properties) {
// TODO: we seem to get a null property on occasion
// need to look into this...
if (next == null) { continue; }
TypeDefParticle parentCompositor = compositor;
boolean isChoice = (parentCompositor instanceof Choice);
ComplexType parentType = type;
if (!helper.isAnnotationPresent(next.getElement(), XmlTransient.class)) {
// deal with the XmlElementWrapper case
if (!isChoice && helper.isAnnotationPresent(next.getElement(), XmlElementWrapper.class)) {
XmlElementWrapper wrapper = (XmlElementWrapper) helper.getAnnotation(next.getElement(), XmlElementWrapper.class);
Element wrapperElement = new Element();
wrapperElement.setName(wrapper.name());
wrapperElement.setMinOccurs("0");
compositor.addElement(wrapperElement);
ComplexType wrapperType = new ComplexType();
Sequence wrapperSequence = new Sequence();
wrapperType.setSequence(wrapperSequence);
wrapperElement.setComplexType(wrapperType);
parentType = wrapperType;
parentCompositor = wrapperSequence;
}
if (helper.isAnnotationPresent(next.getElement(), XmlAttribute.class)) {
Attribute attribute = new Attribute();
QName attributeName = next.getSchemaName();
attribute.setName(attributeName.getLocalPart());
if(next.isRequired()) {
attribute.setUse(Attribute.REQUIRED);
}
//Check to see if it's a collection.
//Should assume XmlList on any collection?
JavaClass javaType = next.getType();
if (next.getGenericType() != null) {
javaType = (JavaClass) next.getGenericType();
}
String typeName = null;
TypeInfo info = (TypeInfo)typeInfo.get(next.getType().getQualifiedName());
if (info != null) {
if (!info.isComplexType()) {
typeName = info.getSimpleType().getName();
}
} else {
if (helper.isAnnotationPresent(next.getElement(), XmlID.class)) {
typeName = XMLConstants.SCHEMA_PREFIX + ":ID";
} else if (helper.isAnnotationPresent(next.getElement(), XmlIDREF.class)) {
typeName = XMLConstants.SCHEMA_PREFIX + ":IDREF";
} else {
QName schemaType = next.getSchemaType();
if (schemaType == null) {
schemaType = getSchemaTypeFor(javaType);
}
if (schemaType != null) {
typeName = XMLConstants.SCHEMA_PREFIX + ":" + schemaType.getLocalPart();
} else {
typeName = XMLConstants.SCHEMA_PREFIX + ":anySimpleType";
}
}
}
if (isCollectionType(next)) {
// assume XmlList for an attribute collection
SimpleType localType = new SimpleType();
org.eclipse.persistence.internal.oxm.schema.model.List list = new org.eclipse.persistence.internal.oxm.schema.model.List();
list.setItemType(typeName);
localType.setList(list);
attribute.setSimpleType(localType);
} else {
// may need to qualify the type
if (typeName != null && !typeName.contains(":")) {
if (info.getSchema() == schema) {
String prefix = getPrefixForNamespace(schema.getTargetNamespace(), schema.getNamespaceResolver());
if (prefix != null) {
typeName = prefix + ":" + typeName;
}
}
}
attribute.setType(typeName);
}
if (!attributeName.getNamespaceURI().equals("")) {
Schema attributeSchema = this.getSchemaForNamespace(attributeName.getNamespaceURI());
if(attributeSchema.getTopLevelAttributes().get(attribute.getName()) == null) {
//don't overwrite existing global elements and attributes.
attributeSchema.getTopLevelAttributes().put(attribute.getName(), attribute);
}
if(!importExists(schema, attributeSchema.getName())){
Import schemaImport = new Import();
schemaImport.setNamespace(attributeSchema.getTargetNamespace());
schemaImport.setSchemaLocation(attributeSchema.getName());
schema.getImports().add(schemaImport);
schema.getNamespaceResolver().put(schema.getNamespaceResolver().generatePrefix(), attributeSchema.getTargetNamespace());
}
Attribute reference = new Attribute();
//add an import here
String prefix = getPrefixForNamespace(attributeSchema.getTargetNamespace(), schema.getNamespaceResolver());
if (prefix == null) {
reference.setRef(attribute.getName());
} else {
reference.setRef(prefix + ":" + attribute.getName());
}
if(parentType.getSimpleContent() != null) {
parentType.getSimpleContent().getExtension().getOrderedAttributes().add(reference);
} else {
parentType.getOrderedAttributes().add(reference);
}
} else {
if(parentType.getSimpleContent() != null) {
parentType.getSimpleContent().getExtension().getOrderedAttributes().add(attribute);
} else {
parentType.getOrderedAttributes().add(attribute);
}
}
} else if (helper.isAnnotationPresent(next.getElement(), XmlAnyAttribute.class)) {
AnyAttribute anyAttribute = new AnyAttribute();
anyAttribute.setProcessContents(AnyAttribute.LAX);
if (type.getSimpleContent() != null) {
SimpleContent content = type.getSimpleContent();
content.getRestriction().setAnyAttribute(anyAttribute);
} else {
type.setAnyAttribute(anyAttribute);
}
} else if(next.isChoice()) {
Choice choice = new Choice();
ArrayList<Property> choiceProperties = (ArrayList<Property>)((ChoiceProperty)next).getChoiceProperties();
addToSchemaType(choiceProperties, choice, parentType, schema);
if(parentCompositor instanceof Sequence) {
((Sequence)parentCompositor).addChoice(choice);
} else if(parentCompositor instanceof Choice) {
((Choice)parentCompositor).addChoice(choice);
}
} else if(next.isAny()) {
Any any = new Any();
AnyProperty anyProp = (AnyProperty)next;
if(anyProp.isLax()) {
any.setProcessContents("lax");
}
if(parentCompositor instanceof Sequence) {
((Sequence)parentCompositor).addAny(any);
} else if(parentCompositor instanceof Choice) {
((Choice)parentCompositor).addAny(any);
}
} else if(next.isReference()) {
ReferenceProperty refProp = (ReferenceProperty)next;
java.util.List<ElementDeclaration> referencedElements = refProp.getReferencedElements();
if(referencedElements.size() == 1) {
//if only a single reference, just add the element.
Element element = new Element();
ElementDeclaration decl = referencedElements.get(0);
String localName = decl.getElementName().getLocalPart();
Schema referencedSchema = this.getSchemaForNamespace(decl.getElementName().getNamespaceURI());
if(referencedSchema != schema) {
//add import and namespace prefix if requried
if(!importExists(schema, referencedSchema.getName())){
Import schemaImport = new Import();
schemaImport.setSchemaLocation(referencedSchema.getName());
schemaImport.setNamespace(referencedSchema.getTargetNamespace());
schema.getImports().add(schemaImport);
if (schemaImport.getNamespace() != null) {
schema.getNamespaceResolver().put(schema.getNamespaceResolver().generatePrefix(), schemaImport.getNamespace());
}
}
}
String prefix = this.getPrefixForNamespace(decl.getElementName().getNamespaceURI(), schema.getNamespaceResolver());
if(prefix == null || prefix.equals("")) {
element.setRef(localName);
} else {
element.setRef(prefix + ":" + localName);
}
if(isCollectionType(next)) {
element.setMaxOccurs("unbounded");
}
parentCompositor.addElement(element);
} else {
// otherwise, add a choice of referenced elements.
Choice choice = new Choice();
if(isCollectionType(next)) {
choice.setMaxOccurs("unbounded");
}
for(ElementDeclaration elementDecl:referencedElements) {
Element element = new Element();
String localName = elementDecl.getElementName().getLocalPart();
Schema referencedSchema = this.getSchemaForNamespace(elementDecl.getElementName().getNamespaceURI());
if(referencedSchema != schema) {
//add import and namespace prefix if requried
if(!importExists(schema, referencedSchema.getName())){
Import schemaImport = new Import();
schemaImport.setSchemaLocation(referencedSchema.getName());
schemaImport.setNamespace(referencedSchema.getTargetNamespace());
schema.getImports().add(schemaImport);
if (schemaImport.getNamespace() != null) {
schema.getNamespaceResolver().put(schema.getNamespaceResolver().generatePrefix(), schemaImport.getNamespace());
}
}
}
String prefix = this.getPrefixForNamespace(elementDecl.getElementName().getNamespaceURI(), schema.getNamespaceResolver());
if(prefix == null || prefix.equals("")) {
element.setRef(localName);
} else {
element.setRef(prefix + ":" + localName);
}
choice.addElement(element);
}
if(parentCompositor instanceof Sequence) {
((Sequence)parentCompositor).addChoice(choice);
} else if(parentCompositor instanceof Choice) {
((Choice)parentCompositor).addChoice(choice);
}
}
} else if (!helper.isAnnotationPresent(next.getElement(), XmlValue.class)) {
Element element = new Element();
// Set minOccurs based on the 'required' flag
element.setMinOccurs(next.isRequired() ? "1" : "0");
QName elementName = next.getSchemaName();
JavaClass javaType = next.getType();
boolean isCollectionType = isCollectionType(next);
if (isCollectionType) {
JavaClass gType = next.getGenericType();
if (gType != null && gType.hasActualTypeArguments()) {
Object[] params = gType.getActualTypeArguments().toArray();
javaType = (JavaClass) params[0];
}
}
element.setName(elementName.getLocalPart());
TypeInfo info = (TypeInfo)typeInfo.get(javaType.getQualifiedName());
String typeName = null;
boolean isComplexType = false;
if (info != null) {
if (helper.isAnnotationPresent(next.getElement(), XmlID.class)) {
typeName = XMLConstants.SCHEMA_PREFIX + ":ID";
} else if (helper.isAnnotationPresent(next.getElement(), XmlIDREF.class)) {
typeName = XMLConstants.SCHEMA_PREFIX + ":IDREF";
} else {
isComplexType = info.isComplexType();
if (info.isComplexType()) {
typeName = info.getComplexType().getName();
} else {
typeName = info.getSimpleType().getName();
}
}
if(typeName == null) {
//need to add complex-type locally, or reference global element
if(!info.hasRootElement()) {
if(info.isComplexType()) {
element.setComplexType(info.getComplexType());
} else {
element.setSimpleType(info.getSimpleType());
}
}
}
// check to see if we need to add an import
if (info.getSchema() != schema) {
if(!importExists(schema, info.getSchema().getName())){
Import schemaImport = new Import();
schemaImport.setSchemaLocation(info.getSchema().getName());
schemaImport.setNamespace(info.getSchema().getTargetNamespace());
schema.getImports().add(schemaImport);
if (schemaImport.getNamespace() != null) {
schema.getNamespaceResolver().put(schema.getNamespaceResolver().generatePrefix(), schemaImport.getNamespace());
}
// qualify the type name
String prefix = getPrefixForNamespace(info.getSchema().getTargetNamespace(), schema.getNamespaceResolver());
if (prefix != null && !typeName.equals("")) {
typeName = prefix + ":" + typeName;
}
}
}
} else {
QName schemaType = next.getSchemaType();
if (schemaType == null) {
schemaType = getSchemaTypeFor(javaType);
}
if (schemaType != null) {
typeName = XMLConstants.SCHEMA_PREFIX + ":" + schemaType.getLocalPart();
}
}
// may need to qualify the type
if (typeName != null && !typeName.contains(":")) {
if (info.getSchema() == schema) {
String prefix = getPrefixForNamespace(schema.getTargetNamespace(), schema.getNamespaceResolver());
if (prefix != null) {
typeName = prefix + ":" + typeName;
}
}
}
if (isCollectionType) {
if (helper.isAnnotationPresent(next.getElement(), XmlList.class)) {
if (isComplexType) {
//TODO: Error case probably
}
SimpleType localSimpleType = new SimpleType();
org.eclipse.persistence.internal.oxm.schema.model.List list = new org.eclipse.persistence.internal.oxm.schema.model.List();
list.setItemType(typeName);
localSimpleType.setList(list);
element.setSimpleType(localSimpleType);
} else {
element.setMaxOccurs("unbounded");
element.setType(typeName);
}
} else {
element.setType(typeName);
}
if (!elementName.getNamespaceURI().equals("")) {
Element reference = new Element();
reference.setMinOccurs(element.getMinOccurs());
reference.setMaxOccurs(element.getMaxOccurs());
Schema attributeSchema = this.getSchemaForNamespace(elementName.getNamespaceURI());
if(attributeSchema.getTopLevelElements().get(element.getName()) == null) {
// reset min/max occurs as they aren't applicable for global elements
element.setMinOccurs(null);
element.setMaxOccurs(null);
//don't overwrite global elements. May have been defined by a type.
attributeSchema.getTopLevelElements().put(element.getName(), element);
}
if (attributeSchema != schema && (!importExists(schema, attributeSchema.getName()))){
Import schemaImport = new Import();
schemaImport.setNamespace(attributeSchema.getTargetNamespace());
schemaImport.setSchemaLocation(attributeSchema.getName());
schema.getImports().add(schemaImport);
schema.getNamespaceResolver().put(schema.getNamespaceResolver().generatePrefix(), attributeSchema.getTargetNamespace());
}
//add an import here
String prefix = getPrefixForNamespace(attributeSchema.getTargetNamespace(), schema.getNamespaceResolver());
if (prefix == null) {
reference.setRef(element.getName());
} else {
reference.setRef(prefix + ":" + element.getName());
}
parentCompositor.addElement(reference);
} else {
parentCompositor.addElement(element);
}
}
}
}
}
public QName getSchemaTypeFor(JavaClass javaClass) {
// check user defined types first
QName schemaType = (QName) userDefinedSchemaTypes.get(javaClass.getQualifiedName());
if (schemaType == null) {
schemaType = (QName) helper.getXMLToJavaTypeMap().get(javaClass.getRawName());
}
if (schemaType == null) {
return XMLConstants.ANY_SIMPLE_TYPE_QNAME;
}
return schemaType;
}
public void populateSchemaTypes() {
Iterator<String> classNames = typeInfo.keySet().iterator();
while (classNames.hasNext()) {
String javaClassName = classNames.next();
TypeInfo info = (TypeInfo)typeInfo.get(javaClassName);
if (info.isComplexType()) {
ComplexType type = info.getComplexType();
TypeDefParticle compositor = info.getCompositor();
String[] propOrder = info.getPropOrder();
if (propOrder.length == 0 || propOrder[0].equals("")) {
propOrder = (String[])info.getPropertyNames().toArray(new String[info.getPropertyNames().size()]);
}
ArrayList<Property> properties = new ArrayList(propOrder.length);
for (int i = 0; i < propOrder.length; i++) {
Property next = info.getProperties().get(propOrder[i]);
properties.add(next);
}
addToSchemaType(properties, compositor, type, info.getSchema());
}
}
}
public String getSchemaTypeNameForClassName(String className) {
String typeName = Introspector.decapitalize(className.substring(className.lastIndexOf('.') + 1));
return typeName;
}
public ArrayList getEnumerationFacetsFor(EnumTypeInfo info) {
Collection valuesCollection = info.getObjectValuesToFieldValues().values();
return new ArrayList(valuesCollection);
}
public Property getXmlValueFieldForSimpleContent(ArrayList<Property> properties) {
boolean foundValue = false;
boolean foundNonAttribute = false;
Property valueField = null;
for (Property prop : properties) {
if (helper.isAnnotationPresent(prop.getElement(), XmlValue.class)) {
foundValue = true;
valueField = prop;
} else if (!helper.isAnnotationPresent(prop.getElement(), XmlAttribute.class) && !helper.isAnnotationPresent(prop.getElement(), XmlTransient.class) && !helper.isAnnotationPresent(prop.getElement(), XmlAnyAttribute.class)) {
foundNonAttribute = true;
}
}
if (foundValue && !foundNonAttribute) {
return valueField;
}
return null;
}
public boolean isCollectionType(Property field) {
JavaClass type = field.getType();
return (helper.getJavaClass(java.util.Collection.class).isAssignableFrom(type)
|| helper.getJavaClass(java.util.List.class).isAssignableFrom(type)
|| helper.getJavaClass(java.util.Set.class).isAssignableFrom(type));
}
private Schema getSchemaForNamespace(String namespace) {
if(schemaForNamespace == null) {
schemaForNamespace = new HashMap<String, Schema>();
}
Schema schema = schemaForNamespace.get(namespace);
if (schema == null) {
NamespaceInfo namespaceInfo = getNamespaceInfoForNamespace(namespace);
schema = new Schema();
schema.setName("schema" + schemaCount + ".xsd");
schemaCount++;
if (!namespace.equals("")) {
schema.setTargetNamespace(namespace);
String prefix = null;
if (namespaceInfo != null) {
prefix = namespaceInfo.getNamespaceResolver().resolveNamespaceURI(namespace);
}
if (prefix == null) {
prefix = schema.getNamespaceResolver().generatePrefix();
}
schema.getNamespaceResolver().put(prefix, namespace);
}
if (namespaceInfo != null) {
schema.setAttributeFormDefault(namespaceInfo.isAttributeFormQualified());
schema.setElementFormDefault(namespaceInfo.isElementFormQualified());
}
schemaForNamespace.put(namespace, schema);
}
return schema;
}
public Collection<Schema> getAllSchemas() {
if(schemaForNamespace == null) {
schemaForNamespace = new HashMap<String, Schema>();
}
return schemaForNamespace.values();
}
public NamespaceInfo getNamespaceInfoForNamespace(String namespace) {
Collection<NamespaceInfo> namespaceInfo = packageToNamespaceMappings.values();
for (NamespaceInfo info : namespaceInfo) {
if (info.getNamespace().equals(namespace)) {
return info;
}
}
return null;
}
public String getPrefixForNamespace(String URI, org.eclipse.persistence.oxm.NamespaceResolver namespaceResolver) {
Enumeration keys = namespaceResolver.getPrefixes();
while (keys.hasMoreElements()) {
String next = (String)keys.nextElement();
String nextUri = namespaceResolver.resolveNamespacePrefix(next);
if (nextUri.equals(URI)) {
return next;
}
}
return null;
}
public void addGlobalElements(HashMap<QName, ElementDeclaration> additionalElements) {
for (QName next : additionalElements.keySet()) {
String namespaceURI = next.getNamespaceURI();
Schema targetSchema = getSchemaForNamespace(namespaceURI);
if(targetSchema.getTopLevelElements().get(next.getLocalPart()) == null) {
Element element = new Element();
element.setName(next.getLocalPart());
ElementDeclaration nextElement = additionalElements.get(next);
JavaClass javaClass = helper.getJavaClass(nextElement.getJavaTypeName());
// First check for built in type
QName schemaType = (QName) helper.getXMLToJavaTypeMap().get(javaClass.getRawName());
if (schemaType != null) {
element.setType(XMLConstants.SCHEMA_PREFIX + ":" + schemaType.getLocalPart());
} else {
TypeInfo type = (TypeInfo)this.typeInfo.get(javaClass.getQualifiedName());
if (type != null) {
String typeName = null;
if (type.isComplexType()) {
typeName = type.getComplexType().getName();
} else {
typeName = type.getSimpleType().getName();
}
// check namespace of schemaType
if (type.getClassNamespace().equals(namespaceURI)) {
// no need to prefix here
element.setType(typeName);
} else {
Schema complexTypeSchema = getSchemaForNamespace(type.getClassNamespace());
String complexTypeSchemaNS = complexTypeSchema.getTargetNamespace();
if(complexTypeSchemaNS == null) {
complexTypeSchemaNS = "";
}
if(!importExists(targetSchema, complexTypeSchema.getName())){
Import schemaImport = new Import();
schemaImport.setNamespace(complexTypeSchema.getTargetNamespace());
schemaImport.setSchemaLocation(complexTypeSchema.getName());
targetSchema.getImports().add(schemaImport);
// Don't need to generate prefix for default namespace
if (!complexTypeSchemaNS.equals("")) {
targetSchema.getNamespaceResolver().put(targetSchema.getNamespaceResolver().generatePrefix(), complexTypeSchemaNS);
}
}
String prefix = targetSchema.getNamespaceResolver().resolveNamespaceURI(complexTypeSchema.getTargetNamespace());
if(prefix != null) {
element.setType(prefix + ":" + typeName);
} else {
element.setType(typeName);
}
}
}
}
if(nextElement.getSubstitutionHead() != null) {
String subLocal = nextElement.getSubstitutionHead().getLocalPart();
String subNamespace = nextElement.getSubstitutionHead().getNamespaceURI();
String prefix = getPrefixForNamespace(subNamespace, targetSchema.getNamespaceResolver());
if(prefix == null || prefix.equals("")) {
element.setSubstitutionGroup(subLocal);
} else {
element.setSubstitutionGroup(prefix + ":" + subLocal);
}
}
targetSchema.addTopLevelElement(element);
SchemaTypeInfo info = this.schemaTypeInfo.get(javaClass.getQualifiedName());
if (info == null) {
//probably for a simple type, not generated by toplink
info = new SchemaTypeInfo();
info.setSchemaTypeName(schemaType);
schemaTypeInfo.put(javaClass.getQualifiedName(), info);
}
info.getGlobalElementDeclarations().add(next);
}
}
}
public HashMap<String, SchemaTypeInfo> getSchemaTypeInfo() {
return this.schemaTypeInfo;
}
private boolean importExists(Schema schema, String schemaName){
java.util.List imports = schema.getImports();
for(int i=0;i < imports.size();i++){
Import nextImport = (Import)imports.get(i);
if(nextImport.getSchemaLocation() != null && nextImport.getSchemaLocation().equals(schemaName)){
return true;
}
}
return false;
}
}