/**
* Copyright © 2006-2016 Web Cohesion (info@webcohesion.com)
*
* Licensed 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 com.webcohesion.enunciate.modules.jaxb.model;
import com.webcohesion.enunciate.api.InterfaceDescriptionFile;
import com.webcohesion.enunciate.javac.TypeElementComparator;
import com.webcohesion.enunciate.modules.jaxb.EnunciateJaxbContext;
import com.webcohesion.enunciate.modules.jaxb.model.types.MapXmlType;
import com.webcohesion.enunciate.modules.jaxb.model.types.XmlClassType;
import com.webcohesion.enunciate.modules.jaxb.model.types.XmlType;
import javax.xml.namespace.QName;
import java.util.*;
/**
* Configuration information about a schema.
*
* @author Ryan Heaton
*/
public class SchemaInfo {
private String id;
private String namespace;
private String filename;
private String jaxbBindingVersion;
private String appinfo;
private String explicitLocation;
private InterfaceDescriptionFile schemaFile;
private final EnunciateJaxbContext context;
private final Collection<ImplicitSchemaElement> implicitSchemaElements = new TreeSet<ImplicitSchemaElement>(new ImplicitSchemaElementComparator());
private final Collection<ImplicitSchemaAttribute> implicitSchemaAttributes = new TreeSet<ImplicitSchemaAttribute>(new ImplicitSchemaAttributeComparator());
private final Collection<TypeDefinition> typeDefinitions = new TreeSet<TypeDefinition>(new TypeElementComparator());
private final Collection<RootElementDeclaration> rootElements = new TreeSet<RootElementDeclaration>(new TypeElementComparator());
private final Collection<Registry> registries = new ArrayList<Registry>();
private final Collection<LocalElementDeclaration> localElementDeclarations = new ArrayList<LocalElementDeclaration>();
private final TreeSet<Schema> packages = new TreeSet<Schema>();
public SchemaInfo(EnunciateJaxbContext context) {
this.context = context;
}
public EnunciateJaxbContext getContext() {
return context;
}
/**
* A unique id for this schema.
*
* @return A unique id for this schema.
*/
public String getId() {
return id;
}
/**
* A unique id for this schema.
*
* @param id A unique id for this schema.
*/
public void setId(String id) {
this.id = id;
}
/**
* The target namespace.
*
* @return The target namespace.
*/
public String getNamespace() {
return namespace;
}
/**
* The target namespace.
*
* @param namespace The target namespace.
*/
public void setNamespace(String namespace) {
this.namespace = namespace;
}
/**
* The XML schema file for this schema.
*
* @return The XML schema file for this schema.
*/
public InterfaceDescriptionFile getSchemaFile() {
return schemaFile;
}
/**
* The XML schema file for this schema.
*
* @param schemaFile The XML schema file for this schema.
*/
public void setSchemaFile(InterfaceDescriptionFile schemaFile) {
this.schemaFile = schemaFile;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getJaxbBindingVersion() {
return jaxbBindingVersion;
}
public void setJaxbBindingVersion(String jaxbBindingVersion) {
this.jaxbBindingVersion = jaxbBindingVersion;
}
public String getAppinfo() {
return appinfo;
}
public void setAppinfo(String appinfo) {
this.appinfo = appinfo;
}
public String getExplicitLocation() {
return explicitLocation;
}
public void setExplicitLocation(String explicitLocation) {
this.explicitLocation = explicitLocation;
}
/**
* The collection of types defined in this schema.
*
* @return The collection of types defined in this schema.
*/
public Collection<TypeDefinition> getTypeDefinitions() {
return typeDefinitions;
}
/**
* Get the implicit schema elements to be included in this schema.
*
* @return The implicit schema elements to be included in this schema.
*/
public Collection<ImplicitSchemaElement> getImplicitSchemaElements() {
return implicitSchemaElements;
}
/**
* Get the implicit schema attributes to be included in this schema.
*
* @return The implicit schema attributes to be included in this schema.
*/
public Collection<ImplicitSchemaAttribute> getImplicitSchemaAttributes() {
return implicitSchemaAttributes;
}
/**
* The collection of global elements defined in this schema.
*
* @return The collection of global elements defined in this schema.
*/
public Collection<RootElementDeclaration> getRootElements() {
return rootElements;
}
/**
* The XML registries.
*
* @return The XML registries.
*/
public Collection<Registry> getRegistries() {
return registries;
}
/**
* Local element declarations.
*
* @return Local element declarations.
*/
public Collection<LocalElementDeclaration> getLocalElementDeclarations() {
return localElementDeclarations;
}
/**
* The set of packages that make up this schema info.
*
* @return The set of packages that make up this schema info.
*/
public Set<Schema> getPackages() {
return this.packages;
}
/**
* The elementFormDefault for this schema.
*
* @return The elementFormDefault for this schema.
*/
public String getElementFormDefault() {
for (Schema pckg : getPackages()) {
if (pckg.getElementFormDefault() != null) {
return pckg.getElementFormDefault().toString().toLowerCase();
}
}
return null;
}
/**
* The attributeFormDefault for this schema.
*
* @return The attributeFormDefault for this schema.
*/
public String getAttributeFormDefault() {
for (Schema pckg : getPackages()) {
if (pckg.getAttributeFormDefault() != null) {
return pckg.getAttributeFormDefault().toString().toLowerCase();
}
}
return null;
}
public String getDocumentation() {
for (Schema pckg : getPackages()) {
String docValue = pckg.getDocValue();
if (docValue != null) {
return docValue;
}
}
return null;
}
/**
* The imported namespace of a specific schema.
*
* @return The imported namespace of a specific schema.
*/
public Set<String> getReferencedNamespaces() {
Set<String> referencedNamespaces = new HashSet<String>();
for (TypeDefinition typeDefinition : getTypeDefinitions()) {
addReferencedNamespaces(typeDefinition, referencedNamespaces);
}
for (RootElementDeclaration rootElement : getRootElements()) {
referencedNamespaces.add(rootElement.getNamespace());
referencedNamespaces.add(rootElement.getTypeDefinition().getNamespace());
}
for (ImplicitSchemaElement schemaElement : implicitSchemaElements) {
QName typeQName = schemaElement.getTypeQName();
if (typeQName != null) {
referencedNamespaces.add(typeQName.getNamespaceURI());
}
if (schemaElement instanceof ImplicitRootElement) {
for (ImplicitChildElement childElement : ((ImplicitRootElement) schemaElement).getChildElements()) {
addReferencedNamespaces(childElement.getXmlType(), new LinkedList<String>(), referencedNamespaces);
}
}
}
for (ImplicitSchemaAttribute schemaAttribute : implicitSchemaAttributes) {
QName typeQName = schemaAttribute.getTypeQName();
if (typeQName != null) {
referencedNamespaces.add(typeQName.getNamespaceURI());
}
}
for (LocalElementDeclaration localElementDeclaration : localElementDeclarations) {
QName typeQName = localElementDeclaration.getElementXmlType().getQname();
if (typeQName != null) {
referencedNamespaces.add(typeQName.getNamespaceURI());
}
}
referencedNamespaces.add(getNamespace());
//remove the obvious referenced namespace.
referencedNamespaces.remove("http://www.w3.org/2001/XMLSchema");
//consolidate the "" and the null:
if (referencedNamespaces.remove(null)) {
referencedNamespaces.add("");
}
return referencedNamespaces;
}
/**
* Adds the referenced namespaces of the given type definition to the given set.
*
* @param typeDefinition The type definition.
* @param referencedNamespaces The set of referenced namespaces.
*/
private void addReferencedNamespaces(TypeDefinition typeDefinition, Set<String> referencedNamespaces) {
addReferencedNamespaces(typeDefinition, new LinkedList<String>(), referencedNamespaces);
}
private void addReferencedNamespaces(TypeDefinition typeDefinition, LinkedList<String> stack, Set<String> referencedNamespaces) {
if (stack.contains(typeDefinition.getQualifiedName().toString())) {
return;
}
stack.push(typeDefinition.getQualifiedName().toString());
try {
for (Attribute attribute : typeDefinition.getAttributes()) {
QName ref = attribute.getRef();
if (ref != null) {
referencedNamespaces.add(ref.getNamespaceURI());
}
else {
addReferencedNamespaces(attribute.getBaseType(), stack, referencedNamespaces);
}
}
for (Element element : typeDefinition.getElements()) {
for (Element choice : element.getChoices()) {
QName ref = choice.getRef();
if (ref != null) {
referencedNamespaces.add(ref.getNamespaceURI());
}
else {
addReferencedNamespaces(choice.getBaseType(), stack, referencedNamespaces);
}
}
}
Value value = typeDefinition.getValue();
if (value != null) {
addReferencedNamespaces(value.getBaseType(), stack, referencedNamespaces);
}
if (typeDefinition instanceof QNameEnumTypeDefinition) {
for (EnumValue enumValue : ((QNameEnumTypeDefinition) typeDefinition).getEnumValues()) {
if (enumValue.getValue() != null) {
referencedNamespaces.add(((QName)enumValue.getValue()).getNamespaceURI());
}
}
}
addReferencedNamespaces(typeDefinition.getBaseType(), stack, referencedNamespaces);
}
finally {
stack.pop();
}
}
/**
* Adds the referenced namespaces of the given xml type to the given set.
*
* @param xmlType The xml type.
* @param referencedNamespaces The set of referenced namespaces.
*/
private void addReferencedNamespaces(XmlType xmlType, LinkedList<String> stack, Set<String> referencedNamespaces) {
if (!xmlType.isAnonymous()) {
referencedNamespaces.add(xmlType.getNamespace());
}
else if (xmlType instanceof MapXmlType) {
referencedNamespaces.add(((MapXmlType) xmlType).getKeyType().getNamespace());
referencedNamespaces.add(((MapXmlType) xmlType).getValueType().getNamespace());
}
if (xmlType instanceof XmlClassType) {
addReferencedNamespaces(((XmlClassType) xmlType).getTypeDefinition(), stack, referencedNamespaces);
}
}
/**
* The list of imported schemas.
*
* @return The list of imported schemas.
*/
public List<SchemaInfo> getImportedSchemas() {
Set<String> importedNamespaces = getReferencedNamespaces();
importedNamespaces.remove(getNamespace() == null ? "" : getNamespace());
List<SchemaInfo> schemas = new ArrayList<SchemaInfo>();
for (String ns : importedNamespaces) {
SchemaInfo schema = lookupSchema(ns);
if (schema != null) {
schemas.add(schema);
}
else {
SchemaInfo schemaInfo = new SchemaInfo(context);
schemaInfo.setNamespace(ns);
schemas.add(schemaInfo);
}
}
return schemas;
}
/**
* Convenience method to lookup a namespace schema given a namespace.
*
* @param namespace The namespace for which to lookup the schema.
* @return The schema info.
*/
protected SchemaInfo lookupSchema(String namespace) {
if ("".equals(namespace)) {
namespace = null;
}
return this.context.getSchemas().get(namespace);
}
/**
* Compares implicit elements by element name.
*/
private static class ImplicitSchemaElementComparator implements Comparator<ImplicitSchemaElement> {
/**
* @param element1 The first element.
* @param element2 The second element.
* @return The comparison of the element names.
*/
public int compare(ImplicitSchemaElement element1, ImplicitSchemaElement element2) {
return element1.getElementName().compareTo(element2.getElementName());
}
}
/**
* Compares implicit attributes by attribute name.
*/
private static class ImplicitSchemaAttributeComparator implements Comparator<ImplicitSchemaAttribute> {
/**
* @param attribute1 The first attribute.
* @param attribute2 The second attribute.
* @return The comparison of the attribute names.
*/
public int compare(ImplicitSchemaAttribute attribute1, ImplicitSchemaAttribute attribute2) {
return attribute1.getAttributeName().compareTo(attribute2.getAttributeName());
}
}
}