Source Code Cross Referenced for XmlSchemaGenerator.java in  » 6.0-JDK-Modules » jaxb-impl » com » sun » xml » 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 » jaxb impl » com.sun.xml.bind.v2.schemagen 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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