001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.tools.xjc.model;
038:
039: import java.util.ArrayList;
040: import java.util.Collection;
041: import java.util.HashSet;
042: import java.util.Iterator;
043: import java.util.List;
044: import java.util.Set;
045:
046: import javax.xml.bind.annotation.XmlElement;
047: import javax.xml.bind.annotation.XmlID;
048: import javax.xml.bind.annotation.XmlIDREF;
049: import javax.xml.bind.annotation.XmlRootElement;
050: import javax.xml.namespace.QName;
051:
052: import com.sun.codemodel.JClass;
053: import com.sun.codemodel.JCodeModel;
054: import com.sun.codemodel.JPackage;
055: import com.sun.istack.Nullable;
056: import com.sun.tools.xjc.model.nav.NClass;
057: import com.sun.tools.xjc.model.nav.NType;
058: import com.sun.tools.xjc.outline.Aspect;
059: import com.sun.tools.xjc.outline.Outline;
060: import com.sun.xml.bind.v2.model.core.ClassInfo;
061: import com.sun.xml.bind.v2.model.core.Element;
062: import com.sun.xml.xsom.XSComponent;
063:
064: import org.xml.sax.Locator;
065:
066: /**
067: * Mutable {@link ClassInfo} represenatation.
068: *
069: * <p>
070: * Schema parsers build these objects.
071: *
072: * @author Kohsuke Kawaguchi
073: */
074: public final class CClassInfo extends AbstractCElement implements
075: ClassInfo<NType, NClass>, CClassInfoParent, CClass, NClass {
076:
077: @XmlIDREF
078: private CClass baseClass;
079:
080: /**
081: * List of all subclasses, together with {@link #nextSibling}.
082: *
083: * If this class has no sub-class, this field is null. Otherwise,
084: * this field points to a sub-class of this class. From there you can enumerate
085: * all the sub-classes by using {@link #nextSibling}.
086: */
087: private CClassInfo firstSubclass;
088:
089: /**
090: * @see #firstSubclass
091: */
092: private CClassInfo nextSibling = null;
093:
094: /**
095: * @see #getTypeName()
096: */
097: private final QName typeName;
098:
099: /**
100: * If this class also gets {@link XmlRootElement}, the class name.
101: */
102: private final @Nullable
103: QName elementName;
104:
105: private boolean isOrdered = true;
106:
107: private final List<CPropertyInfo> properties = new ArrayList<CPropertyInfo>();
108:
109: /**
110: * TODO: revisit this design.
111: * we should at least do a basic encapsulation to avoid careless
112: * mistakes. Maybe we should even differ the javadoc generation
113: * by queueing runners.
114: */
115: public String javadoc;
116:
117: @XmlIDREF
118: private final CClassInfoParent parent;
119:
120: /**
121: * short name.
122: */
123: public final String shortName;
124:
125: /**
126: * Optional user-specified implementation override class.
127: */
128: private @Nullable
129: String implClass;
130:
131: /**
132: * The {@link Model} object to which this bean belongs.
133: */
134: public final Model model;
135:
136: /**
137: * @see #hasAttributeWildcard()
138: */
139: private boolean hasAttributeWildcard;
140:
141: public CClassInfo(Model model, JPackage pkg, String shortName,
142: Locator location, QName typeName, QName elementName,
143: XSComponent source, CCustomizations customizations) {
144: this (model, model.getPackage(pkg), shortName, location,
145: typeName, elementName, source, customizations);
146: }
147:
148: public CClassInfo(Model model, CClassInfoParent p,
149: String shortName, Locator location, QName typeName,
150: QName elementName, XSComponent source,
151: CCustomizations customizations) {
152: super (model, source, location, customizations);
153: this .model = model;
154: this .parent = p;
155: this .shortName = model.allocator.assignClassName(parent,
156: shortName);
157: this .typeName = typeName;
158: this .elementName = elementName;
159:
160: model.add(this );
161: }
162:
163: public CClassInfo(Model model, JCodeModel cm, String fullName,
164: Locator location, QName typeName, QName elementName,
165: XSComponent source, CCustomizations customizations) {
166: super (model, source, location, customizations);
167: this .model = model;
168: int idx = fullName.indexOf('.');
169: if (idx < 0) {
170: this .parent = model.getPackage(cm.rootPackage());
171: this .shortName = model.allocator.assignClassName(parent,
172: fullName);
173: } else {
174: this .parent = model.getPackage(cm._package(fullName
175: .substring(0, idx)));
176: this .shortName = model.allocator.assignClassName(parent,
177: fullName.substring(idx + 1));
178: }
179: this .typeName = typeName;
180: this .elementName = elementName;
181:
182: model.add(this );
183: }
184:
185: public boolean hasAttributeWildcard() {
186: return hasAttributeWildcard;
187: }
188:
189: public void hasAttributeWildcard(boolean hasAttributeWildcard) {
190: this .hasAttributeWildcard = hasAttributeWildcard;
191: }
192:
193: public boolean hasSubClasses() {
194: return firstSubclass != null;
195: }
196:
197: /**
198: * Returns true iff a new attribute wildcard property needs to be
199: * declared on this class.
200: */
201: public boolean declaresAttributeWildcard() {
202: return hasAttributeWildcard && !inheritsAttributeWildcard();
203: }
204:
205: /**
206: * Returns true iff this class inherits a wildcard attribute property
207: * from its ancestor classes.
208: */
209: public boolean inheritsAttributeWildcard() {
210: for (CClassInfo c = getBaseClass(); c != null; c = c
211: .getBaseClass()) {
212: if (c.hasAttributeWildcard)
213: return true;
214: }
215: return false;
216: }
217:
218: public NClass getClazz() {
219: return this ;
220: }
221:
222: public CClassInfo getScope() {
223: return null;
224: }
225:
226: @XmlID
227: public String getName() {
228: return fullName();
229: }
230:
231: /**
232: * Returns the "squeezed name" of this bean token.
233: * <p>
234: * The squeezed name of a bean is the concatenation of
235: * the names of its outer classes and itself.
236: * <p>
237: * Thus if the bean is "org.acme.foo.Bean", then the squeezed name is "Bean",
238: * if the bean is "org.acme.foo.Outer1.Outer2.Bean", then "Outer1Outer2Bean".
239: * <p>
240: * This is used by the code generator
241: */
242: @XmlElement
243: public String getSqueezedName() {
244: return calcSqueezedName.onBean(this );
245: }
246:
247: private static final CClassInfoParent.Visitor<String> calcSqueezedName = new Visitor<String>() {
248: public String onBean(CClassInfo bean) {
249: return bean.parent.accept(this ) + bean.shortName;
250: }
251:
252: public String onElement(CElementInfo element) {
253: return element.parent.accept(this ) + element.shortName();
254: }
255:
256: public String onPackage(JPackage pkg) {
257: return "";
258: }
259: };
260:
261: /**
262: * Returns a mutable list.
263: */
264: public List<CPropertyInfo> getProperties() {
265: return properties;
266: }
267:
268: public boolean hasValueProperty() {
269: throw new UnsupportedOperationException();
270: }
271:
272: /**
273: * Gets a propery by name.
274: */
275: public CPropertyInfo getProperty(String name) {
276: // TODO: does this method need to be fast?
277: for (CPropertyInfo p : properties)
278: if (p.getName(false).equals(name))
279: return p;
280: return null;
281: }
282:
283: public boolean hasProperties() {
284: return !getProperties().isEmpty();
285: }
286:
287: public boolean isElement() {
288: return elementName != null;
289: }
290:
291: /**
292: * Guaranteed to return this.
293: */
294: @Deprecated
295: public CNonElement getInfo() {
296: return this ;
297: }
298:
299: public Element<NType, NClass> asElement() {
300: if (isElement())
301: return this ;
302: else
303: return null;
304: }
305:
306: public boolean isOrdered() {
307: return isOrdered;
308: }
309:
310: /**
311: * @deprecated
312: * if you are calling this method directly, you must be doing something wrong.
313: */
314: public boolean isFinal() {
315: return false;
316: }
317:
318: public void setOrdered(boolean value) {
319: isOrdered = value;
320: }
321:
322: public QName getElementName() {
323: return elementName;
324: }
325:
326: public QName getTypeName() {
327: return typeName;
328: }
329:
330: public boolean isSimpleType() {
331: throw new UnsupportedOperationException();
332: }
333:
334: /**
335: * Returns the FQCN of this bean.
336: */
337: public String fullName() {
338: String r = parent.fullName();
339: if (r.length() == 0)
340: return shortName;
341: else
342: return r + '.' + shortName;
343: }
344:
345: public CClassInfoParent parent() {
346: return parent;
347: }
348:
349: public void setUserSpecifiedImplClass(String implClass) {
350: assert this .implClass == null;
351: assert implClass != null;
352: this .implClass = implClass;
353: }
354:
355: public String getUserSpecifiedImplClass() {
356: return implClass;
357: }
358:
359: /**
360: * Adds a new property.
361: */
362: public void addProperty(CPropertyInfo prop) {
363: if (prop.ref().isEmpty())
364: // this property isn't contributing anything
365: // this happens when you try to map an empty sequence to a property
366: return;
367: prop.setParent(this );
368: properties.add(prop);
369: }
370:
371: /**
372: * This method accepts both {@link CClassInfo} (which means the base class
373: * is also generated), or {@link CClassRef} (which means the base class is
374: * already generated and simply referenced.)
375: *
376: * The latter is treated somewhat special --- from the rest of the model
377: * this external base class is invisible. This modeling might need more
378: * thoughts to get right.
379: */
380: public void setBaseClass(CClass base) {
381: assert baseClass == null;
382: assert base != null;
383: baseClass = base;
384:
385: assert nextSibling == null;
386: if (base instanceof CClassInfo) {
387: CClassInfo realBase = (CClassInfo) base;
388: this .nextSibling = realBase.firstSubclass;
389: realBase.firstSubclass = this ;
390: }
391: }
392:
393: /**
394: * This inherited version returns null if this class extends from {@link CClassRef}.
395: *
396: * @see #getRefBaseClass()
397: */
398: public CClassInfo getBaseClass() {
399: if (baseClass instanceof CClassInfo) {
400: return (CClassInfo) baseClass;
401: } else {
402: return null;
403: }
404: }
405:
406: public CClassRef getRefBaseClass() {
407: if (baseClass instanceof CClassRef) {
408: return (CClassRef) baseClass;
409: } else {
410: return null;
411: }
412: }
413:
414: /**
415: * Enumerates all the sub-classes of this class.
416: */
417: public Iterator<CClassInfo> listSubclasses() {
418: return new Iterator<CClassInfo>() {
419: CClassInfo cur = firstSubclass;
420:
421: public boolean hasNext() {
422: return cur != null;
423: }
424:
425: public CClassInfo next() {
426: CClassInfo r = cur;
427: cur = cur.nextSibling;
428: return r;
429: }
430:
431: public void remove() {
432: throw new UnsupportedOperationException();
433: }
434: };
435: }
436:
437: public CClassInfo getSubstitutionHead() {
438: CClassInfo c = getBaseClass();
439: while (c != null && !c.isElement())
440: c = c.getBaseClass();
441: return c;
442: }
443:
444: /**
445: * Interfaces to be implemented.
446: * Lazily constructed.
447: */
448: private Set<JClass> _implements = null;
449:
450: public void _implements (JClass c) {
451: if (_implements == null)
452: _implements = new HashSet<JClass>();
453: _implements .add(c);
454: }
455:
456: /** Constructor declarations. array of {@link Constructor}s. */
457: private final List<Constructor> constructors = new ArrayList<Constructor>(
458: 1);
459:
460: /** Creates a new constructor declaration and adds it. */
461: public void addConstructor(String... fieldNames) {
462: constructors.add(new Constructor(fieldNames));
463: }
464:
465: /** list all constructor declarations. */
466: public Collection<? extends Constructor> getConstructors() {
467: return constructors;
468: }
469:
470: public final <T> T accept(Visitor<T> visitor) {
471: return visitor.onBean(this );
472: }
473:
474: public JPackage getOwnerPackage() {
475: return parent.getOwnerPackage();
476: }
477:
478: public final NClass getType() {
479: return this ;
480: }
481:
482: public final JClass toType(Outline o, Aspect aspect) {
483: switch (aspect) {
484: case IMPLEMENTATION:
485: return o.getClazz(this ).implRef;
486: case EXPOSED:
487: return o.getClazz(this ).ref;
488: default:
489: throw new IllegalStateException();
490: }
491: }
492:
493: public boolean isBoxedType() {
494: return false;
495: }
496:
497: public String toString() {
498: return fullName();
499: }
500: }
|