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;
325N/A
325N/Aimport java.util.HashSet;
325N/Aimport java.util.List;
325N/Aimport java.util.Set;
325N/A
325N/Aimport javax.activation.MimeType;
325N/A
325N/Aimport com.sun.tools.internal.xjc.model.CElementPropertyInfo;
325N/Aimport static com.sun.tools.internal.xjc.model.CElementPropertyInfo.CollectionMode.*;
325N/Aimport com.sun.tools.internal.xjc.model.CReferencePropertyInfo;
325N/Aimport com.sun.tools.internal.xjc.model.CTypeRef;
325N/Aimport com.sun.tools.internal.xjc.model.Multiplicity;
325N/Aimport com.sun.tools.internal.xjc.model.nav.NType;
325N/Aimport com.sun.xml.internal.bind.v2.model.core.Element;
325N/Aimport com.sun.xml.internal.bind.v2.model.core.ID;
325N/Aimport java.math.BigInteger;
325N/A
325N/A/**
325N/A * Set of {@link Ref}.
325N/A *
325N/A * @author Kohsuke Kawaguchi
325N/A */
325N/Apublic final class RawTypeSet {
325N/A
325N/A
325N/A public final Set<Ref> refs;
325N/A
325N/A /**
325N/A * True if this type set can form references to types.
325N/A */
325N/A public final Mode canBeTypeRefs;
325N/A
325N/A /**
325N/A * The occurence of the whole references.
325N/A */
325N/A public final Multiplicity mul;
325N/A
325N/A // computed inside canBeTypeRefs()
325N/A private CElementPropertyInfo.CollectionMode collectionMode;
325N/A
325N/A /**
325N/A * Should be called from one of the raw type set builders.
325N/A */
325N/A public RawTypeSet( Set<Ref> refs, Multiplicity m ) {
325N/A this.refs = refs;
325N/A mul = m;
325N/A canBeTypeRefs = canBeTypeRefs();
325N/A }
325N/A
325N/A public CElementPropertyInfo.CollectionMode getCollectionMode() {
325N/A return collectionMode;
325N/A }
325N/A
325N/A public boolean isRequired() {
325N/A return mul.min.compareTo(BigInteger.ZERO) == 1;
325N/A }
325N/A
325N/A
325N/A /**
325N/A * Represents the possible binding option for this {@link RawTypeSet}.
325N/A */
325N/A public enum Mode {
325N/A /**
325N/A * This {@link RawTypeSet} can be either an reference property or
325N/A * an element property, and XJC recommends element property.
325N/A */
325N/A SHOULD_BE_TYPEREF(0),
325N/A /**
325N/A * This {@link RawTypeSet} can be either an reference property or
325N/A * an element property, and XJC recommends reference property.
325N/A */
325N/A CAN_BE_TYPEREF(1),
325N/A /**
325N/A * This {@link RawTypeSet} can be only bound to a reference property.
325N/A */
325N/A MUST_BE_REFERENCE(2);
325N/A
325N/A private final int rank;
325N/A
325N/A Mode(int rank) {
325N/A this.rank = rank;
325N/A }
325N/A
325N/A Mode or(Mode that) {
325N/A switch(Math.max(this.rank,that.rank)) {
325N/A case 0: return SHOULD_BE_TYPEREF;
325N/A case 1: return CAN_BE_TYPEREF;
325N/A case 2: return MUST_BE_REFERENCE;
325N/A }
325N/A throw new AssertionError();
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Returns true if {@link #refs} can form refs of types.
325N/A *
325N/A * If there are multiple {@link Ref}s with the same type,
325N/A * we cannot make them into type refs. Or if any of the {@link Ref}
325N/A * says they cannot be in type refs, we cannot do that either.
325N/A *
325N/A * TODO: just checking if the refs are the same is not suffice.
325N/A * If two refs derive from each other, they cannot form a list of refs
325N/A * (because of a possible ambiguity).
325N/A */
325N/A private Mode canBeTypeRefs() {
325N/A Set<NType> types = new HashSet<NType>();
325N/A
325N/A collectionMode = mul.isAtMostOnce()?NOT_REPEATED:REPEATED_ELEMENT;
325N/A
325N/A // the way we compute this is that we start from the most optimistic value,
325N/A // and then gradually degrade as we find something problematic.
325N/A Mode mode = Mode.SHOULD_BE_TYPEREF;
325N/A
325N/A for( Ref r : refs ) {
325N/A mode = mode.or(r.canBeType(this));
325N/A if(mode== Mode.MUST_BE_REFERENCE)
325N/A return mode; // no need to continue the processing
325N/A
325N/A if(!types.add(r.toTypeRef(null).getTarget().getType()))
325N/A return Mode.MUST_BE_REFERENCE; // collision
325N/A if(r.isListOfValues()) {
325N/A if(refs.size()>1 || !mul.isAtMostOnce())
325N/A return Mode.MUST_BE_REFERENCE; // restriction on @XmlList
325N/A collectionMode = REPEATED_VALUE;
325N/A }
325N/A }
325N/A return mode;
325N/A }
325N/A
325N/A
325N/A
325N/A
325N/A public void addTo(CElementPropertyInfo prop) {
325N/A assert canBeTypeRefs!= Mode.MUST_BE_REFERENCE;
325N/A if(mul.isZero())
325N/A return; // the property can't have any value
325N/A
325N/A List<CTypeRef> dst = prop.getTypes();
325N/A for( Ref t : refs )
325N/A dst.add(t.toTypeRef(prop));
325N/A }
325N/A
325N/A public void addTo(CReferencePropertyInfo prop) {
325N/A if(mul.isZero())
325N/A return; // the property can't have any value
325N/A for( Ref t : refs )
325N/A t.toElementRef(prop);
325N/A }
325N/A
325N/A public ID id() {
325N/A for( Ref t : refs ) {
325N/A ID id = t.id();
325N/A if(id!=ID.NONE) return id;
325N/A }
325N/A return ID.NONE;
325N/A }
325N/A
325N/A public MimeType getExpectedMimeType() {
325N/A for( Ref t : refs ) {
325N/A MimeType mt = t.getExpectedMimeType();
325N/A if(mt!=null) return mt;
325N/A }
325N/A return null;
325N/A }
325N/A
325N/A
325N/A /**
325N/A * A reference to something.
325N/A *
325N/A * <p>
325N/A * A {@link Ref} can be either turned into {@link CTypeRef} to form
325N/A * an element property, or {@link Element} to form a reference property.
325N/A */
325N/A public static abstract class Ref {
325N/A /**
325N/A * @param ep
325N/A * the property to which the returned {@link CTypeRef} will be
325N/A * added to.
325N/A */
325N/A protected abstract CTypeRef toTypeRef(CElementPropertyInfo ep);
325N/A protected abstract void toElementRef(CReferencePropertyInfo prop);
325N/A /**
325N/A * Can this {@link Ref} be a type ref?
325N/A * @return false to veto.
325N/A * @param parent
325N/A */
325N/A protected abstract Mode canBeType(RawTypeSet parent);
325N/A protected abstract boolean isListOfValues();
325N/A /**
325N/A * When this {@link RawTypeSet} binds to a {@link CElementPropertyInfo},
325N/A * this method is used to determine if the property is ID or not.
325N/A */
325N/A protected abstract ID id();
325N/A
325N/A /**
325N/A * When this {@link RawTypeSet} binds to a {@link CElementPropertyInfo},
325N/A * this method is used to determine if the property has an associated expected MIME type or not.
325N/A */
325N/A protected MimeType getExpectedMimeType() { return null; }
325N/A }
325N/A}