1 /*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
93 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalAttribute;
94 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalElement;
95 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Schema;
96 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleExtension;
97 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleRestrictionModel;
98 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleType;
99 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleTypeHost;
100 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TopLevelAttribute;
101 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TopLevelElement;
102 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TypeHost;
103 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ContentModelContainer;
104 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TypeDefParticle;
105 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.AttributeType;
106 import com.sun.xml.internal.bind.v2.schemagen.episode.Bindings;
107 import com.sun.xml.internal.txw2.TXW;
108 import com.sun.xml.internal.txw2.TxwException;
109 import com.sun.xml.internal.txw2.TypedXmlWriter;
110 import com.sun.xml.internal.txw2.output.ResultFactory;
111 import com.sun.xml.internal.txw2.output.XmlSerializer;
112 import java.util.Collection;
113 import org.xml.sax.SAXParseException;
114
115 /**
116 * Generates a set of W3C XML Schema documents from a set of Java classes.
117 *
118 * <p>
119 * A client must invoke methods in the following order:
120 * <ol>
121 * <li>Create a new {@link XmlSchemaGenerator}
122 * <li>Invoke {@link #add} methods, multiple times if necessary.
123 * <li>Invoke {@link #write}
124 * <li>Discard the {@link XmlSchemaGenerator}.
125 * </ol>
126 *
127 * @author Ryan Shoemaker
128 * @author Kohsuke Kawaguchi (kk@kohsuke.org)
129 */
130 public final class XmlSchemaGenerator<T,C,F,M> {
131
132 private static final Logger logger = Util.getClassLogger();
419 Bindings child = group.bindings();
420 child.scd('~'+prefix+en.getTypeName().getLocalPart());
421 child.klass().ref(navigator.getClassName(en.getClazz()));
422 }
423
424 group.commit(true);
425 }
426
427 root.commit();
428 }
429
430 /**
431 * Write out the schema documents.
432 */
433 public void write(SchemaOutputResolver resolver, ErrorListener errorListener) throws IOException {
434 if(resolver==null)
435 throw new IllegalArgumentException();
436
437 if(logger.isLoggable(Level.FINE)) {
438 // debug logging to see what's going on.
439 logger.log(Level.FINE,"Wrigin XML Schema for "+toString(),new StackRecorder());
440 }
441
442 // make it fool-proof
443 resolver = new FoolProofResolver(resolver);
444 this.errorListener = errorListener;
445
446 Map<String, String> schemaLocations = types.getSchemaLocations();
447
448 Map<Namespace,Result> out = new HashMap<Namespace,Result>();
449 Map<Namespace,String> systemIds = new HashMap<Namespace,String>();
450
451 // we create a Namespace object for the XML Schema namespace
452 // as a side-effect, but we don't want to generate it.
453 namespaces.remove(WellKnownNamespace.XML_SCHEMA);
454
455 // first create the outputs for all so that we can resolve references among
456 // schema files when we write
457 for( Namespace n : namespaces.values() ) {
458 String schemaLocation = schemaLocations.get(n.uri);
459 if(schemaLocation!=null) {
460 systemIds.put(n,schemaLocation);
461 } else {
462 Result output = resolver.createOutput(n.uri,"schema"+(out.size()+1)+".xsd");
463 if(output!=null) { // null result means no schema for that namespace
464 out.put(n,output);
465 systemIds.put(n,output.getSystemId());
466 }
467 }
468 }
469
470 // then write'em all
471 for( Map.Entry<Namespace,Result> e : out.entrySet() ) {
472 Result result = e.getValue();
473 e.getKey().writeTo( result, systemIds );
474 if(result instanceof StreamResult) {
475 OutputStream outputStream = ((StreamResult)result).getOutputStream();
476 if(outputStream != null) {
477 outputStream.close(); // fix for bugid: 6291301
478 } else {
479 final Writer writer = ((StreamResult)result).getWriter();
480 if(writer != null) writer.close();
481 }
482 }
483 }
484 }
485
486
487
525 * Global element declarations to be written, keyed by their local names.
526 */
527 private final MultiMap<String,ElementDeclaration> elementDecls =
528 new MultiMap<String,ElementDeclaration>(new ElementWithType(true,anyType));
529
530 private Form attributeFormDefault;
531 private Form elementFormDefault;
532
533 /**
534 * Does schema in this namespace uses swaRef? If so, we need to generate import
535 * statement.
536 */
537 private boolean useSwaRef;
538
539 /**
540 * Import for mime namespace needs to be generated.
541 * See #856
542 */
543 private boolean useMimeNs;
544
545 public Namespace(String uri) {
546 this.uri = uri;
547 assert !XmlSchemaGenerator.this.namespaces.containsKey(uri);
548 XmlSchemaGenerator.this.namespaces.put(uri,this);
549 }
550
551 /**
552 * Process the given PropertyInfo looking for references to namespaces that
553 * are foreign to the given namespace. Any foreign namespace references
554 * found are added to the given namespaces dependency list and an <import>
555 * is generated for it.
556 *
557 * @param p the PropertyInfo
558 */
559 private void processForeignNamespaces(PropertyInfo<T, C> p, int processingDepth) {
560 for (TypeInfo<T, C> t : p.ref()) {
561 if ((t instanceof ClassInfo) && (processingDepth > 0)) {
562 java.util.List<PropertyInfo> l = ((ClassInfo) t).getProperties();
563 for (PropertyInfo subp : l) {
564 processForeignNamespaces(subp, --processingDepth);
565 }
566 }
567 if (t instanceof Element) {
568 addDependencyTo(((Element) t).getElementName());
569 }
570 if (t instanceof NonElement) {
571 addDependencyTo(((NonElement) t).getTypeName());
836 private void writeEnum(EnumLeafInfo<T, C> e, SimpleTypeHost th) {
837 SimpleType st = th.simpleType();
838 writeName(e,st);
839
840 SimpleRestrictionModel base = st.restriction();
841 writeTypeRef(base, e.getBaseType(), "base");
842
843 for (EnumConstant c : e.getConstants()) {
844 base.enumeration().value(c.getLexicalValue());
845 }
846 st.commit();
847 }
848
849 /**
850 * Writes the schema definition for the specified class to the schema writer.
851 *
852 * @param c the class info
853 * @param parent the writer of the parent element into which the type will be defined
854 */
855 private void writeClass(ClassInfo<T,C> c, TypeHost parent) {
856 // special handling for value properties
857 if (containsValueProp(c)) {
858 if (c.getProperties().size() == 1) {
859 // [RESULT 2 - simpleType if the value prop is the only prop]
860 //
861 // <simpleType name="foo">
862 // <xs:restriction base="xs:int"/>
863 // </>
864 ValuePropertyInfo<T,C> vp = (ValuePropertyInfo<T,C>)c.getProperties().get(0);
865 SimpleType st = ((SimpleTypeHost)parent).simpleType();
866 writeName(c, st);
867 if(vp.isCollection()) {
868 writeTypeRef(st.list(),vp.getTarget(),"itemType");
869 } else {
870 writeTypeRef(st.restriction(),vp.getTarget(),"base");
871 }
872 return;
873 } else {
874 // [RESULT 1 - complexType with simpleContent]
875 //
|
1 /*
2 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
93 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalAttribute;
94 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.LocalElement;
95 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.Schema;
96 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleExtension;
97 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleRestrictionModel;
98 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleType;
99 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.SimpleTypeHost;
100 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TopLevelAttribute;
101 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TopLevelElement;
102 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TypeHost;
103 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.ContentModelContainer;
104 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.TypeDefParticle;
105 import com.sun.xml.internal.bind.v2.schemagen.xmlschema.AttributeType;
106 import com.sun.xml.internal.bind.v2.schemagen.episode.Bindings;
107 import com.sun.xml.internal.txw2.TXW;
108 import com.sun.xml.internal.txw2.TxwException;
109 import com.sun.xml.internal.txw2.TypedXmlWriter;
110 import com.sun.xml.internal.txw2.output.ResultFactory;
111 import com.sun.xml.internal.txw2.output.XmlSerializer;
112 import java.util.Collection;
113 import java.util.HashSet;
114 import org.xml.sax.SAXParseException;
115
116 /**
117 * Generates a set of W3C XML Schema documents from a set of Java classes.
118 *
119 * <p>
120 * A client must invoke methods in the following order:
121 * <ol>
122 * <li>Create a new {@link XmlSchemaGenerator}
123 * <li>Invoke {@link #add} methods, multiple times if necessary.
124 * <li>Invoke {@link #write}
125 * <li>Discard the {@link XmlSchemaGenerator}.
126 * </ol>
127 *
128 * @author Ryan Shoemaker
129 * @author Kohsuke Kawaguchi (kk@kohsuke.org)
130 */
131 public final class XmlSchemaGenerator<T,C,F,M> {
132
133 private static final Logger logger = Util.getClassLogger();
420 Bindings child = group.bindings();
421 child.scd('~'+prefix+en.getTypeName().getLocalPart());
422 child.klass().ref(navigator.getClassName(en.getClazz()));
423 }
424
425 group.commit(true);
426 }
427
428 root.commit();
429 }
430
431 /**
432 * Write out the schema documents.
433 */
434 public void write(SchemaOutputResolver resolver, ErrorListener errorListener) throws IOException {
435 if(resolver==null)
436 throw new IllegalArgumentException();
437
438 if(logger.isLoggable(Level.FINE)) {
439 // debug logging to see what's going on.
440 logger.log(Level.FINE,"Writing XML Schema for "+toString(),new StackRecorder());
441 }
442
443 // make it fool-proof
444 resolver = new FoolProofResolver(resolver);
445 this.errorListener = errorListener;
446
447 Map<String, String> schemaLocations = types.getSchemaLocations();
448
449 Map<Namespace,Result> out = new HashMap<Namespace,Result>();
450 Map<Namespace,String> systemIds = new HashMap<Namespace,String>();
451
452 // we create a Namespace object for the XML Schema namespace
453 // as a side-effect, but we don't want to generate it.
454 namespaces.remove(WellKnownNamespace.XML_SCHEMA);
455
456 // first create the outputs for all so that we can resolve references among
457 // schema files when we write
458 for( Namespace n : namespaces.values() ) {
459 String schemaLocation = schemaLocations.get(n.uri);
460 if(schemaLocation!=null) {
461 systemIds.put(n,schemaLocation);
462 } else {
463 Result output = resolver.createOutput(n.uri,"schema"+(out.size()+1)+".xsd");
464 if(output!=null) { // null result means no schema for that namespace
465 out.put(n,output);
466 systemIds.put(n,output.getSystemId());
467 }
468 }
469 //Clear the namespace specific set with already written classes
470 n.resetWritten();
471 }
472
473 // then write'em all
474 for( Map.Entry<Namespace,Result> e : out.entrySet() ) {
475 Result result = e.getValue();
476 e.getKey().writeTo( result, systemIds );
477 if(result instanceof StreamResult) {
478 OutputStream outputStream = ((StreamResult)result).getOutputStream();
479 if(outputStream != null) {
480 outputStream.close(); // fix for bugid: 6291301
481 } else {
482 final Writer writer = ((StreamResult)result).getWriter();
483 if(writer != null) writer.close();
484 }
485 }
486 }
487 }
488
489
490
528 * Global element declarations to be written, keyed by their local names.
529 */
530 private final MultiMap<String,ElementDeclaration> elementDecls =
531 new MultiMap<String,ElementDeclaration>(new ElementWithType(true,anyType));
532
533 private Form attributeFormDefault;
534 private Form elementFormDefault;
535
536 /**
537 * Does schema in this namespace uses swaRef? If so, we need to generate import
538 * statement.
539 */
540 private boolean useSwaRef;
541
542 /**
543 * Import for mime namespace needs to be generated.
544 * See #856
545 */
546 private boolean useMimeNs;
547
548 /**
549 * Container for already processed classes
550 */
551 private final Set<ClassInfo> written = new HashSet<ClassInfo>();
552
553 public Namespace(String uri) {
554 this.uri = uri;
555 assert !XmlSchemaGenerator.this.namespaces.containsKey(uri);
556 XmlSchemaGenerator.this.namespaces.put(uri,this);
557 }
558
559 /**
560 * Clear out the set of already processed classes for this namespace
561 */
562 void resetWritten() {
563 written.clear();
564 }
565
566 /**
567 * Process the given PropertyInfo looking for references to namespaces that
568 * are foreign to the given namespace. Any foreign namespace references
569 * found are added to the given namespaces dependency list and an <import>
570 * is generated for it.
571 *
572 * @param p the PropertyInfo
573 */
574 private void processForeignNamespaces(PropertyInfo<T, C> p, int processingDepth) {
575 for (TypeInfo<T, C> t : p.ref()) {
576 if ((t instanceof ClassInfo) && (processingDepth > 0)) {
577 java.util.List<PropertyInfo> l = ((ClassInfo) t).getProperties();
578 for (PropertyInfo subp : l) {
579 processForeignNamespaces(subp, --processingDepth);
580 }
581 }
582 if (t instanceof Element) {
583 addDependencyTo(((Element) t).getElementName());
584 }
585 if (t instanceof NonElement) {
586 addDependencyTo(((NonElement) t).getTypeName());
851 private void writeEnum(EnumLeafInfo<T, C> e, SimpleTypeHost th) {
852 SimpleType st = th.simpleType();
853 writeName(e,st);
854
855 SimpleRestrictionModel base = st.restriction();
856 writeTypeRef(base, e.getBaseType(), "base");
857
858 for (EnumConstant c : e.getConstants()) {
859 base.enumeration().value(c.getLexicalValue());
860 }
861 st.commit();
862 }
863
864 /**
865 * Writes the schema definition for the specified class to the schema writer.
866 *
867 * @param c the class info
868 * @param parent the writer of the parent element into which the type will be defined
869 */
870 private void writeClass(ClassInfo<T,C> c, TypeHost parent) {
871 if (written.contains(c)) { // to avoid cycles let's check if we haven't already processed the class
872 return;
873 }
874 written.add(c);
875 // special handling for value properties
876 if (containsValueProp(c)) {
877 if (c.getProperties().size() == 1) {
878 // [RESULT 2 - simpleType if the value prop is the only prop]
879 //
880 // <simpleType name="foo">
881 // <xs:restriction base="xs:int"/>
882 // </>
883 ValuePropertyInfo<T,C> vp = (ValuePropertyInfo<T,C>)c.getProperties().get(0);
884 SimpleType st = ((SimpleTypeHost)parent).simpleType();
885 writeName(c, st);
886 if(vp.isCollection()) {
887 writeTypeRef(st.list(),vp.getTarget(),"itemType");
888 } else {
889 writeTypeRef(st.restriction(),vp.getTarget(),"base");
890 }
891 return;
892 } else {
893 // [RESULT 1 - complexType with simpleContent]
894 //
|