|
1 /* |
|
2 * Copyright (c) 1997, 2011, 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 |
|
26 package com.sun.tools.internal.xjc.reader.xmlschema; |
|
27 |
|
28 import java.util.LinkedHashSet; |
|
29 import java.util.Set; |
|
30 |
|
31 import javax.activation.MimeType; |
|
32 import javax.xml.namespace.QName; |
|
33 |
|
34 import com.sun.tools.internal.xjc.model.CAdapter; |
|
35 import com.sun.tools.internal.xjc.model.CClass; |
|
36 import com.sun.tools.internal.xjc.model.CClassInfo; |
|
37 import com.sun.tools.internal.xjc.model.CCustomizations; |
|
38 import com.sun.tools.internal.xjc.model.CElement; |
|
39 import com.sun.tools.internal.xjc.model.CElementInfo; |
|
40 import com.sun.tools.internal.xjc.model.CElementPropertyInfo; |
|
41 import com.sun.tools.internal.xjc.model.CReferencePropertyInfo; |
|
42 import com.sun.tools.internal.xjc.model.CTypeRef; |
|
43 import com.sun.tools.internal.xjc.model.Model; |
|
44 import com.sun.tools.internal.xjc.model.Multiplicity; |
|
45 import com.sun.tools.internal.xjc.model.TypeUse; |
|
46 import com.sun.tools.internal.xjc.reader.RawTypeSet; |
|
47 import com.sun.tools.internal.xjc.reader.Ring; |
|
48 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIDom; |
|
49 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIGlobalBinding; |
|
50 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIXSubstitutable; |
|
51 import com.sun.xml.internal.bind.v2.model.core.ID; |
|
52 import com.sun.xml.internal.bind.v2.model.core.WildcardMode; |
|
53 import com.sun.xml.internal.xsom.XSElementDecl; |
|
54 import com.sun.xml.internal.xsom.XSModelGroup; |
|
55 import com.sun.xml.internal.xsom.XSModelGroupDecl; |
|
56 import com.sun.xml.internal.xsom.XSParticle; |
|
57 import com.sun.xml.internal.xsom.XSWildcard; |
|
58 import com.sun.xml.internal.xsom.visitor.XSTermVisitor; |
|
59 |
|
60 /** |
|
61 * Builds {@link RawTypeSet} for XML Schema. |
|
62 * |
|
63 * @author Kohsuke Kawaguchi |
|
64 */ |
|
65 public class RawTypeSetBuilder implements XSTermVisitor { |
|
66 /** |
|
67 * @param optional |
|
68 * if this whole property is optional due to the |
|
69 * occurrence constraints on ancestors, set this to true. |
|
70 * this will prevent the primitive types to be generated. |
|
71 */ |
|
72 public static RawTypeSet build( XSParticle p, boolean optional ) { |
|
73 RawTypeSetBuilder rtsb = new RawTypeSetBuilder(); |
|
74 rtsb.particle(p); |
|
75 Multiplicity mul = MultiplicityCounter.theInstance.particle(p); |
|
76 |
|
77 if(optional) |
|
78 mul = mul.makeOptional(); |
|
79 |
|
80 return new RawTypeSet(rtsb.refs,mul); |
|
81 } |
|
82 |
|
83 /** |
|
84 * To avoid declaring the same element twice for a content model like |
|
85 * (A,A), we keep track of element names here while we are building up |
|
86 * this instance. |
|
87 */ |
|
88 private final Set<QName> elementNames = new LinkedHashSet<QName>(); |
|
89 |
|
90 private final Set<RawTypeSet.Ref> refs = new LinkedHashSet<RawTypeSet.Ref>(); |
|
91 |
|
92 protected final BGMBuilder builder = Ring.get(BGMBuilder.class); |
|
93 |
|
94 public RawTypeSetBuilder() {} |
|
95 |
|
96 |
|
97 /** |
|
98 * Gets the {@link RawTypeSet.Ref}s that were built. |
|
99 */ |
|
100 public Set<RawTypeSet.Ref> getRefs() { |
|
101 return refs; |
|
102 } |
|
103 |
|
104 /** |
|
105 * Build up {@link #refs} and compute the total multiplicity of this {@link RawTypeSet.Ref} set. |
|
106 */ |
|
107 private void particle( XSParticle p ) { |
|
108 // if the DOM customization is present, bind it like a wildcard |
|
109 BIDom dom = builder.getLocalDomCustomization(p); |
|
110 if(dom!=null) { |
|
111 dom.markAsAcknowledged(); |
|
112 refs.add(new WildcardRef(WildcardMode.SKIP)); |
|
113 } else { |
|
114 p.getTerm().visit(this); |
|
115 } |
|
116 } |
|
117 |
|
118 public void wildcard(XSWildcard wc) { |
|
119 refs.add(new WildcardRef(wc)); |
|
120 } |
|
121 |
|
122 public void modelGroupDecl(XSModelGroupDecl decl) { |
|
123 modelGroup(decl.getModelGroup()); |
|
124 } |
|
125 |
|
126 public void modelGroup(XSModelGroup group) { |
|
127 for( XSParticle p : group.getChildren()) |
|
128 particle(p); |
|
129 } |
|
130 |
|
131 public void elementDecl(XSElementDecl decl) { |
|
132 |
|
133 QName n = BGMBuilder.getName(decl); |
|
134 if(elementNames.add(n)) { |
|
135 CElement elementBean = Ring.get(ClassSelector.class).bindToType(decl,null); |
|
136 if(elementBean==null) |
|
137 refs.add(new XmlTypeRef(decl)); |
|
138 else { |
|
139 // yikes! |
|
140 if(elementBean instanceof CClass) |
|
141 refs.add(new CClassRef(decl,(CClass)elementBean)); |
|
142 else |
|
143 refs.add(new CElementInfoRef(decl,(CElementInfo)elementBean)); |
|
144 } |
|
145 } |
|
146 } |
|
147 |
|
148 /** |
|
149 * Reference to a wildcard. |
|
150 */ |
|
151 public static final class WildcardRef extends RawTypeSet.Ref { |
|
152 private final WildcardMode mode; |
|
153 |
|
154 WildcardRef(XSWildcard wildcard) { |
|
155 this.mode = getMode(wildcard); |
|
156 } |
|
157 WildcardRef(WildcardMode mode) { |
|
158 this.mode = mode; |
|
159 } |
|
160 |
|
161 private static WildcardMode getMode(XSWildcard wildcard) { |
|
162 switch(wildcard.getMode()) { |
|
163 case XSWildcard.LAX: |
|
164 return WildcardMode.LAX; |
|
165 case XSWildcard.STRTICT: |
|
166 return WildcardMode.STRICT; |
|
167 case XSWildcard.SKIP: |
|
168 return WildcardMode.SKIP; |
|
169 default: |
|
170 throw new IllegalStateException(); |
|
171 } |
|
172 } |
|
173 |
|
174 protected CTypeRef toTypeRef(CElementPropertyInfo ep) { |
|
175 // we don't allow a mapping to typeRef if the wildcard is present |
|
176 throw new IllegalStateException(); |
|
177 } |
|
178 |
|
179 protected void toElementRef(CReferencePropertyInfo prop) { |
|
180 prop.setWildcard(mode); |
|
181 } |
|
182 |
|
183 protected RawTypeSet.Mode canBeType(RawTypeSet parent) { |
|
184 return RawTypeSet.Mode.MUST_BE_REFERENCE; |
|
185 } |
|
186 |
|
187 protected boolean isListOfValues() { |
|
188 return false; |
|
189 } |
|
190 |
|
191 protected ID id() { |
|
192 return ID.NONE; |
|
193 } |
|
194 } |
|
195 |
|
196 /** |
|
197 * Reference to a class that maps from an element. |
|
198 */ |
|
199 public static final class CClassRef extends RawTypeSet.Ref { |
|
200 public final CClass target; |
|
201 public final XSElementDecl decl; |
|
202 |
|
203 CClassRef(XSElementDecl decl, CClass target) { |
|
204 this.decl = decl; |
|
205 this.target = target; |
|
206 } |
|
207 |
|
208 protected CTypeRef toTypeRef(CElementPropertyInfo ep) { |
|
209 return new CTypeRef(target,decl); |
|
210 } |
|
211 |
|
212 protected void toElementRef(CReferencePropertyInfo prop) { |
|
213 prop.getElements().add(target); |
|
214 } |
|
215 |
|
216 protected RawTypeSet.Mode canBeType(RawTypeSet parent) { |
|
217 // if element substitution can occur, no way it can be mapped to a list of types |
|
218 if(decl.getSubstitutables().size()>1) |
|
219 return RawTypeSet.Mode.MUST_BE_REFERENCE; |
|
220 |
|
221 return RawTypeSet.Mode.SHOULD_BE_TYPEREF; |
|
222 } |
|
223 |
|
224 protected boolean isListOfValues() { |
|
225 return false; |
|
226 } |
|
227 |
|
228 protected ID id() { |
|
229 return ID.NONE; |
|
230 } |
|
231 } |
|
232 |
|
233 /** |
|
234 * Reference to a class that maps from an element. |
|
235 */ |
|
236 public final class CElementInfoRef extends RawTypeSet.Ref { |
|
237 public final CElementInfo target; |
|
238 public final XSElementDecl decl; |
|
239 |
|
240 CElementInfoRef(XSElementDecl decl, CElementInfo target) { |
|
241 this.decl = decl; |
|
242 this.target = target; |
|
243 } |
|
244 |
|
245 protected CTypeRef toTypeRef(CElementPropertyInfo ep) { |
|
246 assert !target.isCollection(); |
|
247 CAdapter a = target.getProperty().getAdapter(); |
|
248 if(a!=null && ep!=null) ep.setAdapter(a); |
|
249 |
|
250 return new CTypeRef(target.getContentType(),decl); |
|
251 } |
|
252 |
|
253 protected void toElementRef(CReferencePropertyInfo prop) { |
|
254 prop.getElements().add(target); |
|
255 } |
|
256 |
|
257 protected RawTypeSet.Mode canBeType(RawTypeSet parent) { |
|
258 // if element substitution can occur, no way it can be mapped to a list of types |
|
259 if(decl.getSubstitutables().size()>1) |
|
260 return RawTypeSet.Mode.MUST_BE_REFERENCE; |
|
261 // BIXSubstitutable also simulates this effect. Useful for separate compilation |
|
262 BIXSubstitutable subst = builder.getBindInfo(decl).get(BIXSubstitutable.class); |
|
263 if(subst!=null) { |
|
264 subst.markAsAcknowledged(); |
|
265 return RawTypeSet.Mode.MUST_BE_REFERENCE; |
|
266 } |
|
267 |
|
268 // we have no place to put an adater if this thing maps to a type |
|
269 CElementPropertyInfo p = target.getProperty(); |
|
270 // if we have an adapter or IDness, which requires special |
|
271 // annotation, and there's more than one element, |
|
272 // we have no place to put the special annotation, so we need JAXBElement. |
|
273 if((parent.refs.size()>1 || !parent.mul.isAtMostOnce()) && p.id()!=ID.NONE) |
|
274 return RawTypeSet.Mode.MUST_BE_REFERENCE; |
|
275 if(parent.refs.size() > 1 && p.getAdapter() != null) |
|
276 return RawTypeSet.Mode.MUST_BE_REFERENCE; |
|
277 |
|
278 if(target.hasClass()) |
|
279 // if the CElementInfo was explicitly bound to a class (which happen if and only if |
|
280 // the user requested so, then map that to reference property so that the user sees a class |
|
281 return RawTypeSet.Mode.CAN_BE_TYPEREF; |
|
282 else |
|
283 return RawTypeSet.Mode.SHOULD_BE_TYPEREF; |
|
284 } |
|
285 |
|
286 protected boolean isListOfValues() { |
|
287 return target.getProperty().isValueList(); |
|
288 } |
|
289 |
|
290 protected ID id() { |
|
291 return target.getProperty().id(); |
|
292 } |
|
293 |
|
294 @Override |
|
295 protected MimeType getExpectedMimeType() { |
|
296 return target.getProperty().getExpectedMimeType(); |
|
297 } |
|
298 } |
|
299 |
|
300 /** |
|
301 * References to a type. Could be global or local. |
|
302 */ |
|
303 public static final class XmlTypeRef extends RawTypeSet.Ref { |
|
304 private final XSElementDecl decl; |
|
305 private final TypeUse target; |
|
306 |
|
307 public XmlTypeRef(XSElementDecl decl) { |
|
308 this.decl = decl; |
|
309 SimpleTypeBuilder stb = Ring.get(SimpleTypeBuilder.class); |
|
310 stb.refererStack.push(decl); |
|
311 TypeUse r = Ring.get(ClassSelector.class).bindToType(decl.getType(),decl); |
|
312 stb.refererStack.pop(); |
|
313 target = r; |
|
314 } |
|
315 |
|
316 protected CTypeRef toTypeRef(CElementPropertyInfo ep) { |
|
317 if(ep!=null && target.getAdapterUse()!=null) |
|
318 ep.setAdapter(target.getAdapterUse()); |
|
319 return new CTypeRef(target.getInfo(),decl); |
|
320 } |
|
321 |
|
322 /** |
|
323 * The whole type set can be later bound to a reference property, |
|
324 * in which case we need to generate additional code to wrap this |
|
325 * type reference into an element class. |
|
326 * |
|
327 * This method generates such an element class and returns it. |
|
328 */ |
|
329 protected void toElementRef(CReferencePropertyInfo prop) { |
|
330 CClassInfo scope = Ring.get(ClassSelector.class).getCurrentBean(); |
|
331 Model model = Ring.get(Model.class); |
|
332 |
|
333 CCustomizations custs = Ring.get(BGMBuilder.class).getBindInfo(decl).toCustomizationList(); |
|
334 |
|
335 if(target instanceof CClassInfo && Ring.get(BIGlobalBinding.class).isSimpleMode()) { |
|
336 CClassInfo bean = new CClassInfo(model,scope, |
|
337 model.getNameConverter().toClassName(decl.getName()), |
|
338 decl.getLocator(), null, BGMBuilder.getName(decl), decl, |
|
339 custs); |
|
340 bean.setBaseClass((CClassInfo)target); |
|
341 prop.getElements().add(bean); |
|
342 } else { |
|
343 CElementInfo e = new CElementInfo(model,BGMBuilder.getName(decl),scope,target, |
|
344 decl.getDefaultValue(), decl, custs, decl.getLocator()); |
|
345 prop.getElements().add(e); |
|
346 } |
|
347 } |
|
348 |
|
349 protected RawTypeSet.Mode canBeType(RawTypeSet parent) { |
|
350 // if we have an adapter or IDness, which requires special |
|
351 // annotation, and there's more than one element, |
|
352 // we have no place to put the special annotation, so we need JAXBElement. |
|
353 if((parent.refs.size()>1 || !parent.mul.isAtMostOnce()) && target.idUse()!=ID.NONE) |
|
354 return RawTypeSet.Mode.MUST_BE_REFERENCE; |
|
355 if(parent.refs.size() > 1 && target.getAdapterUse() != null) |
|
356 return RawTypeSet.Mode.MUST_BE_REFERENCE; |
|
357 |
|
358 // nillable and optional at the same time. needs an element wrapper to distinguish those |
|
359 // two states. But this is not a hard requirement. |
|
360 if(decl.isNillable() && parent.mul.isOptional()) |
|
361 return RawTypeSet.Mode.CAN_BE_TYPEREF; |
|
362 |
|
363 return RawTypeSet.Mode.SHOULD_BE_TYPEREF; |
|
364 } |
|
365 |
|
366 protected boolean isListOfValues() { |
|
367 return target.isCollection(); |
|
368 } |
|
369 |
|
370 protected ID id() { |
|
371 return target.idUse(); |
|
372 } |
|
373 |
|
374 @Override |
|
375 protected MimeType getExpectedMimeType() { |
|
376 return target.getExpectedMimeType(); |
|
377 } |
|
378 } |
|
379 } |