gt:         if (type.isOpen()) {
context: /*******************************************************************************
   * Copyright (c) 1998, 2012 Oracle and/or its affiliates. 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.sdo.helper;
  
  import commonj.sdo.Property;
  import commonj.sdo.Type;
  import commonj.sdo.helper.HelperContext;
  import java.io.StringWriter;
  import java.util.List;
  import java.util.Map;
  import java.util.Vector;
  import javax.xml.namespace.QName;
  import org.eclipse.persistence.sdo.SDOConstants;
  import org.eclipse.persistence.sdo.SDOProperty;
  import org.eclipse.persistence.sdo.SDOType;
  import org.eclipse.persistence.internal.helper.ClassConstants;
  import org.eclipse.persistence.internal.oxm.Namespace;
  import org.eclipse.persistence.internal.oxm.XMLConversionManager;
  import org.eclipse.persistence.internal.oxm.schema.SchemaModelProject;
  import org.eclipse.persistence.internal.oxm.schema.model.*;
  import org.eclipse.persistence.oxm.XMLConstants;
  import org.eclipse.persistence.oxm.XMLContext;
  import org.eclipse.persistence.oxm.XMLDescriptor;
  import org.eclipse.persistence.oxm.XMLLogin;
  import org.eclipse.persistence.oxm.XMLMarshaller;
  import org.eclipse.persistence.oxm.platform.DOMPlatform;
  import org.eclipse.persistence.sessions.Project;
  
  /**
   * <p><b>Purpose</b> SDOSchemaGenerator generates an XSD (returned as a String)
   * from a list of SDO Type objects. Populates an org.eclipse.persistence.internal.oxm.schema.model.Schema
   * object and makes use of org.eclipse.persistence.internal.oxm.schema.SchemaModelProject to marshal
   * the Schema Object to XML.
   * @see commonj.sdo.XSDHelper
   */
  public class SDOSchemaGenerator {
      private Map namespaceToSchemaLocation;
      private SchemaLocationResolver schemaLocationResolver;
      private List allTypes;
      private Schema generatedSchema;
  
      // hold the context containing all helpers so that we can preserve inter-helper relationships
      private HelperContext aHelperContext;
  
      public SDOSchemaGenerator(HelperContext aContext) {
          aHelperContext = aContext;
      }
  
      /**
       * <p>Method to generate an XSD. Note the following:<ul>
       * <li> All types must have same URI
       * <li> Referenced types in same URI will also be generated in schema
       * <li> Includes will never be generated
       * <li> Imports will be generated for referenced types in other URIs
       * </ul>
       * @param types The list of commonj.sdo.Type objects to generate the XSD from
       * @param aSchemaLocationResolver implementation of the org.eclipse.persistence.sdo.helper.SchemaLocationResolver interface
       * used for getting the value of the schemaLocation attribute of generated imports and includes
       * @return String The generated XSD.
       */
      public String generate(List types, SchemaLocationResolver aSchemaLocationResolver) {
          schemaLocationResolver = aSchemaLocationResolver;
          if ((types == null) || (types.size() == 0)) {
              throw new IllegalArgumentException("No Schema was generated from null or empty list of types.");
          }
  
          String uri = null;
          Type firstType = (Type)types.get(0);
          uri = firstType.getURI();
  
          allTypes = types;
          generateSchema(uri, types);
          
          //Now we have a built schema model        
          Project p = new SchemaModelProject();
          Vector generatedNamespaces = generatedSchema.getNamespaceResolver().getNamespaces();
          XMLDescriptor desc = ((XMLDescriptor)p.getDescriptor(Schema.class));
          for (int i = 0; i < generatedNamespaces.size(); i++) {
              Namespace next = (Namespace)generatedNamespaces.get(i);
              desc.getNamespaceResolver().put(next.getPrefix(), next.getNamespaceURI());
  
              if (next.getNamespaceURI().equals(SDOConstants.SDO_URL) || next.getNamespaceURI().equals(SDOConstants.SDOXML_URL) || next.getNamespaceURI().equals(SDOConstants.SDOJAVA_URL)) {
                  if (!importExists(generatedSchema.getImports(), next.getNamespaceURI())) {
                      Import theImport = new Import();
                      theImport.setNamespace(next.getNamespaceURI());
                      String schemaLocation = "classpath:/xml/";
                      String customLocation = null;
                      if (next.getNamespaceURI().equals(SDOConstants.SDO_URL)) {
                          if(schemaLocationResolver != null) {
                              customLocation = schemaLocationResolver.resolveSchemaLocation(firstType, SDOConstants.SDO_BOOLEAN);
                          }
                          if(customLocation != null) {
                              schemaLocation = customLocation;
                          } else {
                              schemaLocation += "sdoModel.xsd";
                          }
                      } else if (next.getNamespaceURI().equals(SDOConstants.SDOXML_URL)) {
                          if(schemaLocationResolver != null) {
                              customLocation = schemaLocationResolver.resolveSchemaLocation(firstType, new SDOType(SDOConstants.SDOXML_URL, "XMLInfo"));
                          }
                          if(customLocation != null) {
                              schemaLocation = customLocation;
                          } else {
                              schemaLocation += "sdoXML.xsd";
                          }
                      } else if (next.getNamespaceURI().equals(SDOConstants.SDOJAVA_URL)) {
                          if(schemaLocationResolver != null) {
                              customLocation = schemaLocationResolver.resolveSchemaLocation(firstType, SDOConstants.SDO_BOOLEANOBJECT);
                          }
                          if(customLocation != null) {
                              schemaLocation = customLocation;
                          } else {
                              schemaLocation += "sdoJava.xsd";
                          }
                      }
                      theImport.setSchemaLocation(schemaLocation);
                      generatedSchema.getImports().add(theImport);
                  }
              }
          }
  
          XMLLogin login = new XMLLogin();
          login.setDatasourcePlatform(new DOMPlatform());
          p.setDatasourceLogin(login);
  
          XMLContext context = new XMLContext(p);
  
          XMLMarshaller marshaller = context.createMarshaller();
  
          StringWriter generatedSchemaWriter = new StringWriter();
          marshaller.marshal(generatedSchema, generatedSchemaWriter);
          return generatedSchemaWriter.toString();
      }
  
      /**
       * <p>Method to generate an XSD. Note the following:<ul>
       * <li> All types must have same URI
       * <li> Referenced types in same URI will also be generated in schema
       * <li> Includes will never be generated
       * <li> Imports will be generated for referenced types in other URIs
       * </ul>
       * @param types The list of commonj.sdo.Type objects to generate the XSD from
       * @param aNamespaceToSchemaLocation map of namespaces to schemaLocations
       * used for getting the value of the schemaLocation attribute of generated imports and includes
       * @return String The generated XSD.
      */
      public String generate(List types, Map aNamespaceToSchemaLocation) {
          if ((types == null) || (types.size() == 0)) {
              throw new IllegalArgumentException("No Schema was generated from null or empty list of types.");
          }
  
          String uri = null;
          namespaceToSchemaLocation = aNamespaceToSchemaLocation;
   
          Type firstType = (Type)types.get(0);
          if (firstType == null) {
              throw new IllegalArgumentException("No Schema was generated from a list of types containing null elements");
          } else {
              uri = firstType.getURI();
          }
          allTypes = types;
          generateSchema(uri, types);
  
          //Now we have a built schema model						      
          Project p = new SchemaModelProject();
          Vector namespaces = generatedSchema.getNamespaceResolver().getNamespaces();
          for (int i = 0; i < namespaces.size(); i++) {
              Namespace next = (Namespace)namespaces.get(i);
              ((XMLDescriptor)p.getDescriptor(Schema.class)).getNamespaceResolver().put(next.getPrefix(), next.getNamespaceURI());
          }
  
          XMLLogin login = new XMLLogin();
          login.setDatasourcePlatform(new DOMPlatform());
          p.setDatasourceLogin(login);
          XMLContext context = new XMLContext(p);
          XMLMarshaller marshaller = context.createMarshaller();
  
          StringWriter generatedSchemaWriter = new StringWriter();
          marshaller.marshal(generatedSchema, generatedSchemaWriter);
          return generatedSchemaWriter.toString();
      }
  
      private void generateSchema(String uri, List typesWithSameUri) { 
          generatedSchema = new Schema();
          generatedSchema.setTargetNamespace(uri);
          generatedSchema.setDefaultNamespace(uri);
  
          generatedSchema.setAttributeFormDefault(false);
          generatedSchema.setElementFormDefault(true);
          String javaPackage = null;
  
          for (int i = 0; i < typesWithSameUri.size(); i++) {
              SDOType nextType = (SDOType)typesWithSameUri.get(i);
              if (nextType.isSubType()) {
                  //A schema can not be generated because the following type has more than 1 base type + type
              }
  
              if (!nextType.isDataType()) {
                  String fullName = nextType.getInstanceClassName();
                  if (fullName != null) {
                      String nextPackage = null;
  
                      int lastDot = fullName.lastIndexOf('.');
                      if (lastDot != -1) {
                          nextPackage = fullName.substring(0, lastDot);
                      }
  
                      if (nextPackage != null) {
                          javaPackage = nextPackage;
                      }
                  }
              }            
  
              if (nextType.isDataType()) {
                  //generate simple type
                  SimpleType generatedType = generateSimpleType(nextType);
                  generatedSchema.addTopLevelSimpleTypes(generatedType);
              } else {
                  //generate complex type
                  ComplexType generatedType = generateComplexType(nextType);
                  generatedSchema.addTopLevelComplexTypes(generatedType);
  
                  //generate global element for the complex type generated above
                  Element element = buildElementForComplexType(generatedSchema, generatedType);
                  if (element != null) {
                      generatedSchema.addTopLevelElement(element);
                  }
              }
          }
          if (javaPackage != null) {
              getPrefixForURI(SDOConstants.SDOJAVA_URL);
              generatedSchema.getAttributesMap().put(SDOConstants.SDOJAVA_PACKAGE_QNAME, javaPackage);
          }
      }
  
      private SimpleType generateSimpleType(Type type) {
          SDOType sdoType = (SDOType) type;
          SimpleType simpleType = new SimpleType();
  
          String xsdLocalName = sdoType.getXsdLocalName();
          if (xsdLocalName != null) {
              simpleType.setName(xsdLocalName);
          } else {
              simpleType.setName(sdoType.getName());
          }
  
          if ((sdoType.getAppInfoElements() != null) && (sdoType.getAppInfoElements().size() > 0)) {
              Annotation annotation = new Annotation();
  
              annotation.setAppInfo(sdoType.getAppInfoElements());
              simpleType.setAnnotation(annotation);
          }
          
          if ((xsdLocalName != null) && !(xsdLocalName.equals(sdoType.getName()))) {
              String sdoXmlPrefix = getPrefixForURI(SDOConstants.SDOXML_URL);
              QName qname = new QName(SDOConstants.SDOXML_URL, SDOConstants.SDOXML_NAME, sdoXmlPrefix);
              simpleType.getAttributesMap().put(qname, sdoType.getName());
          }
  
          if ((sdoType.getAliasNames() != null) && (sdoType.getAliasNames().size() > 0)) {
              String sdoXmlPrefix = getPrefixForURI(SDOConstants.SDOXML_URL);
              String aliasNamesString = buildAliasNameString(sdoType.getAliasNames());
              QName qname = new QName(SDOConstants.SDOXML_URL, SDOConstants.SDOXML_ALIASNAME, sdoXmlPrefix);
              simpleType.getAttributesMap().put(qname, aliasNamesString);
          }
  
          Object value = sdoType.get(SDOConstants.JAVA_CLASS_PROPERTY);
          if ((value != null) && value instanceof String) {
              String sdoJavaPrefix = getPrefixForURI(SDOConstants.SDOJAVA_URL);
              QName qname = new QName(SDOConstants.SDOJAVA_URL, SDOConstants.SDOJAVA_INSTANCECLASS, sdoJavaPrefix);
              simpleType.getAttributesMap().put(qname, value);
          }
  
          SDOType baseType = null;
          if (sdoType.isSubType()) {
              baseType = (SDOType) sdoType.getBaseTypes().get(0);
          } 
  
          if (baseType != null) {
              Restriction restriction = new Restriction();
              addTypeToListIfNeeded(sdoType, baseType);
              QName schemaType = ((SDOTypeHelper)aHelperContext.getTypeHelper()).getXSDTypeFromSDOType(baseType);
  
              if (schemaType != null) {
                  String prefix = getPrefixStringForURI(schemaType.getNamespaceURI());
                  restriction.setBaseType(prefix + schemaType.getLocalPart());
              } else {
                  String prefix = getPrefixStringForURI(baseType.getURI());
                  restriction.setBaseType(prefix + baseType.getName());
              }
              simpleType.setRestriction(restriction);
          }
  
          return simpleType;
      }
  
      private ComplexType generateComplexType(Type type) {
          SDOType sdoType = (SDOType) type;
          ComplexType complexType = new ComplexType();
          String xsdLocalName = sdoType.getXsdLocalName();
          if (xsdLocalName != null) {
              complexType.setName(xsdLocalName);
          } else {
              complexType.setName(sdoType.getName());
          }
  
          if ((xsdLocalName != null) && !(xsdLocalName.equals(sdoType.getName()))) {
              String sdoXmlPrefix = getPrefixForURI(SDOConstants.SDOXML_URL);
              QName qname = new QName(SDOConstants.SDOXML_URL, SDOConstants.SDOXML_NAME, sdoXmlPrefix);
              complexType.getAttributesMap().put(qname, sdoType.getName());
          }
  
          complexType.setAbstractValue(sdoType.isAbstract());
          if ((sdoType.getAppInfoElements() != null) && (sdoType.getAppInfoElements().size() > 0)) {
              Annotation annotation = new Annotation();
              annotation.setAppInfo(sdoType.getAppInfoElements());
              complexType.setAnnotation(annotation);
          }
  
          if ((sdoType.getAliasNames() != null) && (sdoType.getAliasNames().size() > 0)) {
              String sdoXmlPrefix = getPrefixForURI(SDOConstants.SDOXML_URL);
              String aliasNamesString = buildAliasNameString(sdoType.getAliasNames());
  
              QName qname = new QName(SDOConstants.SDOXML_URL, SDOConstants.SDOXML_ALIASNAME, sdoXmlPrefix);
              complexType.getAttributesMap().put(qname, aliasNamesString);
          }
  
          complexType.setMixed(sdoType.isSequenced());
          Type baseType = null;
          if (sdoType.isSubType()) {
              baseType = (Type)sdoType.getBaseTypes().get(0);
  
              //baseName = base.getName();
              //String baseURI = ((Type)type.getBaseTypes().get(0)).getURI();
              //if (baseURI != type.getURI()) {
              //need to add something  to track referenced uris for includes/imports
              //}
          }
  
          if (baseType != null) {
              addTypeToListIfNeeded(sdoType, baseType);
              Extension extension = new Extension();
              QName schemaType = ((SDOTypeHelper)aHelperContext.getTypeHelper()).getXSDTypeFromSDOType(baseType);
  
              //fixed below for bug5893546
              if (schemaType != null) {
                  extension.setBaseType(getPrefixStringForURI(schemaType.getNamespaceURI()) + schemaType.getLocalPart());
              } else if ((baseType.getURI() == null) || (baseType.getURI().equalsIgnoreCase(generatedSchema.getTargetNamespace()))) {
                  extension.setBaseType(baseType.getName());
              } else {
                  extension.setBaseType(getPrefixStringForURI(baseType.getURI()) + baseType.getName());
              }
  
              buildElementsAndAttributes(extension, sdoType);
              ComplexContent complexContent = new ComplexContent();
              complexContent.setExtension(extension);
              complexType.setComplexContent(complexContent);
              return complexType;
          }
  
          buildElementsAndAttributes(complexType, sdoType);
  
          return complexType;
      }
  
      private void buildElementsAndAttributes(Object owner, Type type) {
          List properties = ((SDOType) type).getDeclaredProperties();
          NestedParticle nestedParticle = null;
  
          if ((properties == null) || (properties.size() == 0)) {
              if (type.isOpen()) {
                  nestedParticle = new Sequence();
              } else {
                  return;
              }
          } else {
              if (type.isSequenced()) {
                  nestedParticle = new Choice();
                  nestedParticle.setMaxOccurs(Occurs.UNBOUNDED);
              } else {
                  nestedParticle = new Sequence();
              }
          }
          for (int i = 0; i < properties.size(); i++) {
              Property nextProperty = (Property)properties.get(i);
  
              if (aHelperContext.getXSDHelper().isElement(nextProperty)) {
                  Element elem = buildElement(nextProperty, nestedParticle);
                  nestedParticle.addElement(elem);
              } else if (aHelperContext.getXSDHelper().isAttribute(nextProperty)) {
                  Attribute attr = buildAttribute(nextProperty);
                  if (owner instanceof ComplexType) {
                      ((ComplexType)owner).getOrderedAttributes().add(attr);
                  } else if (owner instanceof Extension) {
                      ((Extension)owner).getOrderedAttributes().add(attr);
                  }
              }
          }
  