001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.internal.xjc.model;
027:
028: import java.util.Collection;
029: import java.util.Collections;
030: import java.util.HashSet;
031: import java.util.List;
032: import java.util.Set;
033:
034: import javax.xml.bind.JAXBElement;
035: import javax.xml.bind.annotation.XmlElement;
036: import javax.xml.bind.annotation.XmlTransient;
037: import javax.xml.namespace.QName;
038:
039: import com.sun.codemodel.internal.JPackage;
040: import com.sun.codemodel.internal.JType;
041: import com.sun.tools.internal.xjc.model.nav.NClass;
042: import com.sun.tools.internal.xjc.model.nav.NType;
043: import com.sun.tools.internal.xjc.model.nav.NavigatorImpl;
044: import com.sun.tools.internal.xjc.outline.Aspect;
045: import com.sun.tools.internal.xjc.outline.Outline;
046: import com.sun.xml.internal.bind.v2.model.core.ElementInfo;
047: import com.sun.xml.internal.xsom.XSComponent;
048: import com.sun.xml.internal.xsom.XmlString;
049:
050: import org.xml.sax.Locator;
051:
052: import static com.sun.tools.internal.xjc.model.CElementPropertyInfo.CollectionMode.REPEATED_VALUE;
053: import static com.sun.tools.internal.xjc.model.CElementPropertyInfo.CollectionMode.NOT_REPEATED;
054:
055: /**
056: * {@link ElementInfo} implementation for the compile-time model.
057: *
058: * <p>
059: * As an NType, it represents the Java representation of this element
060: * (either JAXBElement<T> or Foo).
061: *
062: * @author Kohsuke Kawaguchi
063: */
064: public final class CElementInfo extends AbstractCTypeInfoImpl implements
065: ElementInfo<NType, NClass>, CElement, CTypeInfo, NType,
066: CClassInfoParent {
067:
068: private final QName tagName;
069:
070: /**
071: * Represents {@code JAXBElement<ContentType>}.
072: */
073: private NType type;
074:
075: /**
076: * If this element produces its own class, the short name of that class.
077: * Otherwise null.
078: */
079: private String className;
080:
081: /**
082: * If this element is global, the element info is considered to be
083: * package-level, and this points to the package in which this element
084: * lives in.
085: *
086: * <p>
087: * For local elements, this points to the parent {@link CClassInfo}.
088: */
089: public final CClassInfoParent parent;
090:
091: /**
092: * The location in the source file where this class was declared.
093: */
094: @XmlTransient
095: private final Locator location;
096:
097: private boolean isAbstract;
098:
099: private CElementInfo substitutionHead;
100:
101: /**
102: * Lazily computed.
103: */
104: private Set<CElementInfo> substitutionMembers;
105:
106: /**
107: * {@link Model} that owns this object.
108: */
109: private final Model model;
110:
111: private CElementPropertyInfo property;
112:
113: /**
114: * Creates an element in the given parent.
115: *
116: * <p>
117: * When using this construction, {@link #initContentType(TypeUse, XSComponent, XmlString)}
118: * must not be invoked.
119: */
120: public CElementInfo(Model model, QName tagName,
121: CClassInfoParent parent, TypeUse contentType,
122: XmlString defaultValue, XSComponent source,
123: CCustomizations customizations, Locator location) {
124: super (model, source, customizations);
125: this .tagName = tagName;
126: this .model = model;
127: this .parent = parent;
128: this .location = location;
129: if (contentType != null)
130: initContentType(contentType, source, defaultValue);
131:
132: model.add(this );
133: }
134:
135: /**
136: * Creates an element with a class in the given parent.
137: *
138: * <p>
139: * When using this construction, the caller must use
140: * {@link #initContentType(TypeUse, XSComponent, XmlString)} to fill in the content type
141: * later.
142: *
143: * This is to avoid a circular model construction dependency between buidling a type
144: * inside an element and element itself. To build a content type, you need to have
145: * {@link CElementInfo} for a parent, so we can't take it as a constructor parameter.
146: */
147: public CElementInfo(Model model, QName tagName,
148: CClassInfoParent parent, String className,
149: CCustomizations customizations, Locator location) {
150: this (model, tagName, parent, null, null, null, customizations,
151: location);
152: this .className = className;
153: }
154:
155: public void initContentType(TypeUse contentType,
156: XSComponent source, XmlString defaultValue) {
157: assert this .property == null; // must not be called twice
158:
159: this .property = new CElementPropertyInfo("Value", contentType
160: .isCollection() ? REPEATED_VALUE : NOT_REPEATED,
161: contentType.idUse(), contentType.getExpectedMimeType(),
162: source, null, location, true);
163: this .property.setAdapter(contentType.getAdapterUse());
164: property.getTypes().add(
165: new CTypeRef((CNonElement) contentType.getInfo(),
166: tagName, true, defaultValue));
167: this .type = NavigatorImpl.createParameterizedType(
168: NavigatorImpl.theInstance.ref(JAXBElement.class),
169: getContentInMemoryType());
170: }
171:
172: public final String getDefaultValue() {
173: return getProperty().getTypes().get(0).getDefaultValue();
174: }
175:
176: public final JPackage _package() {
177: return parent.getOwnerPackage();
178: }
179:
180: public CNonElement getContentType() {
181: return getProperty().ref().get(0);
182: }
183:
184: public NType getContentInMemoryType() {
185: if (getProperty().getAdapter() == null) {
186: NType itemType = getContentType().getType();
187: if (!property.isCollection())
188: return itemType;
189:
190: return NavigatorImpl.createParameterizedType(List.class,
191: itemType);
192: } else {
193: return getProperty().getAdapter().customType;
194: }
195: }
196:
197: public CElementPropertyInfo getProperty() {
198: return property;
199: }
200:
201: public CClassInfo getScope() {
202: if (parent instanceof CClassInfo)
203: return (CClassInfo) parent;
204: return null;
205: }
206:
207: /**
208: * @deprecated why are you calling a method that returns this?
209: */
210: public NType getType() {
211: return this ;
212: }
213:
214: public QName getElementName() {
215: return tagName;
216: }
217:
218: public JType toType(Outline o, Aspect aspect) {
219: if (className == null)
220: return type.toType(o, aspect);
221: else
222: return o.getElement(this ).implClass;
223: }
224:
225: /**
226: * Returns the "squeezed name" of this element.
227: *
228: * @see CClassInfo#getSqueezedName()
229: */
230: @XmlElement
231: public String getSqueezedName() {
232: StringBuilder b = new StringBuilder();
233: CClassInfo s = getScope();
234: if (s != null)
235: b.append(s.getSqueezedName());
236: if (className != null)
237: b.append(className);
238: else
239: b.append(model.getNameConverter().toClassName(
240: tagName.getLocalPart()));
241: return b.toString();
242: }
243:
244: public void setAbstract() {
245: isAbstract = true;
246: }
247:
248: public boolean isAbstract() {
249: return isAbstract;
250: }
251:
252: public CElementInfo getSubstitutionHead() {
253: return substitutionHead;
254: }
255:
256: public Collection<CElementInfo> getSubstitutionMembers() {
257: if (substitutionMembers == null)
258: return Collections.emptyList();
259: else
260: return substitutionMembers;
261: }
262:
263: public void setSubstitutionHead(CElementInfo substitutionHead) {
264: // don't set it twice
265: assert this .substitutionHead == null;
266: assert substitutionHead != null;
267: this .substitutionHead = substitutionHead;
268:
269: if (substitutionHead.substitutionMembers == null)
270: substitutionHead.substitutionMembers = new HashSet<CElementInfo>();
271: substitutionHead.substitutionMembers.add(this );
272: }
273:
274: public boolean isBoxedType() {
275: return false;
276: }
277:
278: public String fullName() {
279: if (className == null)
280: return type.fullName();
281: else {
282: String r = parent.fullName();
283: if (r.length() == 0)
284: return className;
285: else
286: return r + '.' + className;
287: }
288: }
289:
290: public <T> T accept(Visitor<T> visitor) {
291: return visitor.onElement(this );
292: }
293:
294: public JPackage getOwnerPackage() {
295: return parent.getOwnerPackage();
296: }
297:
298: public String shortName() {
299: return className;
300: }
301:
302: /**
303: * True if this element has its own class
304: * (as opposed to be represented as an instance of {@link JAXBElement}.
305: */
306: public boolean hasClass() {
307: return className != null;
308: }
309:
310: public Locator getLocator() {
311: return location;
312: }
313: }
|