Source Code Cross Referenced for XmlSchemaGenerator.java in  » 6.0-JDK-Modules-com.sun » xml » com » sun » xml » internal » bind » v2 » schemagen » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules com.sun » xml » com.sun.xml.internal.bind.v2.schemagen 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package com.sun.xml.internal.bind.v2.schemagen;
0027:
0028:        import java.io.IOException;
0029:        import java.io.OutputStream;
0030:        import java.io.Writer;
0031:        import java.net.URI;
0032:        import java.net.URISyntaxException;
0033:        import java.util.Comparator;
0034:        import java.util.HashMap;
0035:        import java.util.LinkedHashSet;
0036:        import java.util.Map;
0037:        import java.util.Set;
0038:        import java.util.TreeMap;
0039:        import java.util.logging.Level;
0040:        import java.util.logging.Logger;
0041:
0042:        import javax.activation.MimeType;
0043:        import javax.xml.bind.SchemaOutputResolver;
0044:        import javax.xml.namespace.QName;
0045:        import javax.xml.transform.Result;
0046:        import javax.xml.transform.stream.StreamResult;
0047:
0048:        import com.sun.istack.internal.Nullable;
0049:        import com.sun.xml.internal.bind.Util;
0050:        import com.sun.xml.internal.bind.api.CompositeStructure;
0051:        import com.sun.xml.internal.bind.v2.TODO;
0052:        import com.sun.xml.internal.bind.v2.WellKnownNamespace;
0053:        import static com.sun.xml.internal.bind.v2.WellKnownNamespace.XML_SCHEMA;
0054:        import com.sun.xml.internal.bind.v2.model.core.Adapter;
0055:        import com.sun.xml.internal.bind.v2.model.core.ArrayInfo;
0056:        import com.sun.xml.internal.bind.v2.model.core.AttributePropertyInfo;
0057:        import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
0058:        import com.sun.xml.internal.bind.v2.model.core.Element;
0059:        import com.sun.xml.internal.bind.v2.model.core.ElementInfo;
0060:        import com.sun.xml.internal.bind.v2.model.core.ElementPropertyInfo;
0061:        import com.sun.xml.internal.bind.v2.model.core.EnumConstant;
0062:        import com.sun.xml.internal.bind.v2.model.core.EnumLeafInfo;
0063:        import com.sun.xml.internal.bind.v2.model.core.MapPropertyInfo;
0064:        import com.sun.xml.internal.bind.v2.model.core.NonElement;
0065:        import com.sun.xml.internal.bind.v2.model.core.NonElementRef;
0066:        import com.sun.xml.internal.bind.v2.model.core.PropertyInfo;
0067:        import com.sun.xml.internal.bind.v2.model.core.ReferencePropertyInfo;
0068:        import com.sun.xml.internal.bind.v2.model.core.TypeInfo;
0069:        import com.sun.xml.internal.bind.v2.model.core.TypeInfoSet;
0070:        import com.sun.xml.internal.bind.v2.model.core.TypeRef;
0071:        import com.sun.xml.internal.bind.v2.model.core.ValuePropertyInfo;
0072:        import com.sun.xml.internal.bind.v2.model.core.WildcardMode;
0073:        import com.sun.xml.internal.bind.v2.model.nav.Navigator;
0074:        import com.sun.xml.internal.bind.v2.runtime.SwaRefAdapter;
0075:        import static com.sun.xml.internal.bind.v2.schemagen.Util.*;
0076:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Any;
0077:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.AttrDecls;
0078:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ComplexExtension;
0079:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ComplexType;
0080:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ComplexTypeHost;
0081:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ExplicitGroup;
0082:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Import;
0083:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.List;
0084:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalAttribute;
0085:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalElement;
0086:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Occurs;
0087:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Schema;
0088:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleExtension;
0089:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleRestrictionModel;
0090:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleType;
0091:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleTypeHost;
0092:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TopLevelAttribute;
0093:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TopLevelElement;
0094:        import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TypeHost;
0095:        import com.sun.xml.internal.txw2.TXW;
0096:        import com.sun.xml.internal.txw2.TxwException;
0097:        import com.sun.xml.internal.txw2.TypedXmlWriter;
0098:        import com.sun.xml.internal.txw2.output.ResultFactory;
0099:
0100:        /**
0101:         * Generates a set of W3C XML Schema documents from a set of Java classes.
0102:         *
0103:         * <p>
0104:         * A client must invoke methods in the following order:
0105:         * <ol>
0106:         *  <li>Create a new {@link XmlSchemaGenerator}
0107:         *  <li>Invoke {@link #add} methods, multiple times if necessary.
0108:         *  <li>Invoke {@link #write}
0109:         *  <li>Discard the {@link XmlSchemaGenerator}.
0110:         * </ol>
0111:         *
0112:         * @author Ryan Shoemaker
0113:         * @author Kohsuke Kawaguchi (kk@kohsuke.org)
0114:         */
0115:        public final class XmlSchemaGenerator<T, C, F, M> {
0116:
0117:            private static final Logger logger = Util.getClassLogger();
0118:
0119:            /**
0120:             * Java classes to be written, organized by their namespace.
0121:             *
0122:             * <p>
0123:             * We use a {@link TreeMap} here so that the suggested names will
0124:             * be consistent across JVMs.
0125:             *
0126:             * @see SchemaOutputResolver#createOutput(String, String)
0127:             */
0128:            private final Map<String, Namespace> namespaces = new TreeMap<String, Namespace>(
0129:                    NAMESPACE_COMPARATOR);
0130:
0131:            /** model navigator **/
0132:            private Navigator<T, C, F, M> navigator;
0133:
0134:            private final TypeInfoSet<T, C, F, M> types;
0135:
0136:            /**
0137:             * Representation for xs:string.
0138:             */
0139:            private final NonElement<T, C> stringType;
0140:
0141:            /**
0142:             * Represents xs:anyType.
0143:             */
0144:            private final NonElement<T, C> anyType;
0145:
0146:            public XmlSchemaGenerator(Navigator<T, C, F, M> navigator,
0147:                    TypeInfoSet<T, C, F, M> types) {
0148:                this .navigator = navigator;
0149:                this .types = types;
0150:
0151:                this .stringType = types
0152:                        .getTypeInfo(navigator.ref(String.class));
0153:                this .anyType = types.getAnyTypeInfo();
0154:
0155:                // populate the object
0156:                for (ClassInfo<T, C> ci : types.beans().values())
0157:                    add(ci);
0158:                for (ElementInfo<T, C> ei1 : types.getElementMappings(null)
0159:                        .values())
0160:                    add(ei1);
0161:                for (EnumLeafInfo<T, C> ei : types.enums().values())
0162:                    add(ei);
0163:                for (ArrayInfo<T, C> a : types.arrays().values())
0164:                    add(a);
0165:            }
0166:
0167:            private Namespace getNamespace(String uri) {
0168:                Namespace n = namespaces.get(uri);
0169:                if (n == null)
0170:                    namespaces.put(uri, n = new Namespace(uri));
0171:                return n;
0172:            }
0173:
0174:            /**
0175:             * Adds a new class to the list of classes to be written.
0176:             *
0177:             * <p>
0178:             * A {@link ClassInfo} may have two namespaces --- one for the element name
0179:             * and the other for the type name. If they are different, we put the same
0180:             * {@link ClassInfo} to two {@link Namespace}s.
0181:             */
0182:            public void add(ClassInfo<T, C> clazz) {
0183:                assert clazz != null;
0184:
0185:                String nsUri = null;
0186:
0187:                if (clazz.getClazz() == navigator
0188:                        .asDecl(CompositeStructure.class))
0189:                    return; // this is a special class we introduced for JAX-WS that we *don't* want in the schema
0190:
0191:                if (clazz.isElement()) {
0192:                    // put element -> type reference
0193:                    nsUri = clazz.getElementName().getNamespaceURI();
0194:                    Namespace ns = getNamespace(nsUri);
0195:                    ns.classes.add(clazz);
0196:                    ns.addDependencyTo(clazz.getTypeName());
0197:
0198:                    // schedule writing this global element
0199:                    add(clazz.getElementName(), false, clazz);
0200:                }
0201:
0202:                QName tn = clazz.getTypeName();
0203:                if (tn != null) {
0204:                    nsUri = tn.getNamespaceURI();
0205:                } else {
0206:                    // anonymous type
0207:                    if (nsUri == null)
0208:                        return;
0209:                }
0210:
0211:                Namespace n = getNamespace(nsUri);
0212:                n.classes.add(clazz);
0213:
0214:                // search properties for foreign namespace references
0215:                for (PropertyInfo<T, C> p : clazz.getProperties()) {
0216:                    n.processForeignNamespaces(p);
0217:                    if (p instanceof  AttributePropertyInfo) {
0218:                        AttributePropertyInfo<T, C> ap = (AttributePropertyInfo<T, C>) p;
0219:                        String aUri = ap.getXmlName().getNamespaceURI();
0220:                        if (aUri.length() > 0) {
0221:                            // global attribute
0222:                            getNamespace(aUri).addGlobalAttribute(ap);
0223:                            n.addDependencyTo(ap.getXmlName());
0224:                        }
0225:                    }
0226:                    if (p instanceof  ElementPropertyInfo) {
0227:                        ElementPropertyInfo<T, C> ep = (ElementPropertyInfo<T, C>) p;
0228:                        for (TypeRef<T, C> tref : ep.getTypes()) {
0229:                            String eUri = tref.getTagName().getNamespaceURI();
0230:                            if (eUri.length() > 0 && !eUri.equals(n.uri)) {
0231:                                getNamespace(eUri).addGlobalElement(tref);
0232:                                n.addDependencyTo(tref.getTagName());
0233:                            }
0234:                        }
0235:                    }
0236:                }
0237:
0238:                // recurse on baseTypes to make sure that we can refer to them in the schema
0239:                ClassInfo<T, C> bc = clazz.getBaseClass();
0240:                if (bc != null)
0241:                    add(bc);
0242:            }
0243:
0244:            /**
0245:             * Adds a new element to the list of elements to be written.
0246:             */
0247:            public void add(ElementInfo<T, C> elem) {
0248:                assert elem != null;
0249:
0250:                QName name = elem.getElementName();
0251:                Namespace n = getNamespace(name.getNamespaceURI());
0252:                n.elementDecls.put(name.getLocalPart(), n.new ElementWithType(
0253:                        true, elem.getContentType()));
0254:
0255:                // search for foreign namespace references
0256:                n.processForeignNamespaces(elem.getProperty());
0257:            }
0258:
0259:            public void add(EnumLeafInfo<T, C> envm) {
0260:                assert envm != null;
0261:
0262:                String nsUri = null;
0263:
0264:                if (envm.isElement()) {
0265:                    // put element -> type reference
0266:                    nsUri = envm.getElementName().getNamespaceURI();
0267:                    Namespace ns = getNamespace(nsUri);
0268:                    ns.enums.add(envm);
0269:                    ns.addDependencyTo(envm.getTypeName());
0270:
0271:                    // schedule writing this global element
0272:                    add(envm.getElementName(), false, envm);
0273:                }
0274:
0275:                final QName typeName = envm.getTypeName();
0276:                if (typeName != null) {
0277:                    nsUri = typeName.getNamespaceURI();
0278:                } else {
0279:                    if (nsUri == null)
0280:                        return; // anonymous type
0281:                }
0282:
0283:                Namespace n = getNamespace(nsUri);
0284:                n.enums.add(envm);
0285:
0286:                // search for foreign namespace references
0287:                n.addDependencyTo(envm.getBaseType().getTypeName());
0288:            }
0289:
0290:            public void add(ArrayInfo<T, C> a) {
0291:                assert a != null;
0292:
0293:                final String namespaceURI = a.getTypeName().getNamespaceURI();
0294:                Namespace n = getNamespace(namespaceURI);
0295:                n.arrays.add(a);
0296:
0297:                // search for foreign namespace references
0298:                n.addDependencyTo(a.getItemType().getTypeName());
0299:            }
0300:
0301:            /**
0302:             * Adds an additional element declaration.
0303:             *
0304:             * @param tagName
0305:             *      The name of the element declaration to be added.
0306:             * @param type
0307:             *      The type this element refers to.
0308:             *      Can be null, in which case the element refers to an empty anonymous complex type.
0309:             */
0310:            public void add(QName tagName, boolean isNillable,
0311:                    NonElement<T, C> type) {
0312:
0313:                if (type != null
0314:                        && type.getType() == navigator
0315:                                .ref(CompositeStructure.class))
0316:                    return; // this is a special class we introduced for JAX-WS that we *don't* want in the schema
0317:
0318:                Namespace n = getNamespace(tagName.getNamespaceURI());
0319:                n.elementDecls.put(tagName.getLocalPart(),
0320:                        n.new ElementWithType(isNillable, type));
0321:
0322:                // search for foreign namespace references
0323:                if (type != null)
0324:                    n.addDependencyTo(type.getTypeName());
0325:            }
0326:
0327:            /**
0328:             * Write out the schema documents.
0329:             */
0330:            public void write(SchemaOutputResolver resolver) throws IOException {
0331:                if (resolver == null)
0332:                    throw new IllegalArgumentException();
0333:
0334:                // make it fool-proof
0335:                resolver = new FoolProofResolver(resolver);
0336:
0337:                Map<Namespace, Result> out = new HashMap<Namespace, Result>();
0338:
0339:                // we create a Namespace object for the XML Schema namespace
0340:                // as a side-effect, but we don't want to generate it.
0341:                namespaces.remove(WellKnownNamespace.XML_SCHEMA);
0342:
0343:                // first create the outputs for all so that we can resolve references among
0344:                // schema files when we write
0345:                for (Namespace n : namespaces.values()) {
0346:                    final Result output = resolver.createOutput(n.uri, "schema"
0347:                            + (out.size() + 1) + ".xsd");
0348:                    if (output != null) { // null result means no schema for that namespace
0349:                        out.put(n, output);
0350:                    }
0351:                }
0352:
0353:                // then write'em all
0354:                for (Namespace n : namespaces.values()) {
0355:                    Result result = out.get(n);
0356:                    if (result != null) {
0357:                        n.writeTo(result, out);
0358:                        if (result instanceof  StreamResult) {
0359:                            OutputStream outputStream = ((StreamResult) result)
0360:                                    .getOutputStream();
0361:                            if (outputStream != null) {
0362:                                outputStream.close(); // fix for bugid: 6291301
0363:                            } else {
0364:                                final Writer writer = ((StreamResult) result)
0365:                                        .getWriter();
0366:                                if (writer != null)
0367:                                    writer.close();
0368:                            }
0369:                        }
0370:                    }
0371:                }
0372:            }
0373:
0374:            /**
0375:             * Schema components are organized per namespace.
0376:             */
0377:            private class Namespace {
0378:                final String uri;
0379:
0380:                /**
0381:                 * Other {@link Namespace}s that this namespace depends on.
0382:                 */
0383:                private final Set<Namespace> depends = new LinkedHashSet<Namespace>();
0384:
0385:                /**
0386:                 * If this schema refers to components from this schema by itself.
0387:                 */
0388:                private boolean selfReference;
0389:
0390:                /**
0391:                 * List of classes in this namespace.
0392:                 */
0393:                private final Set<ClassInfo<T, C>> classes = new LinkedHashSet<ClassInfo<T, C>>();
0394:
0395:                /**
0396:                 * Set of enums in this namespace
0397:                 */
0398:                private final Set<EnumLeafInfo<T, C>> enums = new LinkedHashSet<EnumLeafInfo<T, C>>();
0399:
0400:                /**
0401:                 * Set of arrays in this namespace
0402:                 */
0403:                private final Set<ArrayInfo<T, C>> arrays = new LinkedHashSet<ArrayInfo<T, C>>();
0404:
0405:                /**
0406:                 * Global attribute declarations keyed by their local names.
0407:                 */
0408:                private final MultiMap<String, NonElement<T, C>> attributeDecls = new MultiMap<String, NonElement<T, C>>(
0409:                        stringType);
0410:
0411:                /**
0412:                 * Global element declarations to be written, keyed by their local names.
0413:                 */
0414:                private final MultiMap<String, ElementDeclaration> elementDecls = new MultiMap<String, ElementDeclaration>(
0415:                        new ElementWithType(true, anyType));
0416:
0417:                private Form attributeFormDefault;
0418:                private Form elementFormDefault;
0419:
0420:                public Namespace(String uri) {
0421:                    this .uri = uri;
0422:                    assert !XmlSchemaGenerator.this .namespaces.containsKey(uri);
0423:                    XmlSchemaGenerator.this .namespaces.put(uri, this );
0424:                }
0425:
0426:                /**
0427:                 * Process the given PropertyInfo looking for references to namespaces that
0428:                 * are foreign to the given namespace.  Any foreign namespace references
0429:                 * found are added to the given namespaces dependency list and an &lt;import>
0430:                 * is generated for it.
0431:                 *
0432:                 * @param p the PropertyInfo
0433:                 */
0434:                private void processForeignNamespaces(PropertyInfo<T, C> p) {
0435:                    // TODO: missing the correct handling of anonymous type,
0436:                    // which requires recursive checks
0437:                    for (TypeInfo<T, C> t : p.ref()) {
0438:                        if (t instanceof  Element) {
0439:                            addDependencyTo(((Element) t).getElementName());
0440:                        }
0441:                        if (t instanceof  NonElement) {
0442:                            addDependencyTo(((NonElement) t).getTypeName());
0443:                        }
0444:                    }
0445:                }
0446:
0447:                private void addDependencyTo(@Nullable
0448:                QName qname) {
0449:                    // even though the Element interface says getElementName() returns non-null,
0450:                    // ClassInfo always implements Element (even if an instance of ClassInfo might not be an Element).
0451:                    // so this check is still necessary
0452:                    if (qname == null)
0453:                        return;
0454:
0455:                    String nsUri = qname.getNamespaceURI();
0456:
0457:                    if (nsUri.equals(XML_SCHEMA))
0458:                        // no need to explicitly refer to XSD namespace
0459:                        return;
0460:
0461:                    if (nsUri.equals(uri)) {
0462:                        selfReference = true;
0463:                        return;
0464:                    }
0465:
0466:                    // found a type in a foreign namespace, so make sure we generate an import for it
0467:                    depends.add(getNamespace(nsUri));
0468:                }
0469:
0470:                /**
0471:                 * Writes the schema document to the specified result.
0472:                 */
0473:                private void writeTo(Result result, Map<Namespace, Result> out)
0474:                        throws IOException {
0475:                    try {
0476:                        Schema schema = TXW.create(Schema.class, ResultFactory
0477:                                .createSerializer(result));
0478:
0479:                        // additional namespace declarations to be made.
0480:                        Map<String, String> xmlNs = types.getXmlNs(uri);
0481:
0482:                        for (Map.Entry<String, String> e : xmlNs.entrySet()) {
0483:                            schema._namespace(e.getValue(), e.getKey());
0484:                        }
0485:
0486:                        attributeFormDefault = Form.get(types
0487:                                .getAttributeFormDefault(uri));
0488:                        attributeFormDefault.declare("attributeFormDefault",
0489:                                schema);
0490:
0491:                        elementFormDefault = Form.get(types
0492:                                .getElementFormDefault(uri));
0493:                        // TODO: if elementFormDefault is UNSET, figure out the right default value to use
0494:                        elementFormDefault
0495:                                .declare("elementFormDefault", schema);
0496:
0497:                        // declare XML Schema namespace to be xs, but allow the user to override it.
0498:                        // if 'xs' is used for other things, we'll just let TXW assign a random prefix
0499:                        if (!xmlNs.containsValue(WellKnownNamespace.XML_SCHEMA)
0500:                                && !xmlNs.containsKey("xs"))
0501:                            schema._namespace(WellKnownNamespace.XML_SCHEMA,
0502:                                    "xs");
0503:                        schema.version("1.0");
0504:
0505:                        if (uri.length() != 0)
0506:                            schema.targetNamespace(uri);
0507:
0508:                        // declare prefixes for them at this level, so that we can avoid redundant
0509:                        // namespace declarations
0510:                        for (Namespace ns : depends) {
0511:                            schema._namespace(ns.uri);
0512:                        }
0513:
0514:                        if (selfReference && uri.length() != 0) {
0515:                            // use common 'tns' prefix for the own namespace
0516:                            // if self-reference is needed
0517:                            schema._namespace(uri, "tns");
0518:                        }
0519:
0520:                        schema._pcdata(newline);
0521:
0522:                        // refer to other schemas
0523:                        for (Namespace n : depends) {
0524:                            Import imp = schema._import();
0525:                            if (n.uri.length() != 0)
0526:                                imp.namespace(n.uri);
0527:                            imp.schemaLocation(relativize(out.get(n)
0528:                                    .getSystemId(), result.getSystemId()));
0529:                            schema._pcdata(newline);
0530:                        }
0531:
0532:                        // then write each component
0533:                        for (Map.Entry<String, ElementDeclaration> e : elementDecls
0534:                                .entrySet()) {
0535:                            e.getValue().writeTo(e.getKey(), schema);
0536:                            schema._pcdata(newline);
0537:                        }
0538:                        for (ClassInfo<T, C> c : classes) {
0539:                            if (c.getTypeName() == null) {
0540:                                // don't generate anything if it's an anonymous type
0541:                                continue;
0542:                            }
0543:                            if (uri.equals(c.getTypeName().getNamespaceURI()))
0544:                                writeClass(c, schema);
0545:                            schema._pcdata(newline);
0546:                        }
0547:                        for (EnumLeafInfo<T, C> e : enums) {
0548:                            if (e.getTypeName() == null) {
0549:                                // don't generate anything if it's an anonymous type
0550:                                continue;
0551:                            }
0552:                            if (uri.equals(e.getTypeName().getNamespaceURI()))
0553:                                writeEnum(e, schema);
0554:                            schema._pcdata(newline);
0555:                        }
0556:                        for (ArrayInfo<T, C> a : arrays) {
0557:                            writeArray(a, schema);
0558:                            schema._pcdata(newline);
0559:                        }
0560:                        for (Map.Entry<String, NonElement<T, C>> e : attributeDecls
0561:                                .entrySet()) {
0562:                            TopLevelAttribute a = schema.attribute();
0563:                            a.name(e.getKey());
0564:                            writeTypeRef(a, e.getValue(), "type");
0565:                            schema._pcdata(newline);
0566:                        }
0567:
0568:                        // close the schema
0569:                        schema.commit();
0570:                    } catch (TxwException e) {
0571:                        logger.log(Level.INFO, e.getMessage(), e);
0572:                        throw new IOException(e.getMessage());
0573:                    }
0574:                }
0575:
0576:                /**
0577:                 * Writes a type attribute (if the referenced type is a global type)
0578:                 * or writes out the definition of the anonymous type in place (if the referenced
0579:                 * type is not a global type.)
0580:                 *
0581:                 * Also provides processing for ID/IDREF, MTOM @xmime, and swa:ref
0582:                 *
0583:                 * ComplexTypeHost and SimpleTypeHost don't share an api for creating
0584:                 * and attribute in a type-safe way, so we will compromise for now and
0585:                 * use _attribute().
0586:                 */
0587:                private void writeTypeRef(TypeHost th,
0588:                        NonElementRef<T, C> typeRef, String refAttName) {
0589:                    // ID / IDREF handling
0590:                    switch (typeRef.getSource().id()) {
0591:                    case ID:
0592:                        th._attribute(refAttName, new QName(
0593:                                WellKnownNamespace.XML_SCHEMA, "ID"));
0594:                        return;
0595:                    case IDREF:
0596:                        th._attribute(refAttName, new QName(
0597:                                WellKnownNamespace.XML_SCHEMA, "IDREF"));
0598:                        return;
0599:                    case NONE:
0600:                        // no ID/IDREF, so continue on and generate the type
0601:                        break;
0602:                    default:
0603:                        throw new IllegalStateException();
0604:                    }
0605:
0606:                    // MTOM handling
0607:                    MimeType mimeType = typeRef.getSource()
0608:                            .getExpectedMimeType();
0609:                    if (mimeType != null) {
0610:                        th._attribute(new QName(
0611:                                WellKnownNamespace.XML_MIME_URI,
0612:                                "expectedContentTypes", "xmime"), mimeType
0613:                                .toString());
0614:                    }
0615:
0616:                    // ref:swaRef handling
0617:                    if (generateSwaRefAdapter(typeRef)) {
0618:                        th._attribute(refAttName, new QName(
0619:                                WellKnownNamespace.SWA_URI, "swaRef", "ref"));
0620:                        return;
0621:                    }
0622:
0623:                    // type name override
0624:                    if (typeRef.getSource().getSchemaType() != null) {
0625:                        th._attribute(refAttName, typeRef.getSource()
0626:                                .getSchemaType());
0627:                        return;
0628:                    }
0629:
0630:                    // normal type generation
0631:                    writeTypeRef(th, typeRef.getTarget(), refAttName);
0632:                }
0633:
0634:                /**
0635:                 * Examine the specified element ref and determine if a swaRef attribute needs to be generated
0636:                 * @param typeRef
0637:                 */
0638:                private boolean generateSwaRefAdapter(
0639:                        NonElementRef<T, C> typeRef) {
0640:                    final Adapter<T, C> adapter = typeRef.getSource()
0641:                            .getAdapter();
0642:                    if (adapter == null)
0643:                        return false;
0644:                    final Object o = navigator.asDecl(SwaRefAdapter.class);
0645:                    if (o == null)
0646:                        return false;
0647:                    return (o.equals(adapter.adapterType));
0648:                }
0649:
0650:                /**
0651:                 * Writes a type attribute (if the referenced type is a global type)
0652:                 * or writes out the definition of the anonymous type in place (if the referenced
0653:                 * type is not a global type.)
0654:                 *
0655:                 * @param th
0656:                 *      the TXW interface to which the attribute will be written.
0657:                 * @param type
0658:                 *      type to be referenced.
0659:                 * @param refAttName
0660:                 *      The name of the attribute used when referencing a type by QName.
0661:                 */
0662:                private void writeTypeRef(TypeHost th, NonElement<T, C> type,
0663:                        String refAttName) {
0664:                    if (type.getTypeName() == null) {
0665:                        if (type instanceof  ClassInfo) {
0666:                            writeClass((ClassInfo<T, C>) type, th);
0667:                        } else {
0668:                            writeEnum((EnumLeafInfo<T, C>) type,
0669:                                    (SimpleTypeHost) th);
0670:                        }
0671:                    } else {
0672:                        th._attribute(refAttName, type.getTypeName());
0673:                    }
0674:                }
0675:
0676:                /**
0677:                 * writes the schema definition for the given array class
0678:                 */
0679:                private void writeArray(ArrayInfo<T, C> a, Schema schema) {
0680:                    ComplexType ct = schema.complexType().name(
0681:                            a.getTypeName().getLocalPart());
0682:                    ct._final("#all");
0683:                    LocalElement le = ct.sequence().element().name("item");
0684:                    le.type(a.getItemType().getTypeName());
0685:                    le.minOccurs(0).maxOccurs("unbounded");
0686:                    le.nillable(true);
0687:                    ct.commit();
0688:                }
0689:
0690:                /**
0691:                 * writes the schema definition for the specified type-safe enum in the given TypeHost
0692:                 */
0693:                private void writeEnum(EnumLeafInfo<T, C> e, SimpleTypeHost th) {
0694:                    SimpleType st = th.simpleType();
0695:                    writeName(e, st);
0696:
0697:                    SimpleRestrictionModel base = st.restriction();
0698:                    writeTypeRef(base, e.getBaseType(), "base");
0699:
0700:                    for (EnumConstant c : e.getConstants()) {
0701:                        base.enumeration().value(c.getLexicalValue());
0702:                    }
0703:                    st.commit();
0704:                }
0705:
0706:                /**
0707:                 * Writes the schema definition for the specified class to the schema writer.
0708:                 *
0709:                 * @param c the class info
0710:                 * @param parent the writer of the parent element into which the type will be defined
0711:                 */
0712:                private void writeClass(ClassInfo<T, C> c, TypeHost parent) {
0713:                    // special handling for value properties
0714:                    if (containsValueProp(c)) {
0715:                        if (c.getProperties().size() == 1) {
0716:                            // [RESULT 2 - simpleType if the value prop is the only prop]
0717:                            //
0718:                            // <simpleType name="foo">
0719:                            //   <xs:restriction base="xs:int"/>
0720:                            // </>
0721:                            ValuePropertyInfo<T, C> vp = (ValuePropertyInfo<T, C>) c
0722:                                    .getProperties().get(0);
0723:                            SimpleType st = ((SimpleTypeHost) parent)
0724:                                    .simpleType();
0725:                            writeName(c, st);
0726:                            if (vp.isCollection()) {
0727:                                writeTypeRef(st.list(), vp.getTarget(),
0728:                                        "itemType");
0729:                            } else {
0730:                                writeTypeRef(st.restriction(), vp.getTarget(),
0731:                                        "base");
0732:                            }
0733:                            return;
0734:                        } else {
0735:                            // [RESULT 1 - complexType with simpleContent]
0736:                            //
0737:                            // <complexType name="foo">
0738:                            //   <simpleContent>
0739:                            //     <extension base="xs:int"/>
0740:                            //       <attribute name="b" type="xs:boolean"/>
0741:                            //     </>
0742:                            //   </>
0743:                            // </>
0744:                            // ...
0745:                            //   <element name="f" type="foo"/>
0746:                            // ...
0747:                            ComplexType ct = ((ComplexTypeHost) parent)
0748:                                    .complexType();
0749:                            writeName(c, ct);
0750:                            if (c.isFinal())
0751:                                ct._final("extension restriction");
0752:
0753:                            SimpleExtension se = ct.simpleContent().extension();
0754:                            se.block(); // because we might have attribute before value
0755:                            for (PropertyInfo<T, C> p : c.getProperties()) {
0756:                                switch (p.kind()) {
0757:                                case ATTRIBUTE:
0758:                                    handleAttributeProp(
0759:                                            (AttributePropertyInfo<T, C>) p, se);
0760:                                    break;
0761:                                case VALUE:
0762:                                    TODO
0763:                                            .checkSpec("what if vp.isCollection() == true?");
0764:                                    ValuePropertyInfo vp = (ValuePropertyInfo) p;
0765:                                    se.base(vp.getTarget().getTypeName());
0766:                                    break;
0767:                                case ELEMENT: // error
0768:                                case REFERENCE: // error
0769:                                default:
0770:                                    assert false;
0771:                                    throw new IllegalStateException();
0772:                                }
0773:                            }
0774:                            se.commit();
0775:                        }
0776:                        TODO
0777:                                .schemaGenerator("figure out what to do if bc != null");
0778:                        TODO.checkSpec("handle sec 8.9.5.2, bullet #4");
0779:                        // Java types containing value props can only contain properties of type
0780:                        // ValuePropertyinfo and AttributePropertyInfo which have just been handled,
0781:                        // so return.
0782:                        return;
0783:                    }
0784:
0785:                    // we didn't fall into the special case for value props, so we
0786:                    // need to initialize the ct.
0787:                    // generate the complexType
0788:                    ComplexType ct = ((ComplexTypeHost) parent).complexType();
0789:                    writeName(c, ct);
0790:                    if (c.isFinal())
0791:                        ct._final("extension restriction");
0792:                    if (c.isAbstract())
0793:                        ct._abstract(true);
0794:
0795:                    // hold the ct open in case we need to generate @mixed below...
0796:                    ct.block();
0797:
0798:                    // either <sequence> or <all>
0799:                    ExplicitGroup compositor = null;
0800:
0801:                    // only necessary if this type has a base class we need to extend from
0802:                    AttrDecls contentModel = ct;
0803:
0804:                    // if there is a base class, we need to generate an extension in the schema
0805:                    final ClassInfo<T, C> bc = c.getBaseClass();
0806:                    if (bc != null) {
0807:                        ComplexExtension ce = ct.complexContent().extension();
0808:                        contentModel = ce;
0809:
0810:                        ce.base(bc.getTypeName());
0811:                        // TODO: what if the base type is anonymous?
0812:                        // ordered props go in a sequence, unordered go in an all
0813:                        if (c.isOrdered()) {
0814:                            compositor = ce.sequence();
0815:                        } else {
0816:                            compositor = ce.all();
0817:                        }
0818:                    }
0819:
0820:                    // iterate over the properties
0821:                    if (c.hasProperties()) {
0822:                        if (compositor == null) { // if there is no extension base, create a top level seq
0823:                            // ordered props go in a sequence, unordered go in an all
0824:                            if (c.isOrdered()) {
0825:                                compositor = ct.sequence();
0826:                            } else {
0827:                                compositor = ct.all();
0828:                            }
0829:                        }
0830:
0831:                        // block writing the compositor because we might need to
0832:                        // write some out of order attributes to handle min/maxOccurs
0833:                        compositor.block();
0834:
0835:                        for (PropertyInfo<T, C> p : c.getProperties()) {
0836:                            // handling for <complexType @mixed='true' ...>
0837:                            if (p instanceof  ReferencePropertyInfo
0838:                                    && ((ReferencePropertyInfo) p).isMixed()) {
0839:                                ct.mixed(true);
0840:                            }
0841:                            writeProperty(p, contentModel, compositor);
0842:                        }
0843:
0844:                        compositor.commit();
0845:                    }
0846:
0847:                    // look for wildcard attributes
0848:                    if (c.hasAttributeWildcard()) {
0849:                        // TODO: not type safe
0850:                        contentModel.anyAttribute().namespace("##other")
0851:                                .processContents("skip");
0852:                    }
0853:
0854:                    // finally commit the ct
0855:                    ct.commit();
0856:                }
0857:
0858:                /**
0859:                 * Writes the name attribute if it's named.
0860:                 */
0861:                private void writeName(NonElement<T, C> c, TypedXmlWriter xw) {
0862:                    QName tn = c.getTypeName();
0863:                    if (tn != null)
0864:                        xw._attribute("name", tn.getLocalPart()); // named
0865:                }
0866:
0867:                private boolean containsValueProp(ClassInfo<T, C> c) {
0868:                    for (PropertyInfo p : c.getProperties()) {
0869:                        if (p instanceof  ValuePropertyInfo)
0870:                            return true;
0871:                    }
0872:                    return false;
0873:                }
0874:
0875:                /**
0876:                 * write the schema definition(s) for the specified property
0877:                 */
0878:                private void writeProperty(PropertyInfo<T, C> p,
0879:                        AttrDecls attr, ExplicitGroup compositor) {
0880:                    switch (p.kind()) {
0881:                    case ELEMENT:
0882:                        handleElementProp((ElementPropertyInfo<T, C>) p,
0883:                                compositor);
0884:                        break;
0885:                    case ATTRIBUTE:
0886:                        handleAttributeProp((AttributePropertyInfo<T, C>) p,
0887:                                attr);
0888:                        break;
0889:                    case REFERENCE:
0890:                        handleReferenceProp((ReferencePropertyInfo<T, C>) p,
0891:                                compositor);
0892:                        break;
0893:                    case MAP:
0894:                        handleMapProp((MapPropertyInfo<T, C>) p, compositor);
0895:                        break;
0896:                    case VALUE:
0897:                        // value props handled above in writeClass()
0898:                        assert false;
0899:                        throw new IllegalStateException();
0900:                        // break();
0901:                    default:
0902:                        assert false;
0903:                        throw new IllegalStateException();
0904:                    }
0905:                }
0906:
0907:                /**
0908:                 * Generate the proper schema fragment for the given element property into the
0909:                 * specified schema compositor.
0910:                 *
0911:                 * The element property may or may not represent a collection and it may or may
0912:                 * not be wrapped.
0913:                 *
0914:                 * @param ep the element property
0915:                 * @param compositor the schema compositor (sequence or all)
0916:                 */
0917:                private void handleElementProp(ElementPropertyInfo<T, C> ep,
0918:                        ExplicitGroup compositor) {
0919:                    QName ename = ep.getXmlName();
0920:                    Occurs occurs = null;
0921:
0922:                    if (ep.isValueList()) {
0923:                        TypeRef<T, C> t = ep.getTypes().get(0);
0924:                        LocalElement e = compositor.element();
0925:
0926:                        QName tn = t.getTagName();
0927:                        e.name(tn.getLocalPart());
0928:                        List lst = e.simpleType().list();
0929:                        writeTypeRef(lst, t, "itemType");
0930:                        elementFormDefault.writeForm(e, tn);
0931:                        return;
0932:                    }
0933:
0934:                    if (ep.isCollection()) {
0935:                        if (ename != null) { // wrapped collection
0936:                            LocalElement e = compositor.element();
0937:                            if (ename.getNamespaceURI().length() > 0) {
0938:                                if (!ename.getNamespaceURI().equals(this .uri)) {
0939:                                    // TODO: we need to generate the corresponding element declaration for this
0940:                                    // table 8-25: Property/field element wrapper with ref attribute
0941:                                    e.ref(new QName(ename.getNamespaceURI(),
0942:                                            ename.getLocalPart()));
0943:                                    return;
0944:                                }
0945:                            }
0946:                            elementFormDefault.writeForm(e, ename);
0947:
0948:                            ComplexType p = e.name(ename.getLocalPart())
0949:                                    .complexType();
0950:                            if (ep.isCollectionNillable()) {
0951:                                e.nillable(true);
0952:                            } else {
0953:                                e.minOccurs(0);
0954:                            }
0955:                            if (ep.getTypes().size() == 1) {
0956:                                compositor = p.sequence();
0957:                            } else {
0958:                                compositor = p.choice();
0959:                                occurs = compositor;
0960:                            }
0961:                        } else { // unwrapped collection
0962:                            if (ep.getTypes().size() > 1) {
0963:                                compositor = compositor.choice();
0964:                                occurs = compositor;
0965:                            }
0966:                        }
0967:                    } else {
0968:                        if (ep.getTypes().size() > 1) {
0969:                            compositor = compositor.choice();
0970:                            occurs = compositor;
0971:                        }
0972:                    }
0973:
0974:                    // fill in the content model
0975:                    for (TypeRef<T, C> t : ep.getTypes()) {
0976:                        LocalElement e = compositor.element();
0977:                        if (occurs == null)
0978:                            occurs = e;
0979:                        QName tn = t.getTagName();
0980:
0981:                        if (canBeDirectElementRef(t, tn)
0982:                                || (!tn.getNamespaceURI().equals(uri) && tn
0983:                                        .getNamespaceURI().length() > 0)) {
0984:                            e.ref(tn);
0985:                        } else {
0986:                            e.name(tn.getLocalPart());
0987:                            writeTypeRef(e, t, "type");
0988:                            elementFormDefault.writeForm(e, tn);
0989:                        }
0990:
0991:                        if (t.isNillable()) {
0992:                            e.nillable(true);
0993:                        }
0994:                        if (t.getDefaultValue() != null)
0995:                            e._default(t.getDefaultValue());
0996:                    }
0997:
0998:                    if (ep.isCollection())
0999:                        occurs.maxOccurs("unbounded");
1000:
1001:                    if (!ep.isRequired())
1002:                        // see Spec table 8-13
1003:                        occurs.minOccurs(0);
1004:                    // else minOccurs defaults to 1
1005:                }
1006:
1007:                /**
1008:                 * Checks if we can collapse
1009:                 * &lt;element name='foo' type='t' /> to &lt;element ref='foo' />.
1010:                 *
1011:                 * This is possible if we already have such declaration to begin with.
1012:                 */
1013:                private boolean canBeDirectElementRef(TypeRef<T, C> t, QName tn) {
1014:                    if (t.isNillable() || t.getDefaultValue() != null)
1015:                        // can't put those attributes on <element ref>
1016:                        return false;
1017:
1018:                    if (t.getTarget() instanceof  Element) {
1019:                        Element te = (Element) t.getTarget();
1020:                        QName targetTagName = te.getElementName();
1021:                        return targetTagName != null
1022:                                && targetTagName.equals(tn);
1023:                    }
1024:
1025:                    return false;
1026:                }
1027:
1028:                /**
1029:                 * Generate an attribute for the specified property on the specified complexType
1030:                 *
1031:                 * @param ap the attribute
1032:                 * @param attr the schema definition to which the attribute will be added
1033:                 */
1034:                private void handleAttributeProp(
1035:                        AttributePropertyInfo<T, C> ap, AttrDecls attr) {
1036:                    // attr is either a top-level ComplexType or a ComplexExtension
1037:                    //
1038:                    // [RESULT]
1039:                    //
1040:                    // <complexType ...>
1041:                    //   <...>...</>
1042:                    //   <attribute name="foo" type="xs:int"/>
1043:                    // </>
1044:                    //
1045:                    // or
1046:                    //
1047:                    // <complexType ...>
1048:                    //   <complexContent>
1049:                    //     <extension ...>
1050:                    //       <...>...</>
1051:                    //     </>
1052:                    //   </>
1053:                    //   <attribute name="foo" type="xs:int"/>
1054:                    // </>
1055:                    //
1056:                    // or it could also be an in-lined type (attr ref)
1057:                    //
1058:                    LocalAttribute localAttribute = attr.attribute();
1059:
1060:                    final String attrURI = ap.getXmlName().getNamespaceURI();
1061:                    if (attrURI.equals("") || attrURI.equals(uri)) {
1062:                        localAttribute.name(ap.getXmlName().getLocalPart());
1063:
1064:                        TypeHost th;
1065:                        String refAtt;
1066:                        if (ap.isCollection()) {
1067:                            th = localAttribute.simpleType().list();
1068:                            refAtt = "itemType";
1069:                        } else {
1070:                            th = localAttribute;
1071:                            refAtt = "type";
1072:                        }
1073:                        writeTypeRef(th, ap, refAtt);
1074:
1075:                        attributeFormDefault.writeForm(localAttribute, ap
1076:                                .getXmlName());
1077:                    } else { // generate an attr ref
1078:                        localAttribute.ref(ap.getXmlName());
1079:                    }
1080:
1081:                    if (ap.isRequired()) {
1082:                        // TODO: not type safe
1083:                        localAttribute.use("required");
1084:                    }
1085:                }
1086:
1087:                /**
1088:                 * Generate the proper schema fragment for the given reference property into the
1089:                 * specified schema compositor.
1090:                 *
1091:                 * The reference property may or may not refer to a collection and it may or may
1092:                 * not be wrapped.
1093:                 *
1094:                 * @param rp
1095:                 * @param compositor
1096:                 */
1097:                private void handleReferenceProp(
1098:                        ReferencePropertyInfo<T, C> rp, ExplicitGroup compositor) {
1099:                    QName ename = rp.getXmlName();
1100:                    Occurs occurs = null;
1101:
1102:                    if (rp.isCollection()) {
1103:                        if (ename != null) { // wrapped collection
1104:                            LocalElement e = compositor.element();
1105:                            ComplexType p = e.name(ename.getLocalPart())
1106:                                    .complexType();
1107:                            elementFormDefault.writeForm(e, ename);
1108:                            if (rp.isCollectionNillable())
1109:                                e.nillable(true);
1110:                            if (rp.getElements().size() == 1) {
1111:                                compositor = p.sequence();
1112:                            } else {
1113:                                compositor = p.choice();
1114:                                occurs = compositor;
1115:                            }
1116:                        } else { // unwrapped collection
1117:                            if (rp.getElements().size() > 1) {
1118:                                compositor = compositor.choice();
1119:                                occurs = compositor;
1120:                            }
1121:                        }
1122:                    }
1123:
1124:                    // fill in content model
1125:                    TODO
1126:                            .checkSpec("should we loop in the case of a non-collection ep?");
1127:                    for (Element<T, C> e : rp.getElements()) {
1128:                        LocalElement eref = compositor.element();
1129:                        if (occurs == null)
1130:                            occurs = eref;
1131:
1132:                        QName en = e.getElementName();
1133:                        if (e.getScope() != null) {
1134:                            // scoped. needs to be inlined
1135:                            boolean qualified = en.getNamespaceURI()
1136:                                    .equals(uri);
1137:                            boolean unqualified = en.getNamespaceURI().equals(
1138:                                    "");
1139:                            if (qualified || unqualified) {
1140:                                // can be inlined indeed
1141:
1142:                                // write form="..." if necessary
1143:                                if (unqualified) {
1144:                                    if (elementFormDefault.isEffectivelyQualified)
1145:                                        eref.form("unqualified");
1146:                                } else {
1147:                                    if (!elementFormDefault.isEffectivelyQualified)
1148:                                        eref.form("qualified");
1149:                                }
1150:
1151:                                eref.name(en.getLocalPart());
1152:
1153:                                // write out type reference
1154:                                if (e instanceof  ClassInfo) {
1155:                                    writeTypeRef(eref, (ClassInfo<T, C>) e,
1156:                                            "type");
1157:                                } else {
1158:                                    writeTypeRef(eref, ((ElementInfo<T, C>) e)
1159:                                            .getContentType(), "type");
1160:                                }
1161:                                continue;
1162:                            }
1163:                        }
1164:                        eref.ref(en);
1165:                    }
1166:
1167:                    WildcardMode wc = rp.getWildcard();
1168:                    if (wc != null) {
1169:                        Any any = compositor.any();
1170:                        final String pcmode = getProcessContentsModeName(wc);
1171:                        if (pcmode != null)
1172:                            any.processContents(pcmode);
1173:                        TODO.schemaGenerator("generate @namespace ???");
1174:                        if (occurs == null)
1175:                            occurs = any;
1176:                    }
1177:
1178:                    if (rp.isCollection())
1179:                        occurs.maxOccurs("unbounded");
1180:
1181:                }
1182:
1183:                /**
1184:                 * Generate the proper schema fragment for the given map property into the
1185:                 * specified schema compositor.
1186:                 *
1187:                 * @param mp the map property
1188:                 * @param compositor the schema compositor (sequence or all)
1189:                 */
1190:                private void handleMapProp(MapPropertyInfo<T, C> mp,
1191:                        ExplicitGroup compositor) {
1192:                    QName ename = mp.getXmlName();
1193:
1194:                    LocalElement e = compositor.element();
1195:                    elementFormDefault.writeForm(e, ename);
1196:                    if (mp.isCollectionNillable())
1197:                        e.nillable(true);
1198:                    ComplexType p = e.name(ename.getLocalPart()).complexType();
1199:
1200:                    // TODO: entry, key, and value are always unqualified. that needs to be fixed, too.
1201:                    // TODO: we need to generate the corresponding element declaration, if they are qualified
1202:                    e = p.sequence().element();
1203:                    e.name("entry").minOccurs(0).maxOccurs("unbounded");
1204:
1205:                    ExplicitGroup seq = e.complexType().sequence();
1206:                    writeKeyOrValue(seq, "key", mp.getKeyType());
1207:                    writeKeyOrValue(seq, "value", mp.getValueType());
1208:                }
1209:
1210:                private void writeKeyOrValue(ExplicitGroup seq, String tagName,
1211:                        NonElement<T, C> typeRef) {
1212:                    LocalElement key = seq.element().name(tagName);
1213:                    key.minOccurs(0);
1214:                    writeTypeRef(key, typeRef, "type");
1215:                }
1216:
1217:                public void addGlobalAttribute(AttributePropertyInfo<T, C> ap) {
1218:                    attributeDecls.put(ap.getXmlName().getLocalPart(), ap
1219:                            .getTarget());
1220:                    addDependencyTo(ap.getTarget().getTypeName());
1221:                }
1222:
1223:                public void addGlobalElement(TypeRef<T, C> tref) {
1224:                    elementDecls.put(tref.getTagName().getLocalPart(),
1225:                            new ElementWithType(false, tref.getTarget()));
1226:                    addDependencyTo(tref.getTarget().getTypeName());
1227:                }
1228:
1229:                /**
1230:                 * Represents a global element declaration to be written.
1231:                 *
1232:                 * <p>
1233:                 * Because multiple properties can name the same global element even if
1234:                 * they have different Java type, the schema generator first needs to
1235:                 * walk through the model and decide what to generate for the given
1236:                 * element declaration.
1237:                 *
1238:                 * <p>
1239:                 * This class represents what will be written, and its {@link #equals(Object)}
1240:                 * method is implemented in such a way that two identical declarations
1241:                 * are considered as the same.
1242:                 */
1243:                abstract class ElementDeclaration {
1244:                    /**
1245:                     * Returns true if two {@link ElementDeclaration}s are representing
1246:                     * the same schema fragment.
1247:                     */
1248:                    public abstract boolean equals(Object o);
1249:
1250:                    public abstract int hashCode();
1251:
1252:                    /**
1253:                     * Generates the declaration.
1254:                     */
1255:                    public abstract void writeTo(String localName, Schema schema);
1256:                }
1257:
1258:                /**
1259:                 * {@link ElementDeclaration} that refers to a {@link NonElement}.
1260:                 */
1261:                class ElementWithType extends ElementDeclaration {
1262:                    private final boolean nillable;
1263:                    private final NonElement<T, C> type;
1264:
1265:                    public ElementWithType(boolean nillable,
1266:                            NonElement<T, C> type) {
1267:                        this .type = type;
1268:                        this .nillable = nillable;
1269:                    }
1270:
1271:                    public void writeTo(String localName, Schema schema) {
1272:                        TopLevelElement e = schema.element().name(localName);
1273:                        if (nillable)
1274:                            e.nillable(true);
1275:                        if (type != null) {
1276:                            writeTypeRef(e, type, "type");
1277:                        } else {
1278:                            e.complexType(); // refer to the nested empty complex type
1279:                        }
1280:                        e.commit();
1281:                    }
1282:
1283:                    public boolean equals(Object o) {
1284:                        if (this  == o)
1285:                            return true;
1286:                        if (o == null || getClass() != o.getClass())
1287:                            return false;
1288:
1289:                        final ElementWithType that = (ElementWithType) o;
1290:                        return type.equals(that.type);
1291:                    }
1292:
1293:                    public int hashCode() {
1294:                        return type.hashCode();
1295:                    }
1296:                }
1297:            }
1298:
1299:            /**
1300:             * return the string representation of the processContents mode of the
1301:             * give wildcard, or null if it is the schema default "strict"
1302:             *
1303:             */
1304:            private static String getProcessContentsModeName(WildcardMode wc) {
1305:                switch (wc) {
1306:                case LAX:
1307:                case SKIP:
1308:                    return wc.name().toLowerCase();
1309:                case STRICT:
1310:                    return null;
1311:                default:
1312:                    throw new IllegalStateException();
1313:                }
1314:            }
1315:
1316:            /**
1317:             * TODO: JAX-WS dependency on this method - consider moving this method into com.sun.tools.internal.jxc.util.Util
1318:             * 
1319:             * Relativizes a URI by using another URI (base URI.)
1320:             *
1321:             * <p>
1322:             * For example, {@code relative("http://www.sun.com/abc/def","http://www.sun.com/pqr/stu") => "../abc/def"}
1323:             *
1324:             * <p>
1325:             * This method only works on hierarchical URI's, not opaque URI's (refer to the
1326:             * <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/net/URI.html">java.net.URI</a>
1327:             * javadoc for complete definitions of these terms.
1328:             *
1329:             * <p>
1330:             * This method will not normalize the relative URI.
1331:             *
1332:             * @return the relative URI or the original URI if a relative one could not be computed
1333:             */
1334:            protected static String relativize(String uri, String baseUri) {
1335:                try {
1336:                    assert uri != null;
1337:
1338:                    if (baseUri == null)
1339:                        return uri;
1340:
1341:                    URI theUri = new URI(escapeURI(uri));
1342:                    URI theBaseUri = new URI(escapeURI(baseUri));
1343:
1344:                    if (theUri.isOpaque() || theBaseUri.isOpaque())
1345:                        return uri;
1346:
1347:                    if (!equalsIgnoreCase(theUri.getScheme(), theBaseUri
1348:                            .getScheme())
1349:                            || !equal(theUri.getAuthority(), theBaseUri
1350:                                    .getAuthority()))
1351:                        return uri;
1352:
1353:                    String uriPath = theUri.getPath();
1354:                    String basePath = theBaseUri.getPath();
1355:
1356:                    // normalize base path
1357:                    if (!basePath.endsWith("/")) {
1358:                        basePath = normalizeUriPath(basePath);
1359:                    }
1360:
1361:                    if (uriPath.equals(basePath))
1362:                        return ".";
1363:
1364:                    String relPath = calculateRelativePath(uriPath, basePath);
1365:
1366:                    if (relPath == null)
1367:                        return uri; // recursion found no commonality in the two uris at all
1368:                    StringBuffer relUri = new StringBuffer();
1369:                    relUri.append(relPath);
1370:                    if (theUri.getQuery() != null)
1371:                        relUri.append('?').append(theUri.getQuery());
1372:                    if (theUri.getFragment() != null)
1373:                        relUri.append('#').append(theUri.getFragment());
1374:
1375:                    return relUri.toString();
1376:                } catch (URISyntaxException e) {
1377:                    throw new InternalError(
1378:                            "Error escaping one of these uris:\n\t" + uri
1379:                                    + "\n\t" + baseUri);
1380:                }
1381:            }
1382:
1383:            private static String calculateRelativePath(String uri, String base) {
1384:                if (base == null) {
1385:                    return null;
1386:                }
1387:                if (uri.startsWith(base)) {
1388:                    return uri.substring(base.length());
1389:                } else {
1390:                    return "../"
1391:                            + calculateRelativePath(uri, getParentUriPath(base));
1392:                }
1393:            }
1394:
1395:            /**
1396:             * JAX-RPC wants the namespaces to be sorted in the reverse order
1397:             * so that the empty namespace "" comes to the very end. Don't ask me why.
1398:             */
1399:            private static final Comparator<String> NAMESPACE_COMPARATOR = new Comparator<String>() {
1400:                public int compare(String lhs, String rhs) {
1401:                    return -lhs.compareTo(rhs);
1402:                }
1403:            };
1404:
1405:            private static final String newline = "\n";
1406:        }
w_w__w__.___j_a_v__a2___s__.__c_o_m__ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.