src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/BGMBuilder.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2012, 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
    23  * questions.
    24  */
    26 package com.sun.tools.internal.xjc.reader.xmlschema;
    28 import java.util.ArrayList;
    29 import java.util.HashMap;
    30 import java.util.List;
    31 import java.util.Map;
    32 import java.util.Set;
    34 import javax.xml.namespace.QName;
    35 import javax.xml.transform.Transformer;
    36 import javax.xml.transform.TransformerConfigurationException;
    37 import javax.xml.transform.TransformerFactory;
    39 import com.sun.codemodel.internal.JCodeModel;
    40 import com.sun.codemodel.internal.fmt.JTextFile;
    41 import com.sun.istack.internal.NotNull;
    42 import com.sun.istack.internal.Nullable;
    43 import com.sun.tools.internal.xjc.ErrorReceiver;
    44 import com.sun.tools.internal.xjc.Options;
    45 import com.sun.tools.internal.xjc.Plugin;
    46 import com.sun.tools.internal.xjc.generator.bean.field.FieldRendererFactory;
    47 import com.sun.tools.internal.xjc.model.CClassInfoParent;
    48 import com.sun.tools.internal.xjc.model.Model;
    49 import com.sun.tools.internal.xjc.reader.ModelChecker;
    50 import com.sun.tools.internal.xjc.reader.Ring;
    51 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIDeclaration;
    52 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIDom;
    53 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIGlobalBinding;
    54 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BISchemaBinding;
    55 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BISerializable;
    56 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BindInfo;
    57 import com.sun.tools.internal.xjc.util.CodeModelClassFactory;
    58 import com.sun.tools.internal.xjc.util.ErrorReceiverFilter;
    59 import com.sun.xml.internal.bind.api.impl.NameConverter;
    60 import com.sun.xml.internal.bind.v2.util.XmlFactory;
    61 import com.sun.xml.internal.xsom.XSAnnotation;
    62 import com.sun.xml.internal.xsom.XSAttributeUse;
    63 import com.sun.xml.internal.xsom.XSComponent;
    64 import com.sun.xml.internal.xsom.XSDeclaration;
    65 import com.sun.xml.internal.xsom.XSParticle;
    66 import com.sun.xml.internal.xsom.XSSchema;
    67 import com.sun.xml.internal.xsom.XSSchemaSet;
    68 import com.sun.xml.internal.xsom.XSSimpleType;
    69 import com.sun.xml.internal.xsom.XSTerm;
    70 import com.sun.xml.internal.xsom.XSType;
    71 import com.sun.xml.internal.xsom.XSWildcard;
    72 import com.sun.xml.internal.xsom.util.XSFinder;
    74 import org.xml.sax.Locator;
    76 /**
    77  * Root of the XML Schema binder.
    78  *
    79  * <div><img src="doc-files/binding_chart.png"/></div>
    80  *
    81  * @author Kohsuke Kawaguchi
    82  */
    83 public class BGMBuilder extends BindingComponent {
    85     /**
    86      * Entry point.
    87      */
    88     public static Model build( XSSchemaSet _schemas, JCodeModel codeModel,
    89             ErrorReceiver _errorReceiver, Options opts ) {
    90         // set up a ring
    91         final Ring old = Ring.begin();
    92         try {
    93             ErrorReceiverFilter ef = new ErrorReceiverFilter(_errorReceiver);
    95             Ring.add(XSSchemaSet.class,_schemas);
    96             Ring.add(codeModel);
    97             Model model = new Model(opts, codeModel, null/*set later*/, opts.classNameAllocator, _schemas);
    98             Ring.add(model);
    99             Ring.add(ErrorReceiver.class,ef);
   100             Ring.add(CodeModelClassFactory.class,new CodeModelClassFactory(ef));
   102             BGMBuilder builder = new BGMBuilder(opts.defaultPackage,opts.defaultPackage2,
   103                 opts.isExtensionMode(),opts.getFieldRendererFactory(), opts.activePlugins);
   104             builder._build();
   106             if(ef.hadError())   return null;
   107             else                return model;
   108         } finally {
   109             Ring.end(old);
   110         }
   111     }
   114     /**
   115      * True if the compiler is running in the extension mode
   116      * (as opposed to the strict conformance mode.)
   117      */
   118     public final boolean inExtensionMode;
   120     /**
   121      * If this is non-null, this package name takes over
   122      * all the schema customizations.
   123      */
   124     public final String defaultPackage1;
   126     /**
   127      * If this is non-null, this package name will be
   128      * used when no customization is specified.
   129      */
   130     public final String defaultPackage2;
   132     private final BindGreen green = Ring.get(BindGreen.class);
   133     private final BindPurple purple = Ring.get(BindPurple.class);
   135     public final Model model = Ring.get(Model.class);
   137     public final FieldRendererFactory fieldRendererFactory;
   139     /**
   140      * Lazily computed {@link RefererFinder}.
   141      *
   142      * @see #getReferer
   143      */
   144     private RefererFinder refFinder;
   146     private List<Plugin> activePlugins;
   148     protected BGMBuilder(String defaultPackage1, String defaultPackage2,
   149             boolean _inExtensionMode, FieldRendererFactory fieldRendererFactory,
   150             List<Plugin> activePlugins) {
   151         this.inExtensionMode = _inExtensionMode;
   152         this.defaultPackage1 = defaultPackage1;
   153         this.defaultPackage2 = defaultPackage2;
   154         this.fieldRendererFactory = fieldRendererFactory;
   155         this.activePlugins = activePlugins;
   156         promoteGlobalBindings();
   157     }
   159     private void _build() {
   160         // do the binding
   161         buildContents();
   162         getClassSelector().executeTasks();
   164         // additional error check
   165         // Reports unused customizations to the user as errors.
   166         Ring.get(UnusedCustomizationChecker.class).run();
   168         Ring.get(ModelChecker.class).check();
   170         for( Plugin ma : activePlugins )
   171             ma.postProcessModel(model, Ring.get(ErrorReceiver.class));
   173     }
   176     /** List up all the global bindings. */
   177     private void promoteGlobalBindings() {
   178         // promote any global bindings in the schema
   179         XSSchemaSet schemas = Ring.get(XSSchemaSet.class);
   181         for( XSSchema s : schemas.getSchemas() ) {
   182             BindInfo bi = getBindInfo(s);
   184             // collect all global customizations
   185             model.getCustomizations().addAll(bi.toCustomizationList());
   187             BIGlobalBinding gb = bi.get(BIGlobalBinding.class);
   188             if(gb==null)
   189                 continue;
   191             gb.markAsAcknowledged();
   193             if(globalBinding==null) {
   194                 globalBinding = gb;
   195             } else {
   196                 if (!globalBinding.isEqual(gb)) { // see Issue 687 - this may happen with syntactically imported documents
   197                     // acknowledge this customization and report an error
   198                     // otherwise the user will see "customization is attached to a wrong place" error,
   199                     // which is incorrect
   200                     getErrorReporter().error( gb.getLocation(),
   201                         Messages.ERR_MULTIPLE_GLOBAL_BINDINGS);
   202                     getErrorReporter().error( globalBinding.getLocation(),
   203                         Messages.ERR_MULTIPLE_GLOBAL_BINDINGS_OTHER);
   204                 }
   205             }
   206         }
   208         if( globalBinding==null ) {
   209             // no global customization is present.
   210             // use the default one
   211             globalBinding = new BIGlobalBinding();
   212             BindInfo big = new BindInfo();
   213             big.addDecl(globalBinding);
   214             big.setOwner(this,null);
   215         }
   217         // code generation mode
   218         model.strategy = globalBinding.getCodeGenerationStrategy();
   219         model.rootClass = globalBinding.getSuperClass();
   220         model.rootInterface = globalBinding.getSuperInterface();
   222         particleBinder = globalBinding.isSimpleMode() ? new ExpressionParticleBinder() : new DefaultParticleBinder();
   224         // check XJC extensions and realize them
   225         BISerializable serial = globalBinding.getSerializable();
   226         if(serial!=null) {
   227             model.serializable = true;
   228             model.serialVersionUID = serial.uid;
   229         }
   231         // obtain the name conversion mode
   232         if (globalBinding.nameConverter!=null)
   233             model.setNameConverter(globalBinding.nameConverter);
   235         // attach global conversions to the appropriate simple types
   236         globalBinding.dispatchGlobalConversions(schemas);
   238         globalBinding.errorCheck();
   239     }
   241     /**
   242      * Global bindings.
   243      *
   244      * The empty global binding is set as the default, so that
   245      * there will be no need to test if the value is null.
   246      */
   247     private BIGlobalBinding globalBinding;
   249     /**
   250      * Gets the global bindings.
   251      */
   252     public @NotNull BIGlobalBinding getGlobalBinding() { return globalBinding; }
   255     private ParticleBinder particleBinder;
   257     /**
   258      * Gets the particle binder for this binding.
   259      */
   260     public @NotNull ParticleBinder getParticleBinder() { return particleBinder; }
   263     /**
   264      * Name converter that implements "XML->Java name conversion"
   265      * as specified in the spec.
   266      *
   267      * This object abstracts the detail that we use different name
   268      * conversion depending on the customization.
   269      *
   270      * <p>
   271      * This object should be used to perform any name conversion
   272      * needs, instead of the JJavaName class in CodeModel.
   273      */
   274     public NameConverter getNameConverter() { return model.getNameConverter(); }
   276     /** Fill-in the contents of each classes. */
   277     private void buildContents() {
   278         ClassSelector cs = getClassSelector();
   279         SimpleTypeBuilder stb = Ring.get(SimpleTypeBuilder.class);
   281         for( XSSchema s : Ring.get(XSSchemaSet.class).getSchemas() ) {
   282             BISchemaBinding sb = getBindInfo(s).get(BISchemaBinding.class);
   284             if(sb!=null && !sb.map) {
   285                 sb.markAsAcknowledged();
   286                 continue;       // no mapping for this package
   287             }
   289             getClassSelector().pushClassScope( new CClassInfoParent.Package(
   290                 getClassSelector().getPackage(s.getTargetNamespace())) );
   292             checkMultipleSchemaBindings(s);
   293             processPackageJavadoc(s);
   294             populate(s.getAttGroupDecls(),s);
   295             populate(s.getAttributeDecls(),s);
   296             populate(s.getElementDecls(),s);
   297             populate(s.getModelGroupDecls(),s);
   299             // fill in typeUses
   300             for (XSType t : s.getTypes().values()) {
   301                 stb.refererStack.push(t);
   302                 model.typeUses().put( getName(t), cs.bindToType(t,s) );
   303                 stb.refererStack.pop();
   304             }
   306             getClassSelector().popClassScope();
   307         }
   308     }
   310     /** Reports an error if there are more than one jaxb:schemaBindings customization. */
   311     private void checkMultipleSchemaBindings( XSSchema schema ) {
   312         ArrayList<Locator> locations = new ArrayList<Locator>();
   314         BindInfo bi = getBindInfo(schema);
   315         for( BIDeclaration bid : bi ) {
   316             if( bid.getName()==BISchemaBinding.NAME )
   317                 locations.add( bid.getLocation() );
   318         }
   319         if(locations.size()<=1)    return; // OK
   321         // error
   322         getErrorReporter().error( locations.get(0),
   323             Messages.ERR_MULTIPLE_SCHEMA_BINDINGS,
   324             schema.getTargetNamespace() );
   325         for( int i=1; i<locations.size(); i++ )
   326             getErrorReporter().error( (Locator)locations.get(i),
   327                 Messages.ERR_MULTIPLE_SCHEMA_BINDINGS_LOCATION);
   328     }
   330     /**
   331      * Calls {@link ClassSelector} for each item in the iterator
   332      * to populate class items if there is any.
   333      */
   334     private void populate( Map<String,? extends XSComponent> col, XSSchema schema ) {
   335         ClassSelector cs = getClassSelector();
   336         for( XSComponent sc : col.values() )
   337             cs.bindToType(sc,schema);
   338     }
   340     /**
   341      * Generates <code>package.html</code> if the customization
   342      * says so.
   343      */
   344     private void processPackageJavadoc( XSSchema s ) {
   345         // look for the schema-wide customization
   346         BISchemaBinding cust = getBindInfo(s).get(BISchemaBinding.class);
   347         if(cust==null)      return; // not present
   349         cust.markAsAcknowledged();
   350         if( cust.getJavadoc()==null )   return;     // no javadoc customization
   352         // produce a HTML file
   353         JTextFile html = new JTextFile("package.html");
   354         html.setContents(cust.getJavadoc());
   355         getClassSelector().getPackage(s.getTargetNamespace()).addResourceFile(html);
   356     }
   363     /**
   364      * Gets or creates the BindInfo object associated to a schema component.
   365      *
   366      * @return
   367      *      Always return a non-null valid BindInfo object.
   368      *      Even if no declaration was specified, this method creates
   369      *      a new BindInfo so that new decls can be added.
   370      */
   371     public BindInfo getOrCreateBindInfo( XSComponent schemaComponent ) {
   373         BindInfo bi = _getBindInfoReadOnly(schemaComponent);
   374         if(bi!=null)    return bi;
   376         // XSOM is read-only, so we cannot add new annotations.
   377         // for components that didn't have annotations,
   378         // we maintain an external map.
   379         bi = new BindInfo();
   380         bi.setOwner(this,schemaComponent);
   381         externalBindInfos.put(schemaComponent,bi);
   382         return bi;
   383     }
   386     /**
   387      * Used as a constant instance to represent the empty {@link BindInfo}.
   388      */
   389     private final BindInfo emptyBindInfo = new BindInfo();
   391     /**
   392      * Gets the BindInfo object associated to a schema component.
   393      *
   394      * @return
   395      *      always return a valid {@link BindInfo} object. If none
   396      *      is specified for the given component, a dummy empty BindInfo
   397      *      will be returned.
   398      */
   399     public BindInfo getBindInfo( XSComponent schemaComponent ) {
   400         BindInfo bi = _getBindInfoReadOnly(schemaComponent);
   401         if(bi!=null)    return bi;
   402         else            return emptyBindInfo;
   403     }
   405     /**
   406      * Gets the BindInfo object associated to a schema component.
   407      *
   408      * @return
   409      *      null if no bind info is associated to this schema component.
   410      */
   411     private BindInfo _getBindInfoReadOnly( XSComponent schemaComponent ) {
   413         BindInfo bi = externalBindInfos.get(schemaComponent);
   414         if(bi!=null)    return bi;
   416         XSAnnotation annon = schemaComponent.getAnnotation();
   417         if(annon!=null) {
   418             bi = (BindInfo)annon.getAnnotation();
   419             if(bi!=null) {
   420                 if(bi.getOwner()==null)
   421                     bi.setOwner(this,schemaComponent);
   422                 return bi;
   423             }
   424         }
   426         return null;
   427     }
   429     /**
   430      * A map that stores binding declarations augmented by XJC.
   431      */
   432     private final Map<XSComponent,BindInfo> externalBindInfos = new HashMap<XSComponent,BindInfo>();
   434     /**
   435      * Gets the {@link BIDom} object that applies to the given particle.
   436      */
   437     protected final BIDom getLocalDomCustomization( XSParticle p ) {
   438         if (p == null) {
   439             return null;
   440         }
   441         BIDom dom = getBindInfo(p).get(BIDom.class);
   442         if(dom!=null)  return dom;
   444         // if not, the term might have one.
   445         dom = getBindInfo(p.getTerm()).get(BIDom.class);
   446         if(dom!=null)  return dom;
   448         XSTerm t = p.getTerm();
   449         // type could also have one, in case of the dom customization
   450         if(t.isElementDecl())
   451             return getBindInfo(t.asElementDecl().getType()).get(BIDom.class);
   452         // similarly the model group in a model group definition may have one.
   453         if(t.isModelGroupDecl())
   454             return getBindInfo(t.asModelGroupDecl().getModelGroup()).get(BIDom.class);
   456         return null;
   457     }
   459     /**
   460      * Returns true if the component should be processed by purple.
   461      */
   462     private final XSFinder toPurple = new XSFinder() {
   463         @Override
   464         public Boolean attributeUse(XSAttributeUse use) {
   465             // attribute use always maps to a property
   466             return true;
   467         }
   469         @Override
   470         public Boolean simpleType(XSSimpleType xsSimpleType) {
   471             // simple type always maps to a type, hence we should take purple
   472             return true;
   473         }
   475         @Override
   476         public Boolean wildcard(XSWildcard xsWildcard) {
   477             // attribute wildcards always maps to a property.
   478             // element wildcards should have been processed with particle binders
   479             return true;
   480         }
   481     };
   482     /**
   483      * If the component maps to a property, forwards to purple, otherwise to green.
   484      *
   485      * If the component is mapped to a type, this method needs to return true.
   486      * See the chart at the class javadoc.
   487      */
   488     public void ying( XSComponent sc, @Nullable XSComponent referer ) {
   489         if(sc.apply(toPurple)==true || getClassSelector().bindToType(sc,referer)!=null)
   490             sc.visit(purple);
   491         else
   492             sc.visit(green);
   493     }
   495     private Transformer identityTransformer;
   497     /**
   498      * Gets the shared instance of the identity transformer.
   499      */
   500     public Transformer getIdentityTransformer() {
   501         try {
   502             if(identityTransformer==null) {
   503                 TransformerFactory tf = XmlFactory.createTransformerFactory(model.options.disableXmlSecurity);
   504                 identityTransformer = tf.newTransformer();
   505             }
   506             return identityTransformer;
   507         } catch (TransformerConfigurationException e) {
   508             throw new Error(e); // impossible
   509         }
   510     }
   512     /**
   513      * Find all types that refer to the given complex type.
   514      */
   515     public Set<XSComponent> getReferer(XSType c) {
   516         if(refFinder==null) {
   517             refFinder = new RefererFinder();
   518             refFinder.schemaSet(Ring.get(XSSchemaSet.class));
   519         }
   520         return refFinder.getReferer(c);
   521     }
   523     /**
   524      * Returns the QName of the declaration.
   525      * @return null
   526      *      if the declaration is anonymous.
   527      */
   528     public static QName getName(XSDeclaration decl) {
   529         String local = decl.getName();
   530         if(local==null) return null;
   531         return new QName(decl.getTargetNamespace(),local);
   532     }
   534     /**
   535      * Derives a name from a schema component.
   536      *
   537      * This method handles prefix/suffix modification and
   538      * XML-to-Java name conversion.
   539      *
   540      * @param name
   541      *      The base name. This should be things like element names
   542      *      or type names.
   543      * @param comp
   544      *      The component from which the base name was taken.
   545      *      Used to determine how names are modified.
   546      */
   547     public String deriveName( String name, XSComponent comp ) {
   548         XSSchema owner = comp.getOwnerSchema();
   550         name = getNameConverter().toClassName(name);
   552         if( owner!=null ) {
   553             BISchemaBinding sb = getBindInfo(owner).get(BISchemaBinding.class);
   555             if(sb!=null)    name = sb.mangleClassName(name,comp);
   556         }
   558         return name;
   559     }
   561     public boolean isGenerateMixedExtensions() {
   562         if (globalBinding != null) {
   563             return globalBinding.isGenerateMixedExtensions();
   564         }
   565         return false;
   566     }
   568 }

mercurial