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

changeset 0
373ffda63c9a
child 637
9c07ef4934dd
equal deleted inserted replaced
-1:000000000000 0:373ffda63c9a
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 */
25
26 package com.sun.tools.internal.xjc.reader.xmlschema;
27
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;
33
34 import javax.xml.namespace.QName;
35 import javax.xml.transform.Transformer;
36 import javax.xml.transform.TransformerConfigurationException;
37 import javax.xml.transform.TransformerFactory;
38
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;
73
74 import org.xml.sax.Locator;
75
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 {
84
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);
94
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));
101
102 BGMBuilder builder = new BGMBuilder(opts.defaultPackage,opts.defaultPackage2,
103 opts.isExtensionMode(),opts.getFieldRendererFactory(), opts.activePlugins);
104 builder._build();
105
106 if(ef.hadError()) return null;
107 else return model;
108 } finally {
109 Ring.end(old);
110 }
111 }
112
113
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;
119
120 /**
121 * If this is non-null, this package name takes over
122 * all the schema customizations.
123 */
124 public final String defaultPackage1;
125
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;
131
132 private final BindGreen green = Ring.get(BindGreen.class);
133 private final BindPurple purple = Ring.get(BindPurple.class);
134
135 public final Model model = Ring.get(Model.class);
136
137 public final FieldRendererFactory fieldRendererFactory;
138
139 /**
140 * Lazily computed {@link RefererFinder}.
141 *
142 * @see #getReferer
143 */
144 private RefererFinder refFinder;
145
146 private List<Plugin> activePlugins;
147
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 }
158
159 private void _build() {
160 // do the binding
161 buildContents();
162 getClassSelector().executeTasks();
163
164 // additional error check
165 // Reports unused customizations to the user as errors.
166 Ring.get(UnusedCustomizationChecker.class).run();
167
168 Ring.get(ModelChecker.class).check();
169
170 for( Plugin ma : activePlugins )
171 ma.postProcessModel(model, Ring.get(ErrorReceiver.class));
172
173 }
174
175
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);
180
181 for( XSSchema s : schemas.getSchemas() ) {
182 BindInfo bi = getBindInfo(s);
183
184 // collect all global customizations
185 model.getCustomizations().addAll(bi.toCustomizationList());
186
187 BIGlobalBinding gb = bi.get(BIGlobalBinding.class);
188 if(gb==null)
189 continue;
190
191 gb.markAsAcknowledged();
192
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 }
207
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 }
216
217 // code generation mode
218 model.strategy = globalBinding.getCodeGenerationStrategy();
219 model.rootClass = globalBinding.getSuperClass();
220 model.rootInterface = globalBinding.getSuperInterface();
221
222 particleBinder = globalBinding.isSimpleMode() ? new ExpressionParticleBinder() : new DefaultParticleBinder();
223
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 }
230
231 // obtain the name conversion mode
232 if (globalBinding.nameConverter!=null)
233 model.setNameConverter(globalBinding.nameConverter);
234
235 // attach global conversions to the appropriate simple types
236 globalBinding.dispatchGlobalConversions(schemas);
237
238 globalBinding.errorCheck();
239 }
240
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;
248
249 /**
250 * Gets the global bindings.
251 */
252 public @NotNull BIGlobalBinding getGlobalBinding() { return globalBinding; }
253
254
255 private ParticleBinder particleBinder;
256
257 /**
258 * Gets the particle binder for this binding.
259 */
260 public @NotNull ParticleBinder getParticleBinder() { return particleBinder; }
261
262
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(); }
275
276 /** Fill-in the contents of each classes. */
277 private void buildContents() {
278 ClassSelector cs = getClassSelector();
279 SimpleTypeBuilder stb = Ring.get(SimpleTypeBuilder.class);
280
281 for( XSSchema s : Ring.get(XSSchemaSet.class).getSchemas() ) {
282 BISchemaBinding sb = getBindInfo(s).get(BISchemaBinding.class);
283
284 if(sb!=null && !sb.map) {
285 sb.markAsAcknowledged();
286 continue; // no mapping for this package
287 }
288
289 getClassSelector().pushClassScope( new CClassInfoParent.Package(
290 getClassSelector().getPackage(s.getTargetNamespace())) );
291
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);
298
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 }
305
306 getClassSelector().popClassScope();
307 }
308 }
309
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>();
313
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
320
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 }
329
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 }
339
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
348
349 cust.markAsAcknowledged();
350 if( cust.getJavadoc()==null ) return; // no javadoc customization
351
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 }
357
358
359
360
361
362
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 ) {
372
373 BindInfo bi = _getBindInfoReadOnly(schemaComponent);
374 if(bi!=null) return bi;
375
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 }
384
385
386 /**
387 * Used as a constant instance to represent the empty {@link BindInfo}.
388 */
389 private final BindInfo emptyBindInfo = new BindInfo();
390
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 }
404
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 ) {
412
413 BindInfo bi = externalBindInfos.get(schemaComponent);
414 if(bi!=null) return bi;
415
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 }
425
426 return null;
427 }
428
429 /**
430 * A map that stores binding declarations augmented by XJC.
431 */
432 private final Map<XSComponent,BindInfo> externalBindInfos = new HashMap<XSComponent,BindInfo>();
433
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;
443
444 // if not, the term might have one.
445 dom = getBindInfo(p.getTerm()).get(BIDom.class);
446 if(dom!=null) return dom;
447
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);
455
456 return null;
457 }
458
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 }
468
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 }
474
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 }
494
495 private Transformer identityTransformer;
496
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 }
511
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 }
522
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 }
533
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();
549
550 name = getNameConverter().toClassName(name);
551
552 if( owner!=null ) {
553 BISchemaBinding sb = getBindInfo(owner).get(BISchemaBinding.class);
554
555 if(sb!=null) name = sb.mangleClassName(name,comp);
556 }
557
558 return name;
559 }
560
561 public boolean isGenerateMixedExtensions() {
562 if (globalBinding != null) {
563 return globalBinding.isGenerateMixedExtensions();
564 }
565 return false;
566 }
567
568 }

mercurial