1/* 2 * Copyright (c) 1997, 2015, 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.model; 27 28import java.util.Collection; 29import java.util.Collections; 30import java.util.HashSet; 31import java.util.List; 32import java.util.Set; 33 34import javax.xml.bind.JAXBElement; 35import javax.xml.bind.annotation.XmlElement; 36import javax.xml.namespace.QName; 37 38import com.sun.codemodel.internal.JPackage; 39import com.sun.codemodel.internal.JType; 40import com.sun.istack.internal.Nullable; 41import static com.sun.tools.internal.xjc.model.CElementPropertyInfo.CollectionMode.NOT_REPEATED; 42import static com.sun.tools.internal.xjc.model.CElementPropertyInfo.CollectionMode.REPEATED_VALUE; 43import com.sun.tools.internal.xjc.model.nav.NClass; 44import com.sun.tools.internal.xjc.model.nav.NType; 45import com.sun.tools.internal.xjc.model.nav.NavigatorImpl; 46import com.sun.tools.internal.xjc.outline.Aspect; 47import com.sun.tools.internal.xjc.outline.Outline; 48import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIInlineBinaryData; 49import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIFactoryMethod; 50import com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder; 51import com.sun.tools.internal.xjc.reader.Ring; 52import com.sun.xml.internal.bind.v2.model.core.ElementInfo; 53import com.sun.xml.internal.xsom.XSElementDecl; 54import com.sun.xml.internal.xsom.XmlString; 55 56import org.xml.sax.Locator; 57 58/** 59 * {@link ElementInfo} implementation for the compile-time model. 60 * 61 * <p> 62 * As an NType, it represents the Java representation of this element 63 * (either {@code JAXBElement<T>} or Foo). 64 * 65 * @author Kohsuke Kawaguchi 66 */ 67public final class CElementInfo extends AbstractCElement 68 implements ElementInfo<NType,NClass>, NType, CClassInfoParent { 69 70 private final QName tagName; 71 72 /** 73 * Represents {@code JAXBElement<ContentType>}. 74 */ 75 private NType type; 76 77 /** 78 * If this element produces its own class, the short name of that class. 79 * Otherwise null. 80 */ 81 private String className; 82 83 /** 84 * If this element is global, the element info is considered to be 85 * package-level, and this points to the package in which this element 86 * lives in. 87 * 88 * <p> 89 * For local elements, this points to the parent {@link CClassInfo}. 90 */ 91 public final CClassInfoParent parent; 92 93 private CElementInfo substitutionHead; 94 95 /** 96 * Lazily computed. 97 */ 98 private Set<CElementInfo> substitutionMembers; 99 100 /** 101 * {@link Model} that owns this object. 102 */ 103 private final Model model; 104 105 private CElementPropertyInfo property; 106 107 /** 108 * Custom {@link #getSqueezedName() squeezed name}, if any. 109 */ 110 private /*almost final*/ @Nullable String squeezedName; 111 112 /** 113 * Creates an element in the given parent. 114 * 115 * <p> 116 * When using this construction, {@link #initContentType(TypeUse, XSElementDecl, XmlString)} 117 * must not be invoked. 118 */ 119 public CElementInfo(Model model,QName tagName, CClassInfoParent parent, TypeUse contentType, XmlString defaultValue, XSElementDecl source, CCustomizations customizations, Locator location ) { 120 super(model,source,location,customizations); 121 this.tagName = tagName; 122 this.model = model; 123 this.parent = parent; 124 if(contentType!=null) 125 initContentType(contentType, source, defaultValue); 126 127 model.add(this); 128 } 129 130 /** 131 * Creates an element with a class in the given parent. 132 * 133 * <p> 134 * When using this construction, the caller must use 135 * {@link #initContentType(TypeUse, XSElementDecl, XmlString)} to fill in the content type 136 * later. 137 * 138 * This is to avoid a circular model construction dependency between buidling a type 139 * inside an element and element itself. To build a content type, you need to have 140 * {@link CElementInfo} for a parent, so we can't take it as a constructor parameter. 141 */ 142 public CElementInfo(Model model,QName tagName, CClassInfoParent parent, String className, CCustomizations customizations, Locator location ) { 143 this(model,tagName,parent,null,null,null,customizations,location); 144 this.className = className; 145 } 146 147 public void initContentType(TypeUse contentType, @Nullable XSElementDecl source, XmlString defaultValue) { 148 assert this.property==null; // must not be called twice 149 150 this.property = new CElementPropertyInfo("Value", 151 contentType.isCollection()?REPEATED_VALUE:NOT_REPEATED, 152 contentType.idUse(), 153 contentType.getExpectedMimeType(), 154 source,null,getLocator(),true); 155 this.property.setAdapter(contentType.getAdapterUse()); 156 BIInlineBinaryData.handle(source,property); 157 property.getTypes().add(new CTypeRef(contentType.getInfo(),tagName,CTypeRef.getSimpleTypeName(source), true,defaultValue)); 158 this.type = NavigatorImpl.createParameterizedType( 159 NavigatorImpl.theInstance.ref(JAXBElement.class), 160 getContentInMemoryType() ); 161 162 BIFactoryMethod factoryMethod = Ring.get(BGMBuilder.class).getBindInfo(source).get(BIFactoryMethod.class); 163 if(factoryMethod!=null) { 164 factoryMethod.markAsAcknowledged(); 165 this.squeezedName = factoryMethod.name; 166 } 167 168 } 169 170 public final String getDefaultValue() { 171 return getProperty().getTypes().get(0).getDefaultValue(); 172 } 173 174 public final JPackage _package() { 175 return parent.getOwnerPackage(); 176 } 177 178 public CNonElement getContentType() { 179 return getProperty().ref().get(0); 180 } 181 182 public NType getContentInMemoryType() { 183 if(getProperty().getAdapter()==null) { 184 NType itemType = getContentType().getType(); 185 if(!property.isCollection()) 186 return itemType; 187 188 return NavigatorImpl.createParameterizedType(List.class,itemType); 189 } else { 190 return getProperty().getAdapter().customType; 191 } 192 } 193 194 public CElementPropertyInfo getProperty() { 195 return property; 196 } 197 198 public CClassInfo getScope() { 199 if(parent instanceof CClassInfo) 200 return (CClassInfo)parent; 201 return null; 202 } 203 204 /** 205 * @deprecated why are you calling a method that returns this? 206 */ 207 public NType getType() { 208 return this; 209 } 210 211 public QName getElementName() { 212 return tagName; 213 } 214 215 public JType toType(Outline o, Aspect aspect) { 216 if(className==null) 217 return type.toType(o,aspect); 218 else 219 return o.getElement(this).implClass; 220 } 221 222 /** 223 * Returns the "squeezed name" of this element. 224 * 225 * @see CClassInfo#getSqueezedName() 226 */ 227 @XmlElement 228 public String getSqueezedName() { 229 if(squeezedName!=null) return squeezedName; 230 231 StringBuilder b = new StringBuilder(); 232 CClassInfo s = getScope(); 233 if(s!=null) 234 b.append(s.getSqueezedName()); 235 if(className!=null) 236 b.append(className); 237 else 238 b.append( model.getNameConverter().toClassName(tagName.getLocalPart())); 239 return b.toString(); 240 } 241 242 public CElementInfo getSubstitutionHead() { 243 return substitutionHead; 244 } 245 246 public Collection<CElementInfo> getSubstitutionMembers() { 247 if(substitutionMembers==null) 248 return Collections.emptyList(); 249 else 250 return substitutionMembers; 251 } 252 253 public void setSubstitutionHead(CElementInfo substitutionHead) { 254 // don't set it twice 255 assert this.substitutionHead==null; 256 assert substitutionHead!=null; 257 this.substitutionHead = substitutionHead; 258 259 if(substitutionHead.substitutionMembers==null) 260 substitutionHead.substitutionMembers = new HashSet<CElementInfo>(); 261 substitutionHead.substitutionMembers.add(this); 262 } 263 264 public boolean isBoxedType() { 265 return false; 266 } 267 268 public String fullName() { 269 if(className==null) 270 return type.fullName(); 271 else { 272 String r = parent.fullName(); 273 if(r.length()==0) return className; 274 else return r+'.'+className; 275 } 276 } 277 278 public <T> T accept(Visitor<T> visitor) { 279 return visitor.onElement(this); 280 } 281 282 public JPackage getOwnerPackage() { 283 return parent.getOwnerPackage(); 284 } 285 286 public String shortName() { 287 return className; 288 } 289 290 /** 291 * True if this element has its own class 292 * (as opposed to be represented as an instance of {@link JAXBElement}. 293 */ 294 public boolean hasClass() { 295 return className!=null; 296 } 297} 298