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.reader.xmlschema;
038:
039: import java.util.HashSet;
040: import java.util.Set;
041:
042: import javax.activation.MimeType;
043: import javax.xml.namespace.QName;
044:
045: import com.sun.tools.xjc.model.CAdapter;
046: import com.sun.tools.xjc.model.CClass;
047: import com.sun.tools.xjc.model.CClassInfo;
048: import com.sun.tools.xjc.model.CCustomizations;
049: import com.sun.tools.xjc.model.CElement;
050: import com.sun.tools.xjc.model.CElementInfo;
051: import com.sun.tools.xjc.model.CElementPropertyInfo;
052: import com.sun.tools.xjc.model.CReferencePropertyInfo;
053: import com.sun.tools.xjc.model.CTypeRef;
054: import com.sun.tools.xjc.model.Model;
055: import com.sun.tools.xjc.model.Multiplicity;
056: import com.sun.tools.xjc.model.TypeUse;
057: import com.sun.tools.xjc.reader.RawTypeSet;
058: import com.sun.tools.xjc.reader.Ring;
059: import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIDom;
060: import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIGlobalBinding;
061: import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIXSubstitutable;
062: import com.sun.xml.bind.v2.model.core.ID;
063: import com.sun.xml.bind.v2.model.core.WildcardMode;
064: import com.sun.xml.xsom.XSElementDecl;
065: import com.sun.xml.xsom.XSModelGroup;
066: import com.sun.xml.xsom.XSModelGroupDecl;
067: import com.sun.xml.xsom.XSParticle;
068: import com.sun.xml.xsom.XSWildcard;
069: import com.sun.xml.xsom.visitor.XSTermVisitor;
070:
071: /**
072: * Builds {@link RawTypeSet} for XML Schema.
073: *
074: * @author Kohsuke Kawaguchi
075: */
076: public class RawTypeSetBuilder implements XSTermVisitor {
077: /**
078: * @param optional
079: * if this whole property is optional due to the
080: * occurence constraints on ancestors, set this to true.
081: * this will prevent the primitive types to be generated.
082: */
083: public static RawTypeSet build(XSParticle p, boolean optional) {
084: RawTypeSetBuilder rtsb = new RawTypeSetBuilder();
085: rtsb.particle(p);
086: Multiplicity mul = MultiplicityCounter.theInstance.particle(p);
087:
088: if (optional)
089: mul = mul.makeOptional();
090:
091: return new RawTypeSet(rtsb.refs, mul);
092: }
093:
094: /**
095: * To avoid declaring the same element twice for a content model like
096: * (A,A), we keep track of element names here while we are building up
097: * this instance.
098: */
099: private final Set<QName> elementNames = new HashSet<QName>();
100:
101: private final Set<RawTypeSet.Ref> refs = new HashSet<RawTypeSet.Ref>();
102:
103: protected final BGMBuilder builder = Ring.get(BGMBuilder.class);
104:
105: public RawTypeSetBuilder() {
106: }
107:
108: /**
109: * Gets the {@link RawTypeSet.Ref}s that were built.
110: */
111: public Set<RawTypeSet.Ref> getRefs() {
112: return refs;
113: }
114:
115: /**
116: * Build up {@link #refs} and compute the total multiplicity of this {@link RawTypeSet.Ref} set.
117: */
118: private void particle(XSParticle p) {
119: // if the DOM customization is present, bind it like a wildcard
120: BIDom dom = builder.getLocalDomCustomization(p);
121: if (dom != null) {
122: dom.markAsAcknowledged();
123: refs.add(new WildcardRef(WildcardMode.SKIP));
124: } else {
125: p.getTerm().visit(this );
126: }
127: }
128:
129: public void wildcard(XSWildcard wc) {
130: refs.add(new WildcardRef(wc));
131: }
132:
133: public void modelGroupDecl(XSModelGroupDecl decl) {
134: modelGroup(decl.getModelGroup());
135: }
136:
137: public void modelGroup(XSModelGroup group) {
138: for (XSParticle p : group.getChildren())
139: particle(p);
140: }
141:
142: public void elementDecl(XSElementDecl decl) {
143:
144: QName n = BGMBuilder.getName(decl);
145: if (elementNames.add(n)) {
146: CElement elementBean = Ring.get(ClassSelector.class)
147: .bindToType(decl, null);
148: if (elementBean == null)
149: refs.add(new XmlTypeRef(decl));
150: else {
151: // yikes!
152: if (elementBean instanceof CClass)
153: refs.add(new CClassRef(decl, (CClass) elementBean));
154: else
155: refs.add(new CElementInfoRef(decl,
156: (CElementInfo) elementBean));
157: }
158: }
159: }
160:
161: /**
162: * Reference to a wildcard.
163: */
164: public static final class WildcardRef extends RawTypeSet.Ref {
165: private final WildcardMode mode;
166:
167: WildcardRef(XSWildcard wildcard) {
168: this .mode = getMode(wildcard);
169: }
170:
171: WildcardRef(WildcardMode mode) {
172: this .mode = mode;
173: }
174:
175: private static WildcardMode getMode(XSWildcard wildcard) {
176: switch (wildcard.getMode()) {
177: case XSWildcard.LAX:
178: return WildcardMode.LAX;
179: case XSWildcard.STRTICT:
180: return WildcardMode.STRICT;
181: case XSWildcard.SKIP:
182: return WildcardMode.SKIP;
183: default:
184: throw new IllegalStateException();
185: }
186: }
187:
188: protected CTypeRef toTypeRef(CElementPropertyInfo ep) {
189: // we don't allow a mapping to typeRef if the wildcard is present
190: throw new IllegalStateException();
191: }
192:
193: protected void toElementRef(CReferencePropertyInfo prop) {
194: prop.setWildcard(mode);
195: }
196:
197: protected RawTypeSet.Mode canBeType(RawTypeSet parent) {
198: return RawTypeSet.Mode.MUST_BE_REFERENCE;
199: }
200:
201: protected boolean isListOfValues() {
202: return false;
203: }
204:
205: protected ID id() {
206: return ID.NONE;
207: }
208: }
209:
210: /**
211: * Reference to a class that maps from an element.
212: */
213: public static final class CClassRef extends RawTypeSet.Ref {
214: public final CClass target;
215: public final XSElementDecl decl;
216:
217: CClassRef(XSElementDecl decl, CClass target) {
218: this .decl = decl;
219: this .target = target;
220: }
221:
222: protected CTypeRef toTypeRef(CElementPropertyInfo ep) {
223: return new CTypeRef(target, decl);
224: }
225:
226: protected void toElementRef(CReferencePropertyInfo prop) {
227: prop.getElements().add(target);
228: }
229:
230: protected RawTypeSet.Mode canBeType(RawTypeSet parent) {
231: // if element substitution can occur, no way it can be mapped to a list of types
232: if (decl.getSubstitutables().size() > 1)
233: return RawTypeSet.Mode.MUST_BE_REFERENCE;
234:
235: return RawTypeSet.Mode.SHOULD_BE_TYPEREF;
236: }
237:
238: protected boolean isListOfValues() {
239: return false;
240: }
241:
242: protected ID id() {
243: return ID.NONE;
244: }
245: }
246:
247: /**
248: * Reference to a class that maps from an element.
249: */
250: public final class CElementInfoRef extends RawTypeSet.Ref {
251: public final CElementInfo target;
252: public final XSElementDecl decl;
253:
254: CElementInfoRef(XSElementDecl decl, CElementInfo target) {
255: this .decl = decl;
256: this .target = target;
257: }
258:
259: protected CTypeRef toTypeRef(CElementPropertyInfo ep) {
260: assert !target.isCollection();
261: CAdapter a = target.getProperty().getAdapter();
262: if (a != null && ep != null)
263: ep.setAdapter(a);
264:
265: return new CTypeRef(target.getContentType(), decl);
266: }
267:
268: protected void toElementRef(CReferencePropertyInfo prop) {
269: prop.getElements().add(target);
270: }
271:
272: protected RawTypeSet.Mode canBeType(RawTypeSet parent) {
273: // if element substitution can occur, no way it can be mapped to a list of types
274: if (decl.getSubstitutables().size() > 1)
275: return RawTypeSet.Mode.MUST_BE_REFERENCE;
276: // BIXSubstitutable also simulates this effect. Useful for separate compilation
277: BIXSubstitutable subst = builder.getBindInfo(decl).get(
278: BIXSubstitutable.class);
279: if (subst != null) {
280: subst.markAsAcknowledged();
281: return RawTypeSet.Mode.MUST_BE_REFERENCE;
282: }
283:
284: // we have no place to put an adater if this thing maps to a type
285: CElementPropertyInfo p = target.getProperty();
286: // if we have an adapter or IDness, which requires special
287: // annotation, and there's more than one element,
288: // we have no place to put the special annotation, so we need JAXBElement.
289: if ((parent.refs.size() > 1 || !parent.mul.isAtMostOnce())
290: && p.id() != ID.NONE)
291: return RawTypeSet.Mode.MUST_BE_REFERENCE;
292: if (parent.refs.size() > 1 && p.getAdapter() != null)
293: return RawTypeSet.Mode.MUST_BE_REFERENCE;
294:
295: return RawTypeSet.Mode.SHOULD_BE_TYPEREF;
296: }
297:
298: protected boolean isListOfValues() {
299: return target.getProperty().isValueList();
300: }
301:
302: protected ID id() {
303: return target.getProperty().id();
304: }
305:
306: protected MimeType getExpectedMimeType() {
307: return target.getProperty().getExpectedMimeType();
308: }
309: }
310:
311: /**
312: * References to a type. Could be global or local.
313: */
314: public static final class XmlTypeRef extends RawTypeSet.Ref {
315: private final XSElementDecl decl;
316: private final TypeUse target;
317:
318: public XmlTypeRef(XSElementDecl decl) {
319: this .decl = decl;
320: SimpleTypeBuilder stb = Ring.get(SimpleTypeBuilder.class);
321: stb.refererStack.push(decl);
322: TypeUse r = Ring.get(ClassSelector.class).bindToType(
323: decl.getType(), decl);
324: stb.refererStack.pop();
325: target = r;
326: }
327:
328: protected CTypeRef toTypeRef(CElementPropertyInfo ep) {
329: if (ep != null && target.getAdapterUse() != null)
330: ep.setAdapter(target.getAdapterUse());
331: return new CTypeRef(target.getInfo(), decl);
332: }
333:
334: /**
335: * The whole type set can be later bound to a reference property,
336: * in which case we need to generate additional code to wrap this
337: * type reference into an element class.
338: *
339: * This method generates such an element class and returns it.
340: */
341: protected void toElementRef(CReferencePropertyInfo prop) {
342: CClassInfo scope = Ring.get(ClassSelector.class)
343: .getCurrentBean();
344: Model model = Ring.get(Model.class);
345:
346: CCustomizations custs = Ring.get(BGMBuilder.class)
347: .getBindInfo(decl).toCustomizationList();
348:
349: if (target instanceof CClassInfo
350: && Ring.get(BIGlobalBinding.class).isSimpleMode()) {
351: CClassInfo bean = new CClassInfo(model, scope,
352: model.getNameConverter().toClassName(
353: decl.getName()), decl.getLocator(),
354: null, BGMBuilder.getName(decl), decl, custs);
355: bean.setBaseClass((CClassInfo) target);
356: prop.getElements().add(bean);
357: } else {
358: CElementInfo e = new CElementInfo(model, BGMBuilder
359: .getName(decl), scope, target, decl
360: .getDefaultValue(), decl, custs, decl
361: .getLocator());
362: prop.getElements().add(e);
363: }
364: }
365:
366: protected RawTypeSet.Mode canBeType(RawTypeSet parent) {
367: // if we have an adapter or IDness, which requires special
368: // annotation, and there's more than one element,
369: // we have no place to put the special annotation, so we need JAXBElement.
370: if ((parent.refs.size() > 1 || !parent.mul.isAtMostOnce())
371: && target.idUse() != ID.NONE)
372: return RawTypeSet.Mode.MUST_BE_REFERENCE;
373: if (parent.refs.size() > 1
374: && target.getAdapterUse() != null)
375: return RawTypeSet.Mode.MUST_BE_REFERENCE;
376:
377: // nillable and optional at the same time. needs an element wrapper to distinguish those
378: // two states. But this is not a hard requirement.
379: if (decl.isNillable() && parent.mul.isOptional())
380: return RawTypeSet.Mode.CAN_BE_TYPEREF;
381:
382: return RawTypeSet.Mode.SHOULD_BE_TYPEREF;
383: }
384:
385: protected boolean isListOfValues() {
386: return target.isCollection();
387: }
388:
389: protected ID id() {
390: return target.idUse();
391: }
392:
393: protected MimeType getExpectedMimeType() {
394: return target.getExpectedMimeType();
395: }
396: }
397: }
|