325N/A/*
325N/A * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
325N/A *
325N/A * This code is free software; you can redistribute it and/or modify it
325N/A * under the terms of the GNU General Public License version 2 only, as
325N/A * published by the Free Software Foundation. Oracle designates this
325N/A * particular file as subject to the "Classpath" exception as provided
325N/A * by Oracle in the LICENSE file that accompanied this code.
325N/A *
325N/A * This code is distributed in the hope that it will be useful, but WITHOUT
325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325N/A * version 2 for more details (a copy is included in the LICENSE file that
325N/A * accompanied this code).
325N/A *
325N/A * You should have received a copy of the GNU General Public License version
325N/A * 2 along with this work; if not, write to the Free Software Foundation,
325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
325N/A *
325N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
325N/A * or visit www.oracle.com if you need additional information or have any
325N/A * questions.
325N/A */
325N/A
325N/Apackage com.sun.tools.internal.xjc.reader.xmlschema;
325N/A
325N/Aimport java.util.ArrayList;
325N/Aimport java.util.Collection;
325N/Aimport java.util.Collections;
325N/Aimport java.util.HashMap;
325N/Aimport java.util.Hashtable;
325N/Aimport java.util.List;
325N/Aimport java.util.Map;
325N/A
325N/Aimport com.sun.tools.internal.xjc.model.CClassInfo;
325N/Aimport com.sun.tools.internal.xjc.model.CPropertyInfo;
325N/Aimport com.sun.tools.internal.xjc.model.CReferencePropertyInfo;
325N/Aimport com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIProperty;
325N/Aimport com.sun.xml.internal.xsom.XSElementDecl;
325N/Aimport com.sun.xml.internal.xsom.XSModelGroup;
325N/Aimport com.sun.xml.internal.xsom.XSModelGroupDecl;
325N/Aimport com.sun.xml.internal.xsom.XSParticle;
325N/Aimport com.sun.xml.internal.xsom.XSTerm;
325N/Aimport com.sun.xml.internal.xsom.XSWildcard;
325N/Aimport com.sun.xml.internal.xsom.visitor.XSTermVisitor;
325N/Aimport java.math.BigInteger;
325N/A
325N/A/**
325N/A * {@link ParticleBinder} that follows the JAXB spec.
325N/A *
325N/A * @author Kohsuke Kawaguchi
325N/A */
325N/Afinal class DefaultParticleBinder extends ParticleBinder {
325N/A
325N/A @Override
325N/A public void build( XSParticle p, Collection<XSParticle> forcedProps ) {
325N/A Checker checker = checkCollision(p,forcedProps);
325N/A
325N/A if(checker.hasNameCollision()) {
325N/A CReferencePropertyInfo prop = new CReferencePropertyInfo(
325N/A getCurrentBean().getBaseClass()==null?"Content":"Rest",
325N/A true, false, false, p,
325N/A builder.getBindInfo(p).toCustomizationList(),
325N/A p.getLocator(), false, false, false);
325N/A RawTypeSetBuilder.build(p,false).addTo(prop);
325N/A prop.javadoc = Messages.format( Messages.MSG_FALLBACK_JAVADOC,
325N/A checker.getCollisionInfo().toString() );
325N/A
325N/A getCurrentBean().addProperty(prop);
325N/A } else {
325N/A new Builder(checker.markedParticles).particle(p);
325N/A }
325N/A }
325N/A
325N/A @Override
325N/A public boolean checkFallback( XSParticle p ) {
325N/A return checkCollision(p,Collections.<XSParticle>emptyList()).hasNameCollision();
325N/A }
325N/A
325N/A private Checker checkCollision( XSParticle p, Collection<XSParticle> forcedProps ) {
325N/A // scan the tree by a checker.
325N/A Checker checker = new Checker(forcedProps);
325N/A
325N/A CClassInfo superClass = getCurrentBean().getBaseClass();
325N/A
325N/A if(superClass!=null)
325N/A checker.readSuperClass(superClass);
325N/A checker.particle(p);
325N/A
325N/A return checker;
325N/A }
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A /**
325N/A * Marks particles that need to be mapped to properties,
325N/A * by reading customization info.
325N/A */
325N/A private final class Checker implements XSTermVisitor {
325N/A
325N/A Checker(Collection<XSParticle> forcedProps) {
325N/A this.forcedProps = forcedProps;
325N/A }
325N/A
325N/A boolean hasNameCollision() {
325N/A return collisionInfo!=null;
325N/A }
325N/A
325N/A CollisionInfo getCollisionInfo() {
325N/A return collisionInfo;
325N/A }
325N/A
325N/A /**
325N/A * If a collision is found, this field will be non-null.
325N/A */
325N/A private CollisionInfo collisionInfo = null;
325N/A
325N/A /** Used to check name collision. */
325N/A private final NameCollisionChecker cchecker = new NameCollisionChecker();
325N/A
325N/A /**
325N/A * @see DefaultParticleBinder#build(XSParticle, Collection<com.sun.xml.internal.xsom.XSParticle>)
325N/A */
325N/A private final Collection<XSParticle> forcedProps;
325N/A
325N/A public void particle( XSParticle p ) {
325N/A
325N/A if(getLocalPropCustomization(p)!=null
325N/A || builder.getLocalDomCustomization(p)!=null) {
325N/A // if a property customization is specfied,
325N/A // check that value and turn around.
325N/A check(p);
325N/A mark(p);
325N/A return;
325N/A }
325N/A
325N/A XSTerm t = p.getTerm();
325N/A
325N/A if(p.isRepeated() && (t.isModelGroup() || t.isModelGroupDecl())) {
325N/A // a repeated model group gets its own property
325N/A mark(p);
325N/A return;
325N/A }
325N/A
325N/A if(forcedProps.contains(p)) {
325N/A // this particle must become a property
325N/A mark(p);
325N/A return;
325N/A }
325N/A
325N/A outerParticle = p;
325N/A t.visit(this);
325N/A }
325N/A
325N/A /**
325N/A * This field points to the parent XSParticle.
325N/A * The value is only valid when we are processing XSTerm.
325N/A */
325N/A private XSParticle outerParticle;
325N/A
325N/A public void elementDecl(XSElementDecl decl) {
325N/A check(outerParticle);
325N/A mark(outerParticle);
325N/A }
325N/A
325N/A public void modelGroup(XSModelGroup mg) {
325N/A // choice gets mapped to a property
325N/A if(mg.getCompositor()== XSModelGroup.Compositor.CHOICE && builder.getGlobalBinding().isChoiceContentPropertyEnabled()) {
325N/A mark(outerParticle);
325N/A return;
325N/A }
325N/A
325N/A for( XSParticle child : mg.getChildren() )
325N/A particle(child);
325N/A }
325N/A
325N/A public void modelGroupDecl(XSModelGroupDecl decl) {
325N/A modelGroup(decl.getModelGroup());
325N/A }
325N/A
325N/A public void wildcard(XSWildcard wc) {
325N/A mark(outerParticle);
325N/A }
325N/A
325N/A void readSuperClass( CClassInfo ci ) {
325N/A cchecker.readSuperClass(ci);
325N/A }
325N/A
325N/A
325N/A
325N/A
325N/A /**
325N/A * Checks the name collision of a newly found particle.
325N/A */
325N/A private void check( XSParticle p ) {
325N/A if( collisionInfo==null )
325N/A collisionInfo = cchecker.check(p);
325N/A }
325N/A
325N/A /**
325N/A * Marks a particle that it's going to be mapped to a property.
325N/A */
325N/A private void mark( XSParticle p ) {
325N/A markedParticles.put(p,computeLabel(p));
325N/A }
325N/A
325N/A /**
325N/A * Marked particles.
325N/A *
325N/A * A map from XSParticle to its label.
325N/A */
325N/A public final Map<XSParticle,String> markedParticles = new HashMap<XSParticle,String>();
325N/A
325N/A
325N/A /**
325N/A * Checks name collisions among particles that belong to sequences.
325N/A */
325N/A private final class NameCollisionChecker {
325N/A
325N/A /**
325N/A * Checks the label conflict of a particle.
325N/A * This method shall be called for each marked particle.
325N/A *
325N/A * @return
325N/A * a description of a collision if a name collision is
325N/A * found. Otherwise null.
325N/A */
325N/A CollisionInfo check( XSParticle p ) {
325N/A // this can be used for particles with a property customization,
325N/A // which may not have element declaration as its term.
325N/A// // we only check particles with element declarations.
325N/A// _assert( p.getTerm().isElementDecl() );
325N/A
325N/A String label = computeLabel(p);
325N/A if( occupiedLabels.containsKey(label) ) {
325N/A // collide with occupied labels
325N/A return new CollisionInfo(label,p.getLocator(),
325N/A occupiedLabels.get(label).locator);
325N/A }
325N/A
325N/A for( XSParticle jp : particles ) {
325N/A if(!check( p, jp )) {
325N/A // problem was found. no need to check further
325N/A return new CollisionInfo( label, p.getLocator(), jp.getLocator() );
325N/A }
325N/A }
325N/A particles.add(p);
325N/A return null;
325N/A }
325N/A
325N/A /** List of particles reported through the check method. */
325N/A private final List<XSParticle> particles = new ArrayList<XSParticle>();
325N/A
325N/A /**
325N/A * Label names already used in the base type.
325N/A */
325N/A private final Map<String,CPropertyInfo> occupiedLabels = new HashMap<String,CPropertyInfo>();
325N/A
325N/A /**
325N/A * Checks the conflict of two particles.
325N/A * @return
325N/A * true if the check was successful.
325N/A */
325N/A private boolean check( XSParticle p1, XSParticle p2 ) {
325N/A return !computeLabel(p1).equals(computeLabel(p2));
325N/A }
325N/A
325N/A /**
325N/A * Reads fields of the super class and includes them
325N/A * to name collision tests.
325N/A */
325N/A void readSuperClass( CClassInfo base ) {
325N/A for( ; base!=null; base=base.getBaseClass() ) {
325N/A for( CPropertyInfo p : base.getProperties() )
325N/A occupiedLabels.put(p.getName(true),p);
325N/A }
325N/A }
325N/A }
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A /** Keep the computed label names for particles. */
325N/A private final Map<XSParticle,String> labelCache = new Hashtable<XSParticle,String>();
325N/A
325N/A /**
325N/A * Hides the computeLabel method of the outer class
325N/A * and adds caching.
325N/A */
325N/A private String computeLabel( XSParticle p ) {
325N/A String label = labelCache.get(p);
325N/A if(label==null)
325N/A labelCache.put( p, label=DefaultParticleBinder.this.computeLabel(p) );
325N/A return label;
325N/A }
325N/A }
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A
325N/A /**
325N/A * Builds properties by using the result computed by Checker
325N/A */
325N/A private final class Builder implements XSTermVisitor {
325N/A Builder( Map<XSParticle,String> markedParticles ) {
325N/A this.markedParticles = markedParticles;
325N/A }
325N/A
325N/A /** All marked particles. */
325N/A private final Map<XSParticle,String/*label*/> markedParticles;
325N/A
325N/A /**
325N/A * When we are visiting inside an optional particle, this flag
325N/A * is set to true.
325N/A *
325N/A * <p>
325N/A * This allows us to correctly generate primitive/boxed types.
325N/A */
325N/A private boolean insideOptionalParticle;
325N/A
325N/A
325N/A /** Returns true if a particle is marked. */
325N/A private boolean marked( XSParticle p ) {
325N/A return markedParticles.containsKey(p);
325N/A }
325N/A /** Gets a label of a particle. */
325N/A private String getLabel( XSParticle p ) {
325N/A return markedParticles.get(p);
325N/A }
325N/A
325N/A public void particle( XSParticle p ) {
325N/A XSTerm t = p.getTerm();
325N/A
325N/A if(marked(p)) {
325N/A BIProperty cust = BIProperty.getCustomization(p);
325N/A CPropertyInfo prop = cust.createElementOrReferenceProperty(
325N/A getLabel(p), false, p, RawTypeSetBuilder.build(p,insideOptionalParticle));
325N/A getCurrentBean().addProperty(prop);
325N/A } else {
325N/A // repeated model groups should have been marked already
325N/A assert !p.isRepeated();
325N/A
325N/A boolean oldIOP = insideOptionalParticle;
325N/A insideOptionalParticle |= BigInteger.ZERO.equals(p.getMinOccurs());
325N/A // this is an unmarked particle
325N/A t.visit(this);
325N/A insideOptionalParticle = oldIOP;
325N/A }
325N/A }
325N/A
325N/A public void elementDecl( XSElementDecl e ) {
325N/A // because the corresponding particle must be marked.
325N/A assert false;
325N/A }
325N/A
325N/A public void wildcard( XSWildcard wc ) {
325N/A // because the corresponding particle must be marked.
325N/A assert false;
325N/A }
325N/A
325N/A public void modelGroupDecl( XSModelGroupDecl decl ) {
325N/A modelGroup(decl.getModelGroup());
325N/A }
325N/A
325N/A public void modelGroup( XSModelGroup mg ) {
325N/A boolean oldIOP = insideOptionalParticle;
325N/A insideOptionalParticle |= mg.getCompositor()==XSModelGroup.CHOICE;
325N/A
325N/A for( XSParticle p : mg.getChildren())
325N/A particle(p);
325N/A
325N/A insideOptionalParticle = oldIOP;
325N/A }
325N/A }
325N/A}