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

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

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

mercurial