aboutsummaryrefslogtreecommitdiff
path: root/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java')
-rw-r--r--src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java1615
1 files changed, 0 insertions, 1615 deletions
diff --git a/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java b/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java
deleted file mode 100644
index a9cb5bed..00000000
--- a/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/XmlSchemaGenerator.java
+++ /dev/null
@@ -1,1615 +0,0 @@
-/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.xml.internal.bind.v2.schemagen;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.Writer;
-import java.io.File;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.ArrayList;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.activation.MimeType;
-import javax.xml.bind.SchemaOutputResolver;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.namespace.QName;
-import javax.xml.transform.Result;
-import javax.xml.transform.stream.StreamResult;
-
-import com.sun.istack.internal.Nullable;
-import com.sun.istack.internal.NotNull;
-import com.sun.xml.internal.bind.Util;
-import com.sun.xml.internal.bind.api.CompositeStructure;
-import com.sun.xml.internal.bind.api.ErrorListener;
-import com.sun.xml.internal.bind.v2.TODO;
-import com.sun.xml.internal.bind.v2.WellKnownNamespace;
-import com.sun.xml.internal.bind.v2.util.CollisionCheckStack;
-import com.sun.xml.internal.bind.v2.util.StackRecorder;
-import static com.sun.xml.internal.bind.v2.WellKnownNamespace.XML_SCHEMA;
-import com.sun.xml.internal.bind.v2.model.core.Adapter;
-import com.sun.xml.internal.bind.v2.model.core.ArrayInfo;
-import com.sun.xml.internal.bind.v2.model.core.AttributePropertyInfo;
-import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
-import com.sun.xml.internal.bind.v2.model.core.Element;
-import com.sun.xml.internal.bind.v2.model.core.ElementInfo;
-import com.sun.xml.internal.bind.v2.model.core.ElementPropertyInfo;
-import com.sun.xml.internal.bind.v2.model.core.EnumConstant;
-import com.sun.xml.internal.bind.v2.model.core.EnumLeafInfo;
-import com.sun.xml.internal.bind.v2.model.core.MapPropertyInfo;
-import com.sun.xml.internal.bind.v2.model.core.MaybeElement;
-import com.sun.xml.internal.bind.v2.model.core.NonElement;
-import com.sun.xml.internal.bind.v2.model.core.NonElementRef;
-import com.sun.xml.internal.bind.v2.model.core.PropertyInfo;
-import com.sun.xml.internal.bind.v2.model.core.ReferencePropertyInfo;
-import com.sun.xml.internal.bind.v2.model.core.TypeInfo;
-import com.sun.xml.internal.bind.v2.model.core.TypeInfoSet;
-import com.sun.xml.internal.bind.v2.model.core.TypeRef;
-import com.sun.xml.internal.bind.v2.model.core.ValuePropertyInfo;
-import com.sun.xml.internal.bind.v2.model.core.WildcardMode;
-import com.sun.xml.internal.bind.v2.model.impl.ClassInfoImpl;
-import com.sun.xml.internal.bind.v2.model.nav.Navigator;
-import com.sun.xml.internal.bind.v2.runtime.SwaRefAdapter;
-import static com.sun.xml.internal.bind.v2.schemagen.Util.*;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Any;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.AttrDecls;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ComplexExtension;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ComplexType;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ComplexTypeHost;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ExplicitGroup;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Import;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.List;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalAttribute;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalElement;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Schema;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleExtension;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleRestrictionModel;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleType;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleTypeHost;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TopLevelAttribute;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TopLevelElement;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TypeHost;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ContentModelContainer;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TypeDefParticle;
-import com.sun.xml.internal.bind.v2.schemagen.xmlschema.AttributeType;
-import com.sun.xml.internal.bind.v2.schemagen.episode.Bindings;
-import com.sun.xml.internal.txw2.TXW;
-import com.sun.xml.internal.txw2.TxwException;
-import com.sun.xml.internal.txw2.TypedXmlWriter;
-import com.sun.xml.internal.txw2.output.ResultFactory;
-import com.sun.xml.internal.txw2.output.XmlSerializer;
-import java.util.Collection;
-import java.util.HashSet;
-import org.xml.sax.SAXParseException;
-
-/**
- * Generates a set of W3C XML Schema documents from a set of Java classes.
- *
- * <p>
- * A client must invoke methods in the following order:
- * <ol>
- * <li>Create a new {@link XmlSchemaGenerator}
- * <li>Invoke {@link #add} methods, multiple times if necessary.
- * <li>Invoke {@link #write}
- * <li>Discard the {@link XmlSchemaGenerator}.
- * </ol>
- *
- * @author Ryan Shoemaker
- * @author Kohsuke Kawaguchi (kk@kohsuke.org)
- */
-public final class XmlSchemaGenerator<T,C,F,M> {
-
- private static final Logger logger = Util.getClassLogger();
-
- /**
- * Java classes to be written, organized by their namespace.
- *
- * <p>
- * We use a {@link TreeMap} here so that the suggested names will
- * be consistent across JVMs.
- *
- * @see SchemaOutputResolver#createOutput(String, String)
- */
- private final Map<String,Namespace> namespaces = new TreeMap<String,Namespace>(NAMESPACE_COMPARATOR);
-
- /**
- * {@link ErrorListener} to send errors to.
- */
- private ErrorListener errorListener;
-
- /** model navigator **/
- private Navigator<T,C,F,M> navigator;
-
- private final TypeInfoSet<T,C,F,M> types;
-
- /**
- * Representation for xs:string.
- */
- private final NonElement<T,C> stringType;
-
- /**
- * Represents xs:anyType.
- */
- private final NonElement<T,C> anyType;
-
- /**
- * Used to detect cycles in anonymous types.
- */
- private final CollisionCheckStack<ClassInfo<T,C>> collisionChecker = new CollisionCheckStack<ClassInfo<T,C>>();
-
- public XmlSchemaGenerator( Navigator<T,C,F,M> navigator, TypeInfoSet<T,C,F,M> types ) {
- this.navigator = navigator;
- this.types = types;
-
- this.stringType = types.getTypeInfo(navigator.ref(String.class));
- this.anyType = types.getAnyTypeInfo();
-
- // populate the object
- for( ClassInfo<T,C> ci : types.beans().values() )
- add(ci);
- for( ElementInfo<T,C> ei1 : types.getElementMappings(null).values() )
- add(ei1);
- for( EnumLeafInfo<T,C> ei : types.enums().values() )
- add(ei);
- for( ArrayInfo<T,C> a : types.arrays().values())
- add(a);
- }
-
- private Namespace getNamespace(String uri) {
- Namespace n = namespaces.get(uri);
- if(n==null)
- namespaces.put(uri,n=new Namespace(uri));
- return n;
- }
-
- /**
- * Adds a new class to the list of classes to be written.
- *
- * <p>
- * A {@link ClassInfo} may have two namespaces --- one for the element name
- * and the other for the type name. If they are different, we put the same
- * {@link ClassInfo} to two {@link Namespace}s.
- */
- public void add( ClassInfo<T,C> clazz ) {
- assert clazz!=null;
-
- String nsUri = null;
-
- if(clazz.getClazz()==navigator.asDecl(CompositeStructure.class))
- return; // this is a special class we introduced for JAX-WS that we *don't* want in the schema
-
- if(clazz.isElement()) {
- // put element -> type reference
- nsUri = clazz.getElementName().getNamespaceURI();
- Namespace ns = getNamespace(nsUri);
- ns.classes.add(clazz);
- ns.addDependencyTo(clazz.getTypeName());
-
- // schedule writing this global element
- add(clazz.getElementName(),false,clazz);
- }
-
- QName tn = clazz.getTypeName();
- if(tn!=null) {
- nsUri = tn.getNamespaceURI();
- } else {
- // anonymous type
- if(nsUri==null)
- return;
- }
-
- Namespace n = getNamespace(nsUri);
- n.classes.add(clazz);
-
- // search properties for foreign namespace references
- for( PropertyInfo<T,C> p : clazz.getProperties()) {
- n.processForeignNamespaces(p, 1);
- if (p instanceof AttributePropertyInfo) {
- AttributePropertyInfo<T,C> ap = (AttributePropertyInfo<T,C>) p;
- String aUri = ap.getXmlName().getNamespaceURI();
- if(aUri.length()>0) {
- // global attribute
- getNamespace(aUri).addGlobalAttribute(ap);
- n.addDependencyTo(ap.getXmlName());
- }
- }
- if (p instanceof ElementPropertyInfo) {
- ElementPropertyInfo<T,C> ep = (ElementPropertyInfo<T,C>) p;
- for (TypeRef<T,C> tref : ep.getTypes()) {
- String eUri = tref.getTagName().getNamespaceURI();
- if(eUri.length()>0 && !eUri.equals(n.uri)) {
- getNamespace(eUri).addGlobalElement(tref);
- n.addDependencyTo(tref.getTagName());
- }
- }
- }
-
- if(generateSwaRefAdapter(p))
- n.useSwaRef = true;
-
- MimeType mimeType = p.getExpectedMimeType();
- if( mimeType != null ) {
- n.useMimeNs = true;
- }
-
- }
-
- // recurse on baseTypes to make sure that we can refer to them in the schema
- ClassInfo<T,C> bc = clazz.getBaseClass();
- if (bc != null) {
- add(bc);
- n.addDependencyTo(bc.getTypeName());
- }
- }
-
- /**
- * Adds a new element to the list of elements to be written.
- */
- public void add( ElementInfo<T,C> elem ) {
- assert elem!=null;
-
- @SuppressWarnings("UnusedAssignment")
- boolean nillable = false; // default value
-
- QName name = elem.getElementName();
- Namespace n = getNamespace(name.getNamespaceURI());
- ElementInfo ei;
-
- if (elem.getScope() != null) { // (probably) never happens
- ei = this.types.getElementInfo(elem.getScope().getClazz(), name);
- } else {
- ei = this.types.getElementInfo(null, name);
- }
-
- XmlElement xmlElem = ei.getProperty().readAnnotation(XmlElement.class);
-
- if (xmlElem == null) {
- nillable = false;
- } else {
- nillable = xmlElem.nillable();
- }
-
- n.elementDecls.put(name.getLocalPart(),n.new ElementWithType(nillable, elem.getContentType()));
-
- // search for foreign namespace references
- n.processForeignNamespaces(elem.getProperty(), 1);
- }
-
- public void add( EnumLeafInfo<T,C> envm ) {
- assert envm!=null;
-
- String nsUri = null;
-
- if(envm.isElement()) {
- // put element -> type reference
- nsUri = envm.getElementName().getNamespaceURI();
- Namespace ns = getNamespace(nsUri);
- ns.enums.add(envm);
- ns.addDependencyTo(envm.getTypeName());
-
- // schedule writing this global element
- add(envm.getElementName(),false,envm);
- }
-
- final QName typeName = envm.getTypeName();
- if (typeName != null) {
- nsUri = typeName.getNamespaceURI();
- } else {
- if(nsUri==null)
- return; // anonymous type
- }
-
- Namespace n = getNamespace(nsUri);
- n.enums.add(envm);
-
- // search for foreign namespace references
- n.addDependencyTo(envm.getBaseType().getTypeName());
- }
-
- public void add( ArrayInfo<T,C> a ) {
- assert a!=null;
-
- final String namespaceURI = a.getTypeName().getNamespaceURI();
- Namespace n = getNamespace(namespaceURI);
- n.arrays.add(a);
-
- // search for foreign namespace references
- n.addDependencyTo(a.getItemType().getTypeName());
- }
-
- /**
- * Adds an additional element declaration.
- *
- * @param tagName
- * The name of the element declaration to be added.
- * @param type
- * The type this element refers to.
- * Can be null, in which case the element refers to an empty anonymous complex type.
- */
- public void add( QName tagName, boolean isNillable, NonElement<T,C> type ) {
-
- if(type!=null && type.getType()==navigator.ref(CompositeStructure.class))
- return; // this is a special class we introduced for JAX-WS that we *don't* want in the schema
-
-
- Namespace n = getNamespace(tagName.getNamespaceURI());
- n.elementDecls.put(tagName.getLocalPart(), n.new ElementWithType(isNillable,type));
-
- // search for foreign namespace references
- if(type!=null)
- n.addDependencyTo(type.getTypeName());
- }
-
- /**
- * Writes out the episode file.
- */
- public void writeEpisodeFile(XmlSerializer out) {
- Bindings root = TXW.create(Bindings.class, out);
-
- if(namespaces.containsKey("")) // otherwise jaxb binding NS should be the default namespace
- root._namespace(WellKnownNamespace.JAXB,"jaxb");
- root.version("2.1");
- // TODO: don't we want to bake in versions?
-
- // generate listing per schema
- for (Map.Entry<String,Namespace> e : namespaces.entrySet()) {
- Bindings group = root.bindings();
-
- String prefix;
- String tns = e.getKey();
- if(!tns.equals("")) {
- group._namespace(tns,"tns");
- prefix = "tns:";
- } else {
- prefix = "";
- }
-
- group.scd("x-schema::"+(tns.equals("")?"":"tns"));
- group.schemaBindings().map(false);
-
- for (ClassInfo<T,C> ci : e.getValue().classes) {
- if(ci.getTypeName()==null) continue; // local type
-
- if(ci.getTypeName().getNamespaceURI().equals(tns)) {
- Bindings child = group.bindings();
- child.scd('~'+prefix+ci.getTypeName().getLocalPart());
- child.klass().ref(ci.getName());
- }
-
- if(ci.isElement() && ci.getElementName().getNamespaceURI().equals(tns)) {
- Bindings child = group.bindings();
- child.scd(prefix+ci.getElementName().getLocalPart());
- child.klass().ref(ci.getName());
- }
- }
-
- for (EnumLeafInfo<T,C> en : e.getValue().enums) {
- if(en.getTypeName()==null) continue; // local type
-
- Bindings child = group.bindings();
- child.scd('~'+prefix+en.getTypeName().getLocalPart());
- child.klass().ref(navigator.getClassName(en.getClazz()));
- }
-
- group.commit(true);
- }
-
- root.commit();
- }
-
- /**
- * Write out the schema documents.
- */
- public void write(SchemaOutputResolver resolver, ErrorListener errorListener) throws IOException {
- if(resolver==null)
- throw new IllegalArgumentException();
-
- if(logger.isLoggable(Level.FINE)) {
- // debug logging to see what's going on.
- logger.log(Level.FINE,"Writing XML Schema for "+toString(),new StackRecorder());
- }
-
- // make it fool-proof
- resolver = new FoolProofResolver(resolver);
- this.errorListener = errorListener;
-
- Map<String, String> schemaLocations = types.getSchemaLocations();
-
- Map<Namespace,Result> out = new HashMap<Namespace,Result>();
- Map<Namespace,String> systemIds = new HashMap<Namespace,String>();
-
- // we create a Namespace object for the XML Schema namespace
- // as a side-effect, but we don't want to generate it.
- namespaces.remove(WellKnownNamespace.XML_SCHEMA);
-
- // first create the outputs for all so that we can resolve references among
- // schema files when we write
- for( Namespace n : namespaces.values() ) {
- String schemaLocation = schemaLocations.get(n.uri);
- if(schemaLocation!=null) {
- systemIds.put(n,schemaLocation);
- } else {
- Result output = resolver.createOutput(n.uri,"schema"+(out.size()+1)+".xsd");
- if(output!=null) { // null result means no schema for that namespace
- out.put(n,output);
- systemIds.put(n,output.getSystemId());
- }
- }
- //Clear the namespace specific set with already written classes
- n.resetWritten();
- }
-
- // then write'em all
- for( Map.Entry<Namespace,Result> e : out.entrySet() ) {
- Result result = e.getValue();
- e.getKey().writeTo( result, systemIds );
- if(result instanceof StreamResult) {
- OutputStream outputStream = ((StreamResult)result).getOutputStream();
- if(outputStream != null) {
- outputStream.close(); // fix for bugid: 6291301
- } else {
- final Writer writer = ((StreamResult)result).getWriter();
- if(writer != null) writer.close();
- }
- }
- }
- }
-
-
-
- /**
- * Schema components are organized per namespace.
- */
- private class Namespace {
- final @NotNull String uri;
-
- /**
- * Other {@link Namespace}s that this namespace depends on.
- */
- private final Set<Namespace> depends = new LinkedHashSet<Namespace>();
-
- /**
- * If this schema refers to components from this schema by itself.
- */
- private boolean selfReference;
-
- /**
- * List of classes in this namespace.
- */
- private final Set<ClassInfo<T,C>> classes = new LinkedHashSet<ClassInfo<T,C>>();
-
- /**
- * Set of enums in this namespace
- */
- private final Set<EnumLeafInfo<T,C>> enums = new LinkedHashSet<EnumLeafInfo<T,C>>();
-
- /**
- * Set of arrays in this namespace
- */
- private final Set<ArrayInfo<T,C>> arrays = new LinkedHashSet<ArrayInfo<T,C>>();
-
- /**
- * Global attribute declarations keyed by their local names.
- */
- private final MultiMap<String,AttributePropertyInfo<T,C>> attributeDecls = new MultiMap<String,AttributePropertyInfo<T,C>>(null);
-
- /**
- * Global element declarations to be written, keyed by their local names.
- */
- private final MultiMap<String,ElementDeclaration> elementDecls =
- new MultiMap<String,ElementDeclaration>(new ElementWithType(true,anyType));
-
- private Form attributeFormDefault;
- private Form elementFormDefault;
-
- /**
- * Does schema in this namespace uses swaRef? If so, we need to generate import
- * statement.
- */
- private boolean useSwaRef;
-
- /**
- * Import for mime namespace needs to be generated.
- * See #856
- */
- private boolean useMimeNs;
-
- /**
- * Container for already processed classes
- */
- private final Set<ClassInfo> written = new HashSet<ClassInfo>();
-
- public Namespace(String uri) {
- this.uri = uri;
- assert !XmlSchemaGenerator.this.namespaces.containsKey(uri);
- XmlSchemaGenerator.this.namespaces.put(uri,this);
- }
-
- /**
- * Clear out the set of already processed classes for this namespace
- */
- void resetWritten() {
- written.clear();
- }
-
- /**
- * Process the given PropertyInfo looking for references to namespaces that
- * are foreign to the given namespace. Any foreign namespace references
- * found are added to the given namespaces dependency list and an &lt;import>
- * is generated for it.
- *
- * @param p the PropertyInfo
- */
- private void processForeignNamespaces(PropertyInfo<T, C> p, int processingDepth) {
- for (TypeInfo<T, C> t : p.ref()) {
- if ((t instanceof ClassInfo) && (processingDepth > 0)) {
- java.util.List<PropertyInfo> l = ((ClassInfo) t).getProperties();
- for (PropertyInfo subp : l) {
- processForeignNamespaces(subp, --processingDepth);
- }
- }
- if (t instanceof Element) {
- addDependencyTo(((Element) t).getElementName());
- }
- if (t instanceof NonElement) {
- addDependencyTo(((NonElement) t).getTypeName());
- }
- }
- }
-
- private void addDependencyTo(@Nullable QName qname) {
- // even though the Element interface says getElementName() returns non-null,
- // ClassInfo always implements Element (even if an instance of ClassInfo might not be an Element).
- // so this check is still necessary
- if (qname==null) {
- return;
- }
-
- String nsUri = qname.getNamespaceURI();
-
- if (nsUri.equals(XML_SCHEMA)) {
- // no need to explicitly refer to XSD namespace
- return;
- }
-
- if (nsUri.equals(uri)) {
- selfReference = true;
- return;
- }
-
- // found a type in a foreign namespace, so make sure we generate an import for it
- depends.add(getNamespace(nsUri));
- }
-
- /**
- * Writes the schema document to the specified result.
- *
- * @param systemIds
- * System IDs of the other schema documents. "" indicates 'implied'.
- */
- private void writeTo(Result result, Map<Namespace,String> systemIds) throws IOException {
- try {
- Schema schema = TXW.create(Schema.class,ResultFactory.createSerializer(result));
-
- // additional namespace declarations to be made.
- Map<String, String> xmlNs = types.getXmlNs(uri);
-
- for (Map.Entry<String, String> e : xmlNs.entrySet()) {
- schema._namespace(e.getValue(),e.getKey());
- }
-
- if(useSwaRef)
- schema._namespace(WellKnownNamespace.SWA_URI,"swaRef");
-
- if(useMimeNs)
- schema._namespace(WellKnownNamespace.XML_MIME_URI,"xmime");
-
- attributeFormDefault = Form.get(types.getAttributeFormDefault(uri));
- attributeFormDefault.declare("attributeFormDefault",schema);
-
- elementFormDefault = Form.get(types.getElementFormDefault(uri));
- // TODO: if elementFormDefault is UNSET, figure out the right default value to use
- elementFormDefault.declare("elementFormDefault",schema);
-
-
- // declare XML Schema namespace to be xs, but allow the user to override it.
- // if 'xs' is used for other things, we'll just let TXW assign a random prefix
- if(!xmlNs.containsValue(WellKnownNamespace.XML_SCHEMA)
- && !xmlNs.containsKey("xs"))
- schema._namespace(WellKnownNamespace.XML_SCHEMA,"xs");
- schema.version("1.0");
-
- if(uri.length()!=0)
- schema.targetNamespace(uri);
-
- // declare prefixes for them at this level, so that we can avoid redundant
- // namespace declarations
- for (Namespace ns : depends) {
- schema._namespace(ns.uri);
- }
-
- if(selfReference && uri.length()!=0) {
- // use common 'tns' prefix for the own namespace
- // if self-reference is needed
- schema._namespace(uri,"tns");
- }
-
- schema._pcdata(newline);
-
- // refer to other schemas
- for( Namespace n : depends ) {
- Import imp = schema._import();
- if(n.uri.length()!=0)
- imp.namespace(n.uri);
- String refSystemId = systemIds.get(n);
- if(refSystemId!=null && !refSystemId.equals("")) {
- // "" means implied. null if the SchemaOutputResolver said "don't generate!"
- imp.schemaLocation(relativize(refSystemId,result.getSystemId()));
- }
- schema._pcdata(newline);
- }
- if(useSwaRef) {
- schema._import().namespace(WellKnownNamespace.SWA_URI).schemaLocation("http://ws-i.org/profiles/basic/1.1/swaref.xsd");
- }
- if(useMimeNs) {
- schema._import().namespace(WellKnownNamespace.XML_MIME_URI).schemaLocation("http://www.w3.org/2005/05/xmlmime");
- }
-
- // then write each component
- for (Map.Entry<String,ElementDeclaration> e : elementDecls.entrySet()) {
- e.getValue().writeTo(e.getKey(),schema);
- schema._pcdata(newline);
- }
- for (ClassInfo<T, C> c : classes) {
- if (c.getTypeName()==null) {
- // don't generate anything if it's an anonymous type
- continue;
- }
- if(uri.equals(c.getTypeName().getNamespaceURI()))
- writeClass(c, schema);
- schema._pcdata(newline);
- }
- for (EnumLeafInfo<T, C> e : enums) {
- if (e.getTypeName()==null) {
- // don't generate anything if it's an anonymous type
- continue;
- }
- if(uri.equals(e.getTypeName().getNamespaceURI()))
- writeEnum(e,schema);
- schema._pcdata(newline);
- }
- for (ArrayInfo<T, C> a : arrays) {
- writeArray(a,schema);
- schema._pcdata(newline);
- }
- for (Map.Entry<String,AttributePropertyInfo<T,C>> e : attributeDecls.entrySet()) {
- TopLevelAttribute a = schema.attribute();
- a.name(e.getKey());
- if(e.getValue()==null)
- writeTypeRef(a,stringType,"type");
- else
- writeAttributeTypeRef(e.getValue(),a);
- schema._pcdata(newline);
- }
-
- // close the schema
- schema.commit();
- } catch( TxwException e ) {
- logger.log(Level.INFO,e.getMessage(),e);
- throw new IOException(e.getMessage());
- }
- }
-
- /**
- * Writes a type attribute (if the referenced type is a global type)
- * or writes out the definition of the anonymous type in place (if the referenced
- * type is not a global type.)
- *
- * Also provides processing for ID/IDREF, MTOM @xmime, and swa:ref
- *
- * ComplexTypeHost and SimpleTypeHost don't share an api for creating
- * and attribute in a type-safe way, so we will compromise for now and
- * use _attribute().
- */
- private void writeTypeRef(TypeHost th, NonElementRef<T, C> typeRef, String refAttName) {
- // ID / IDREF handling
- switch(typeRef.getSource().id()) {
- case ID:
- th._attribute(refAttName, new QName(WellKnownNamespace.XML_SCHEMA, "ID"));
- return;
- case IDREF:
- th._attribute(refAttName, new QName(WellKnownNamespace.XML_SCHEMA, "IDREF"));
- return;
- case NONE:
- // no ID/IDREF, so continue on and generate the type
- break;
- default:
- throw new IllegalStateException();
- }
-
- // MTOM handling
- MimeType mimeType = typeRef.getSource().getExpectedMimeType();
- if( mimeType != null ) {
- th._attribute(new QName(WellKnownNamespace.XML_MIME_URI, "expectedContentTypes", "xmime"), mimeType.toString());
- }
-
- // ref:swaRef handling
- if(generateSwaRefAdapter(typeRef)) {
- th._attribute(refAttName, new QName(WellKnownNamespace.SWA_URI, "swaRef", "ref"));
- return;
- }
-
- // type name override
- if(typeRef.getSource().getSchemaType()!=null) {
- th._attribute(refAttName,typeRef.getSource().getSchemaType());
- return;
- }
-
- // normal type generation
- writeTypeRef(th, typeRef.getTarget(), refAttName);
- }
-
- /**
- * Writes a type attribute (if the referenced type is a global type)
- * or writes out the definition of the anonymous type in place (if the referenced
- * type is not a global type.)
- *
- * @param th
- * the TXW interface to which the attribute will be written.
- * @param type
- * type to be referenced.
- * @param refAttName
- * The name of the attribute used when referencing a type by QName.
- */
- private void writeTypeRef(TypeHost th, NonElement<T,C> type, String refAttName) {
- Element e = null;
- if (type instanceof MaybeElement) {
- MaybeElement me = (MaybeElement)type;
- boolean isElement = me.isElement();
- if (isElement) e = me.asElement();
- }
- if (type instanceof Element) {
- e = (Element)type;
- }
- if (type.getTypeName()==null) {
- if ((e != null) && (e.getElementName() != null)) {
- th.block(); // so that the caller may write other attributes
- if(type instanceof ClassInfo) {
- writeClass( (ClassInfo<T,C>)type, th );
- } else {
- writeEnum( (EnumLeafInfo<T,C>)type, (SimpleTypeHost)th);
- }
- } else {
- // anonymous
- th.block(); // so that the caller may write other attributes
- if(type instanceof ClassInfo) {
- if(collisionChecker.push((ClassInfo<T,C>)type)) {
- errorListener.warning(new SAXParseException(
- Messages.ANONYMOUS_TYPE_CYCLE.format(collisionChecker.getCycleString()),
- null
- ));
- } else {
- writeClass( (ClassInfo<T,C>)type, th );
- }
- collisionChecker.pop();
- } else {
- writeEnum( (EnumLeafInfo<T,C>)type, (SimpleTypeHost)th);
- }
- }
- } else {
- th._attribute(refAttName,type.getTypeName());
- }
- }
-
- /**
- * writes the schema definition for the given array class
- */
- private void writeArray(ArrayInfo<T, C> a, Schema schema) {
- ComplexType ct = schema.complexType().name(a.getTypeName().getLocalPart());
- ct._final("#all");
- LocalElement le = ct.sequence().element().name("item");
- le.type(a.getItemType().getTypeName());
- le.minOccurs(0).maxOccurs("unbounded");
- le.nillable(true);
- ct.commit();
- }
-
- /**
- * writes the schema definition for the specified type-safe enum in the given TypeHost
- */
- private void writeEnum(EnumLeafInfo<T, C> e, SimpleTypeHost th) {
- SimpleType st = th.simpleType();
- writeName(e,st);
-
- SimpleRestrictionModel base = st.restriction();
- writeTypeRef(base, e.getBaseType(), "base");
-
- for (EnumConstant c : e.getConstants()) {
- base.enumeration().value(c.getLexicalValue());
- }
- st.commit();
- }
-
- /**
- * Writes the schema definition for the specified class to the schema writer.
- *
- * @param c the class info
- * @param parent the writer of the parent element into which the type will be defined
- */
- private void writeClass(ClassInfo<T,C> c, TypeHost parent) {
- if (written.contains(c)) { // to avoid cycles let's check if we haven't already processed the class
- return;
- }
- written.add(c);
- // special handling for value properties
- if (containsValueProp(c)) {
- if (c.getProperties().size() == 1) {
- // [RESULT 2 - simpleType if the value prop is the only prop]
- //
- // <simpleType name="foo">
- // <xs:restriction base="xs:int"/>
- // </>
- ValuePropertyInfo<T,C> vp = (ValuePropertyInfo<T,C>)c.getProperties().get(0);
- SimpleType st = ((SimpleTypeHost)parent).simpleType();
- writeName(c, st);
- if(vp.isCollection()) {
- writeTypeRef(st.list(),vp.getTarget(),"itemType");
- } else {
- writeTypeRef(st.restriction(),vp.getTarget(),"base");
- }
- return;
- } else {
- // [RESULT 1 - complexType with simpleContent]
- //
- // <complexType name="foo">
- // <simpleContent>
- // <extension base="xs:int"/>
- // <attribute name="b" type="xs:boolean"/>
- // </>
- // </>
- // </>
- // ...
- // <element name="f" type="foo"/>
- // ...
- ComplexType ct = ((ComplexTypeHost)parent).complexType();
- writeName(c,ct);
- if(c.isFinal())
- ct._final("extension restriction");
-
- SimpleExtension se = ct.simpleContent().extension();
- se.block(); // because we might have attribute before value
- for (PropertyInfo<T,C> p : c.getProperties()) {
- switch (p.kind()) {
- case ATTRIBUTE:
- handleAttributeProp((AttributePropertyInfo<T,C>)p,se);
- break;
- case VALUE:
- TODO.checkSpec("what if vp.isCollection() == true?");
- ValuePropertyInfo vp = (ValuePropertyInfo) p;
- se.base(vp.getTarget().getTypeName());
- break;
- case ELEMENT: // error
- case REFERENCE: // error
- default:
- assert false;
- throw new IllegalStateException();
- }
- }
- se.commit();
- }
- TODO.schemaGenerator("figure out what to do if bc != null");
- TODO.checkSpec("handle sec 8.9.5.2, bullet #4");
- // Java types containing value props can only contain properties of type
- // ValuePropertyinfo and AttributePropertyInfo which have just been handled,
- // so return.
- return;
- }
-
- // we didn't fall into the special case for value props, so we
- // need to initialize the ct.
- // generate the complexType
- ComplexType ct = ((ComplexTypeHost)parent).complexType();
- writeName(c,ct);
- if(c.isFinal())
- ct._final("extension restriction");
- if(c.isAbstract())
- ct._abstract(true);
-
- // these are where we write content model and attributes
- AttrDecls contentModel = ct;
- TypeDefParticle contentModelOwner = ct;
-
- // if there is a base class, we need to generate an extension in the schema
- final ClassInfo<T,C> bc = c.getBaseClass();
- if (bc != null) {
- if(bc.hasValueProperty()) {
- // extending complex type with simple content
- SimpleExtension se = ct.simpleContent().extension();
- contentModel = se;
- contentModelOwner = null;
- se.base(bc.getTypeName());
- } else {
- ComplexExtension ce = ct.complexContent().extension();
- contentModel = ce;
- contentModelOwner = ce;
-
- ce.base(bc.getTypeName());
- // TODO: what if the base type is anonymous?
- }
- }
-
- if(contentModelOwner!=null) {
- // build the tree that represents the explicit content model from iterate over the properties
- ArrayList<Tree> children = new ArrayList<Tree>();
- for (PropertyInfo<T,C> p : c.getProperties()) {
- // handling for <complexType @mixed='true' ...>
- if(p instanceof ReferencePropertyInfo && ((ReferencePropertyInfo)p).isMixed()) {
- ct.mixed(true);
- }
- Tree t = buildPropertyContentModel(p);
- if(t!=null)
- children.add(t);
- }
-
- Tree top = Tree.makeGroup( c.isOrdered() ? GroupKind.SEQUENCE : GroupKind.ALL, children);
-
- // write the content model
- top.write(contentModelOwner);
- }
-
- // then attributes
- for (PropertyInfo<T,C> p : c.getProperties()) {
- if (p instanceof AttributePropertyInfo) {
- handleAttributeProp((AttributePropertyInfo<T,C>)p, contentModel);
- }
- }
- if( c.hasAttributeWildcard()) {
- contentModel.anyAttribute().namespace("##other").processContents("skip");
- }
- ct.commit();
- }
-
- /**
- * Writes the name attribute if it's named.
- */
- private void writeName(NonElement<T,C> c, TypedXmlWriter xw) {
- QName tn = c.getTypeName();
- if(tn!=null)
- xw._attribute("name",tn.getLocalPart()); // named
- }
-
- private boolean containsValueProp(ClassInfo<T, C> c) {
- for (PropertyInfo p : c.getProperties()) {
- if (p instanceof ValuePropertyInfo) return true;
- }
- return false;
- }
-
- /**
- * Builds content model writer for the specified property.
- */
- private Tree buildPropertyContentModel(PropertyInfo<T,C> p) {
- switch(p.kind()) {
- case ELEMENT:
- return handleElementProp((ElementPropertyInfo<T,C>)p);
- case ATTRIBUTE:
- // attribuets are handled later
- return null;
- case REFERENCE:
- return handleReferenceProp((ReferencePropertyInfo<T,C>)p);
- case MAP:
- return handleMapProp((MapPropertyInfo<T,C>)p);
- case VALUE:
- // value props handled above in writeClass()
- assert false;
- throw new IllegalStateException();
- default:
- assert false;
- throw new IllegalStateException();
- }
- }
-
- /**
- * Generate the proper schema fragment for the given element property into the
- * specified schema compositor.
- *
- * The element property may or may not represent a collection and it may or may
- * not be wrapped.
- *
- * @param ep the element property
- */
- private Tree handleElementProp(final ElementPropertyInfo<T,C> ep) {
- if (ep.isValueList()) {
- return new Tree.Term() {
- protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
- TypeRef<T,C> t = ep.getTypes().get(0);
- LocalElement e = parent.element();
- e.block(); // we will write occurs later
- QName tn = t.getTagName();
- e.name(tn.getLocalPart());
- List lst = e.simpleType().list();
- writeTypeRef(lst,t, "itemType");
- elementFormDefault.writeForm(e,tn);
- writeOccurs(e,isOptional||!ep.isRequired(),repeated);
- }
- };
- }
-
- ArrayList<Tree> children = new ArrayList<Tree>();
- for (final TypeRef<T,C> t : ep.getTypes()) {
- children.add(new Tree.Term() {
- protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
- LocalElement e = parent.element();
-
- QName tn = t.getTagName();
-
- PropertyInfo propInfo = t.getSource();
- TypeInfo parentInfo = (propInfo == null) ? null : propInfo.parent();
-
- if (canBeDirectElementRef(t, tn, parentInfo)) {
- if ((!t.getTarget().isSimpleType()) && (t.getTarget() instanceof ClassInfo) && collisionChecker.findDuplicate((ClassInfo<T, C>) t.getTarget())) {
- e.ref(new QName(uri, tn.getLocalPart()));
- } else {
-
- QName elemName = null;
- if (t.getTarget() instanceof Element) {
- Element te = (Element) t.getTarget();
- elemName = te.getElementName();
- }
-
- Collection<TypeInfo> refs = propInfo.ref();
- TypeInfo ti;
- if ((refs != null) && (!refs.isEmpty()) && (elemName != null)
- && ((ti = refs.iterator().next()) == null || ti instanceof ClassInfoImpl)) {
- ClassInfoImpl cImpl = (ClassInfoImpl)ti;
- if ((cImpl != null) && (cImpl.getElementName() != null)) {
- e.ref(new QName(cImpl.getElementName().getNamespaceURI(), tn.getLocalPart()));
- } else {
- e.ref(new QName("", tn.getLocalPart()));
- }
- } else {
- e.ref(tn);
- }
- }
- } else {
- e.name(tn.getLocalPart());
- writeTypeRef(e,t, "type");
- elementFormDefault.writeForm(e,tn);
- }
-
- if (t.isNillable()) {
- e.nillable(true);
- }
- if(t.getDefaultValue()!=null)
- e._default(t.getDefaultValue());
- writeOccurs(e,isOptional,repeated);
- }
- });
- }
-
- final Tree choice = Tree.makeGroup(GroupKind.CHOICE, children)
- .makeOptional(!ep.isRequired())
- .makeRepeated(ep.isCollection()); // see Spec table 8-13
-
-
- final QName ename = ep.getXmlName();
- if (ename != null) { // wrapped collection
- return new Tree.Term() {
- protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
- LocalElement e = parent.element();
- if(ename.getNamespaceURI().length()>0) {
- if (!ename.getNamespaceURI().equals(uri)) {
- // TODO: we need to generate the corresponding element declaration for this
- // table 8-25: Property/field element wrapper with ref attribute
- e.ref(new QName(ename.getNamespaceURI(), ename.getLocalPart()));
- return;
- }
- }
- e.name(ename.getLocalPart());
- elementFormDefault.writeForm(e,ename);
-
- if(ep.isCollectionNillable()) {
- e.nillable(true);
- }
- writeOccurs(e,!ep.isCollectionRequired(),repeated);
-
- ComplexType p = e.complexType();
- choice.write(p);
- }
- };
- } else {// non-wrapped
- return choice;
- }
- }
-
- /**
- * Checks if we can collapse
- * &lt;element name='foo' type='t' /> to &lt;element ref='foo' />.
- *
- * This is possible if we already have such declaration to begin with.
- */
- private boolean canBeDirectElementRef(TypeRef<T, C> t, QName tn, TypeInfo parentInfo) {
- Element te = null;
- ClassInfo ci = null;
- QName targetTagName = null;
-
- if(t.isNillable() || t.getDefaultValue()!=null) {
- // can't put those attributes on <element ref>
- return false;
- }
-
- if (t.getTarget() instanceof Element) {
- te = (Element) t.getTarget();
- targetTagName = te.getElementName();
- if (te instanceof ClassInfo) {
- ci = (ClassInfo)te;
- }
- }
-
- String nsUri = tn.getNamespaceURI();
- if ((!nsUri.equals(uri) && nsUri.length()>0) && (!((parentInfo instanceof ClassInfo) && (((ClassInfo)parentInfo).getTypeName() == null)))) {
- return true;
- }
-
- if ((ci != null) && ((targetTagName != null) && (te.getScope() == null) && (targetTagName.getNamespaceURI() == null))) {
- if (targetTagName.equals(tn)) {
- return true;
- }
- }
-
- // we have the precise element defined already
- if (te != null) { // it is instanceof Element
- return targetTagName!=null && targetTagName.equals(tn);
- }
-
- return false;
- }
-
-
- /**
- * Generate an attribute for the specified property on the specified complexType
- *
- * @param ap the attribute
- * @param attr the schema definition to which the attribute will be added
- */
- private void handleAttributeProp(AttributePropertyInfo<T,C> ap, AttrDecls attr) {
- // attr is either a top-level ComplexType or a ComplexExtension
- //
- // [RESULT]
- //
- // <complexType ...>
- // <...>...</>
- // <attribute name="foo" type="xs:int"/>
- // </>
- //
- // or
- //
- // <complexType ...>
- // <complexContent>
- // <extension ...>
- // <...>...</>
- // </>
- // </>
- // <attribute name="foo" type="xs:int"/>
- // </>
- //
- // or it could also be an in-lined type (attr ref)
- //
- LocalAttribute localAttribute = attr.attribute();
-
- final String attrURI = ap.getXmlName().getNamespaceURI();
- if (attrURI.equals("") /*|| attrURI.equals(uri) --- those are generated as global attributes anyway, so use them.*/) {
- localAttribute.name(ap.getXmlName().getLocalPart());
-
- writeAttributeTypeRef(ap, localAttribute);
-
- attributeFormDefault.writeForm(localAttribute,ap.getXmlName());
- } else { // generate an attr ref
- localAttribute.ref(ap.getXmlName());
- }
-
- if(ap.isRequired()) {
- // TODO: not type safe
- localAttribute.use("required");
- }
- }
-
- private void writeAttributeTypeRef(AttributePropertyInfo<T,C> ap, AttributeType a) {
- if( ap.isCollection() )
- writeTypeRef(a.simpleType().list(), ap, "itemType");
- else
- writeTypeRef(a, ap, "type");
- }
-
- /**
- * Generate the proper schema fragment for the given reference property into the
- * specified schema compositor.
- *
- * The reference property may or may not refer to a collection and it may or may
- * not be wrapped.
- */
- private Tree handleReferenceProp(final ReferencePropertyInfo<T, C> rp) {
- // fill in content model
- ArrayList<Tree> children = new ArrayList<Tree>();
-
- for (final Element<T,C> e : rp.getElements()) {
- children.add(new Tree.Term() {
- protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
- LocalElement eref = parent.element();
-
- boolean local=false;
-
- QName en = e.getElementName();
- if(e.getScope()!=null) {
- // scoped. needs to be inlined
- boolean qualified = en.getNamespaceURI().equals(uri);
- boolean unqualified = en.getNamespaceURI().equals("");
- if(qualified || unqualified) {
- // can be inlined indeed
-
- // write form="..." if necessary
- if(unqualified) {
- if(elementFormDefault.isEffectivelyQualified)
- eref.form("unqualified");
- } else {
- if(!elementFormDefault.isEffectivelyQualified)
- eref.form("qualified");
- }
-
- local = true;
- eref.name(en.getLocalPart());
-
- // write out type reference
- if(e instanceof ClassInfo) {
- writeTypeRef(eref,(ClassInfo<T,C>)e,"type");
- } else {
- writeTypeRef(eref,((ElementInfo<T,C>)e).getContentType(),"type");
- }
- }
- }
- if(!local)
- eref.ref(en);
- writeOccurs(eref,isOptional,repeated);
- }
- });
- }
-
- final WildcardMode wc = rp.getWildcard();
- if( wc != null ) {
- children.add(new Tree.Term() {
- protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
- Any any = parent.any();
- final String pcmode = getProcessContentsModeName(wc);
- if( pcmode != null ) any.processContents(pcmode);
- any.namespace("##other");
- writeOccurs(any,isOptional,repeated);
- }
- });
- }
-
-
- final Tree choice = Tree.makeGroup(GroupKind.CHOICE, children).makeRepeated(rp.isCollection()).makeOptional(!rp.isRequired());
-
- final QName ename = rp.getXmlName();
-
- if (ename != null) { // wrapped
- return new Tree.Term() {
- protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
- LocalElement e = parent.element().name(ename.getLocalPart());
- elementFormDefault.writeForm(e,ename);
- if(rp.isCollectionNillable())
- e.nillable(true);
- writeOccurs(e,true,repeated);
-
- ComplexType p = e.complexType();
- choice.write(p);
- }
- };
- } else { // unwrapped
- return choice;
- }
- }
-
- /**
- * Generate the proper schema fragment for the given map property into the
- * specified schema compositor.
- *
- * @param mp the map property
- */
- private Tree handleMapProp(final MapPropertyInfo<T,C> mp) {
- return new Tree.Term() {
- protected void write(ContentModelContainer parent, boolean isOptional, boolean repeated) {
- QName ename = mp.getXmlName();
-
- LocalElement e = parent.element();
- elementFormDefault.writeForm(e,ename);
- if(mp.isCollectionNillable())
- e.nillable(true);
-
- e = e.name(ename.getLocalPart());
- writeOccurs(e,isOptional,repeated);
- ComplexType p = e.complexType();
-
- // TODO: entry, key, and value are always unqualified. that needs to be fixed, too.
- // TODO: we need to generate the corresponding element declaration, if they are qualified
- e = p.sequence().element();
- e.name("entry").minOccurs(0).maxOccurs("unbounded");
-
- ExplicitGroup seq = e.complexType().sequence();
- writeKeyOrValue(seq, "key", mp.getKeyType());
- writeKeyOrValue(seq, "value", mp.getValueType());
- }
- };
- }
-
- private void writeKeyOrValue(ExplicitGroup seq, String tagName, NonElement<T, C> typeRef) {
- LocalElement key = seq.element().name(tagName);
- key.minOccurs(0);
- writeTypeRef(key, typeRef, "type");
- }
-
- public void addGlobalAttribute(AttributePropertyInfo<T,C> ap) {
- attributeDecls.put( ap.getXmlName().getLocalPart(), ap );
- addDependencyTo(ap.getTarget().getTypeName());
- }
-
- public void addGlobalElement(TypeRef<T,C> tref) {
- elementDecls.put( tref.getTagName().getLocalPart(), new ElementWithType(false,tref.getTarget()) );
- addDependencyTo(tref.getTarget().getTypeName());
- }
-
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder();
- buf.append("[classes=").append(classes);
- buf.append(",elementDecls=").append(elementDecls);
- buf.append(",enums=").append(enums);
- buf.append("]");
- return super.toString();
- }
-
- /**
- * Represents a global element declaration to be written.
- *
- * <p>
- * Because multiple properties can name the same global element even if
- * they have different Java type, the schema generator first needs to
- * walk through the model and decide what to generate for the given
- * element declaration.
- *
- * <p>
- * This class represents what will be written, and its {@link #equals(Object)}
- * method is implemented in such a way that two identical declarations
- * are considered as the same.
- */
- abstract class ElementDeclaration {
- /**
- * Returns true if two {@link ElementDeclaration}s are representing
- * the same schema fragment.
- */
- @Override
- public abstract boolean equals(Object o);
- @Override
- public abstract int hashCode();
-
- /**
- * Generates the declaration.
- */
- public abstract void writeTo(String localName, Schema schema);
- }
-
- /**
- * {@link ElementDeclaration} that refers to a {@link NonElement}.
- */
- class ElementWithType extends ElementDeclaration {
- private final boolean nillable;
- private final NonElement<T,C> type;
-
- public ElementWithType(boolean nillable,NonElement<T, C> type) {
- this.type = type;
- this.nillable = nillable;
- }
-
- public void writeTo(String localName, Schema schema) {
- TopLevelElement e = schema.element().name(localName);
- if(nillable)
- e.nillable(true);
- if (type != null) {
- writeTypeRef(e,type, "type");
- } else {
- e.complexType(); // refer to the nested empty complex type
- }
- e.commit();
- }
-
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- final ElementWithType that = (ElementWithType) o;
- return type.equals(that.type);
- }
-
- public int hashCode() {
- return type.hashCode();
- }
- }
- }
-
- /**
- * Examine the specified element ref and determine if a swaRef attribute needs to be generated
- * @param typeRef
- */
- private boolean generateSwaRefAdapter(NonElementRef<T,C> typeRef) {
- return generateSwaRefAdapter(typeRef.getSource());
- }
-
- /**
- * Examine the specified element ref and determine if a swaRef attribute needs to be generated
- */
- private boolean generateSwaRefAdapter(PropertyInfo<T,C> prop) {
- final Adapter<T,C> adapter = prop.getAdapter();
- if (adapter == null) return false;
- final Object o = navigator.asDecl(SwaRefAdapter.class);
- if (o == null) return false;
- return (o.equals(adapter.adapterType));
- }
-
- /**
- * Debug information of what's in this {@link XmlSchemaGenerator}.
- */
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder();
- for (Namespace ns : namespaces.values()) {
- if(buf.length()>0) buf.append(',');
- buf.append(ns.uri).append('=').append(ns);
- }
- return super.toString()+'['+buf+']';
- }
-
- /**
- * return the string representation of the processContents mode of the
- * give wildcard, or null if it is the schema default "strict"
- *
- */
- private static String getProcessContentsModeName(WildcardMode wc) {
- switch(wc) {
- case LAX:
- case SKIP:
- return wc.name().toLowerCase();
- case STRICT:
- return null;
- default:
- throw new IllegalStateException();
- }
- }
-
-
- /**
- * Relativizes a URI by using another URI (base URI.)
- *
- * <p>
- * For example, {@code relative("http://www.sun.com/abc/def","http://www.sun.com/pqr/stu") => "../abc/def"}
- *
- * <p>
- * This method only works on hierarchical URI's, not opaque URI's (refer to the
- * <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/net/URI.html">java.net.URI</a>
- * javadoc for complete definitions of these terms.
- *
- * <p>
- * This method will not normalize the relative URI.
- *
- * @return the relative URI or the original URI if a relative one could not be computed
- */
- protected static String relativize(String uri, String baseUri) {
- try {
- assert uri!=null;
-
- if(baseUri==null) return uri;
-
- URI theUri = new URI(escapeURI(uri));
- URI theBaseUri = new URI(escapeURI(baseUri));
-
- if (theUri.isOpaque() || theBaseUri.isOpaque())
- return uri;
-
- if (!equalsIgnoreCase(theUri.getScheme(), theBaseUri.getScheme()) ||
- !equal(theUri.getAuthority(), theBaseUri.getAuthority()))
- return uri;
-
- String uriPath = theUri.getPath();
- String basePath = theBaseUri.getPath();
-
- // normalize base path
- if (!basePath.endsWith("/")) {
- basePath = normalizeUriPath(basePath);
- }
-
- if( uriPath.equals(basePath))
- return ".";
-
- String relPath = calculateRelativePath(uriPath, basePath, fixNull(theUri.getScheme()).equals("file"));
-
- if (relPath == null)
- return uri; // recursion found no commonality in the two uris at all
- StringBuilder relUri = new StringBuilder();
- relUri.append(relPath);
- if (theUri.getQuery() != null)
- relUri.append('?').append(theUri.getQuery());
- if (theUri.getFragment() != null)
- relUri.append('#').append(theUri.getFragment());
-
- return relUri.toString();
- } catch (URISyntaxException e) {
- throw new InternalError("Error escaping one of these uris:\n\t"+uri+"\n\t"+baseUri);
- }
- }
-
- private static String fixNull(String s) {
- if(s==null) return "";
- else return s;
- }
-
- private static String calculateRelativePath(String uri, String base, boolean fileUrl) {
- // if this is a file URL (very likely), and if this is on a case-insensitive file system,
- // then treat it accordingly.
- boolean onWindows = File.pathSeparatorChar==';';
-
- if (base == null) {
- return null;
- }
- if ((fileUrl && onWindows && startsWithIgnoreCase(uri,base)) || uri.startsWith(base)) {
- return uri.substring(base.length());
- } else {
- return "../" + calculateRelativePath(uri, getParentUriPath(base), fileUrl);
- }
- }
-
- private static boolean startsWithIgnoreCase(String s, String t) {
- return s.toUpperCase().startsWith(t.toUpperCase());
- }
-
- /**
- * JAX-RPC wants the namespaces to be sorted in the reverse order
- * so that the empty namespace "" comes to the very end. Don't ask me why.
- */
- private static final Comparator<String> NAMESPACE_COMPARATOR = new Comparator<String>() {
- public int compare(String lhs, String rhs) {
- return -lhs.compareTo(rhs);
- }
- };
-
- private static final String newline = "\n";
-}