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