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 26package com.sun.tools.internal.xjc.reader; 27 28import java.util.HashSet; 29import java.util.List; 30import java.util.Set; 31 32import javax.activation.MimeType; 33 34import com.sun.tools.internal.xjc.model.CElementPropertyInfo; 35import static com.sun.tools.internal.xjc.model.CElementPropertyInfo.CollectionMode.*; 36import com.sun.tools.internal.xjc.model.CReferencePropertyInfo; 37import com.sun.tools.internal.xjc.model.CTypeRef; 38import com.sun.tools.internal.xjc.model.Multiplicity; 39import com.sun.tools.internal.xjc.model.nav.NType; 40import com.sun.xml.internal.bind.v2.model.core.Element; 41import com.sun.xml.internal.bind.v2.model.core.ID; 42import java.math.BigInteger; 43 44/** 45 * Set of {@link Ref}. 46 * 47 * @author Kohsuke Kawaguchi 48 */ 49public final class RawTypeSet { 50 51 52 public final Set<Ref> refs; 53 54 /** 55 * True if this type set can form references to types. 56 */ 57 public final Mode canBeTypeRefs; 58 59 /** 60 * The occurence of the whole references. 61 */ 62 public final Multiplicity mul; 63 64 // computed inside canBeTypeRefs() 65 private CElementPropertyInfo.CollectionMode collectionMode; 66 67 /** 68 * Should be called from one of the raw type set builders. 69 */ 70 public RawTypeSet( Set<Ref> refs, Multiplicity m ) { 71 this.refs = refs; 72 mul = m; 73 canBeTypeRefs = canBeTypeRefs(); 74 } 75 76 public CElementPropertyInfo.CollectionMode getCollectionMode() { 77 return collectionMode; 78 } 79 80 public boolean isRequired() { 81 return mul.min.compareTo(BigInteger.ZERO) == 1; 82 } 83 84 85 /** 86 * Represents the possible binding option for this {@link RawTypeSet}. 87 */ 88 public enum Mode { 89 /** 90 * This {@link RawTypeSet} can be either an reference property or 91 * an element property, and XJC recommends element property. 92 */ 93 SHOULD_BE_TYPEREF(0), 94 /** 95 * This {@link RawTypeSet} can be either an reference property or 96 * an element property, and XJC recommends reference property. 97 */ 98 CAN_BE_TYPEREF(1), 99 /** 100 * This {@link RawTypeSet} can be only bound to a reference property. 101 */ 102 MUST_BE_REFERENCE(2); 103 104 private final int rank; 105 106 Mode(int rank) { 107 this.rank = rank; 108 } 109 110 Mode or(Mode that) { 111 switch(Math.max(this.rank,that.rank)) { 112 case 0: return SHOULD_BE_TYPEREF; 113 case 1: return CAN_BE_TYPEREF; 114 case 2: return MUST_BE_REFERENCE; 115 } 116 throw new AssertionError(); 117 } 118 } 119 120 /** 121 * Returns true if {@link #refs} can form refs of types. 122 * 123 * If there are multiple {@link Ref}s with the same type, 124 * we cannot make them into type refs. Or if any of the {@link Ref} 125 * says they cannot be in type refs, we cannot do that either. 126 * 127 * TODO: just checking if the refs are the same is not suffice. 128 * If two refs derive from each other, they cannot form a list of refs 129 * (because of a possible ambiguity). 130 */ 131 private Mode canBeTypeRefs() { 132 Set<NType> types = new HashSet<NType>(); 133 134 collectionMode = mul.isAtMostOnce()?NOT_REPEATED:REPEATED_ELEMENT; 135 136 // the way we compute this is that we start from the most optimistic value, 137 // and then gradually degrade as we find something problematic. 138 Mode mode = Mode.SHOULD_BE_TYPEREF; 139 140 for( Ref r : refs ) { 141 mode = mode.or(r.canBeType(this)); 142 if(mode== Mode.MUST_BE_REFERENCE) 143 return mode; // no need to continue the processing 144 145 if(!types.add(r.toTypeRef(null).getTarget().getType())) 146 return Mode.MUST_BE_REFERENCE; // collision 147 if(r.isListOfValues()) { 148 if(refs.size()>1 || !mul.isAtMostOnce()) 149 return Mode.MUST_BE_REFERENCE; // restriction on @XmlList 150 collectionMode = REPEATED_VALUE; 151 } 152 } 153 return mode; 154 } 155 156 157 158 159 public void addTo(CElementPropertyInfo prop) { 160 assert canBeTypeRefs!= Mode.MUST_BE_REFERENCE; 161 if(mul.isZero()) 162 return; // the property can't have any value 163 164 List<CTypeRef> dst = prop.getTypes(); 165 for( Ref t : refs ) 166 dst.add(t.toTypeRef(prop)); 167 } 168 169 public void addTo(CReferencePropertyInfo prop) { 170 if(mul.isZero()) 171 return; // the property can't have any value 172 for( Ref t : refs ) 173 t.toElementRef(prop); 174 } 175 176 public ID id() { 177 for( Ref t : refs ) { 178 ID id = t.id(); 179 if(id!=ID.NONE) return id; 180 } 181 return ID.NONE; 182 } 183 184 public MimeType getExpectedMimeType() { 185 for( Ref t : refs ) { 186 MimeType mt = t.getExpectedMimeType(); 187 if(mt!=null) return mt; 188 } 189 return null; 190 } 191 192 193 /** 194 * A reference to something. 195 * 196 * <p> 197 * A {@link Ref} can be either turned into {@link CTypeRef} to form 198 * an element property, or {@link Element} to form a reference property. 199 */ 200 public static abstract class Ref { 201 /** 202 * @param ep 203 * the property to which the returned {@link CTypeRef} will be 204 * added to. 205 */ 206 protected abstract CTypeRef toTypeRef(CElementPropertyInfo ep); 207 protected abstract void toElementRef(CReferencePropertyInfo prop); 208 /** 209 * Can this {@link Ref} be a type ref? 210 * @return false to veto. 211 * @param parent 212 */ 213 protected abstract Mode canBeType(RawTypeSet parent); 214 protected abstract boolean isListOfValues(); 215 /** 216 * When this {@link RawTypeSet} binds to a {@link CElementPropertyInfo}, 217 * this method is used to determine if the property is ID or not. 218 */ 219 protected abstract ID id(); 220 221 /** 222 * When this {@link RawTypeSet} binds to a {@link CElementPropertyInfo}, 223 * this method is used to determine if the property has an associated expected MIME type or not. 224 */ 225 protected MimeType getExpectedMimeType() { return null; } 226 } 227} 228