|
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.ArrayList; |
|
29 import java.util.Collection; |
|
30 import java.util.Collections; |
|
31 import java.util.HashMap; |
|
32 import java.util.Hashtable; |
|
33 import java.util.List; |
|
34 import java.util.Map; |
|
35 |
|
36 import com.sun.tools.internal.xjc.model.CClassInfo; |
|
37 import com.sun.tools.internal.xjc.model.CPropertyInfo; |
|
38 import com.sun.tools.internal.xjc.model.CReferencePropertyInfo; |
|
39 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIProperty; |
|
40 import com.sun.xml.internal.xsom.XSElementDecl; |
|
41 import com.sun.xml.internal.xsom.XSModelGroup; |
|
42 import com.sun.xml.internal.xsom.XSModelGroupDecl; |
|
43 import com.sun.xml.internal.xsom.XSParticle; |
|
44 import com.sun.xml.internal.xsom.XSTerm; |
|
45 import com.sun.xml.internal.xsom.XSWildcard; |
|
46 import com.sun.xml.internal.xsom.visitor.XSTermVisitor; |
|
47 import java.math.BigInteger; |
|
48 |
|
49 /** |
|
50 * {@link ParticleBinder} that follows the JAXB spec. |
|
51 * |
|
52 * @author Kohsuke Kawaguchi |
|
53 */ |
|
54 final class DefaultParticleBinder extends ParticleBinder { |
|
55 |
|
56 @Override |
|
57 public void build( XSParticle p, Collection<XSParticle> forcedProps ) { |
|
58 Checker checker = checkCollision(p,forcedProps); |
|
59 |
|
60 if(checker.hasNameCollision()) { |
|
61 CReferencePropertyInfo prop = new CReferencePropertyInfo( |
|
62 getCurrentBean().getBaseClass()==null?"Content":"Rest", |
|
63 true, false, false, p, |
|
64 builder.getBindInfo(p).toCustomizationList(), |
|
65 p.getLocator(), false, false, false); |
|
66 RawTypeSetBuilder.build(p,false).addTo(prop); |
|
67 prop.javadoc = Messages.format( Messages.MSG_FALLBACK_JAVADOC, |
|
68 checker.getCollisionInfo().toString() ); |
|
69 |
|
70 getCurrentBean().addProperty(prop); |
|
71 } else { |
|
72 new Builder(checker.markedParticles).particle(p); |
|
73 } |
|
74 } |
|
75 |
|
76 @Override |
|
77 public boolean checkFallback( XSParticle p ) { |
|
78 return checkCollision(p,Collections.<XSParticle>emptyList()).hasNameCollision(); |
|
79 } |
|
80 |
|
81 private Checker checkCollision( XSParticle p, Collection<XSParticle> forcedProps ) { |
|
82 // scan the tree by a checker. |
|
83 Checker checker = new Checker(forcedProps); |
|
84 |
|
85 CClassInfo superClass = getCurrentBean().getBaseClass(); |
|
86 |
|
87 if(superClass!=null) |
|
88 checker.readSuperClass(superClass); |
|
89 checker.particle(p); |
|
90 |
|
91 return checker; |
|
92 } |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 /** |
|
104 * Marks particles that need to be mapped to properties, |
|
105 * by reading customization info. |
|
106 */ |
|
107 private final class Checker implements XSTermVisitor { |
|
108 |
|
109 Checker(Collection<XSParticle> forcedProps) { |
|
110 this.forcedProps = forcedProps; |
|
111 } |
|
112 |
|
113 boolean hasNameCollision() { |
|
114 return collisionInfo!=null; |
|
115 } |
|
116 |
|
117 CollisionInfo getCollisionInfo() { |
|
118 return collisionInfo; |
|
119 } |
|
120 |
|
121 /** |
|
122 * If a collision is found, this field will be non-null. |
|
123 */ |
|
124 private CollisionInfo collisionInfo = null; |
|
125 |
|
126 /** Used to check name collision. */ |
|
127 private final NameCollisionChecker cchecker = new NameCollisionChecker(); |
|
128 |
|
129 /** |
|
130 * @see DefaultParticleBinder#build(XSParticle, Collection<com.sun.xml.internal.xsom.XSParticle>) |
|
131 */ |
|
132 private final Collection<XSParticle> forcedProps; |
|
133 |
|
134 public void particle( XSParticle p ) { |
|
135 |
|
136 if(getLocalPropCustomization(p)!=null |
|
137 || builder.getLocalDomCustomization(p)!=null) { |
|
138 // if a property customization is specfied, |
|
139 // check that value and turn around. |
|
140 check(p); |
|
141 mark(p); |
|
142 return; |
|
143 } |
|
144 |
|
145 XSTerm t = p.getTerm(); |
|
146 |
|
147 if(p.isRepeated() && (t.isModelGroup() || t.isModelGroupDecl())) { |
|
148 // a repeated model group gets its own property |
|
149 mark(p); |
|
150 return; |
|
151 } |
|
152 |
|
153 if(forcedProps.contains(p)) { |
|
154 // this particle must become a property |
|
155 mark(p); |
|
156 return; |
|
157 } |
|
158 |
|
159 outerParticle = p; |
|
160 t.visit(this); |
|
161 } |
|
162 |
|
163 /** |
|
164 * This field points to the parent XSParticle. |
|
165 * The value is only valid when we are processing XSTerm. |
|
166 */ |
|
167 private XSParticle outerParticle; |
|
168 |
|
169 public void elementDecl(XSElementDecl decl) { |
|
170 check(outerParticle); |
|
171 mark(outerParticle); |
|
172 } |
|
173 |
|
174 public void modelGroup(XSModelGroup mg) { |
|
175 // choice gets mapped to a property |
|
176 if(mg.getCompositor()== XSModelGroup.Compositor.CHOICE && builder.getGlobalBinding().isChoiceContentPropertyEnabled()) { |
|
177 mark(outerParticle); |
|
178 return; |
|
179 } |
|
180 |
|
181 for( XSParticle child : mg.getChildren() ) |
|
182 particle(child); |
|
183 } |
|
184 |
|
185 public void modelGroupDecl(XSModelGroupDecl decl) { |
|
186 modelGroup(decl.getModelGroup()); |
|
187 } |
|
188 |
|
189 public void wildcard(XSWildcard wc) { |
|
190 mark(outerParticle); |
|
191 } |
|
192 |
|
193 void readSuperClass( CClassInfo ci ) { |
|
194 cchecker.readSuperClass(ci); |
|
195 } |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 /** |
|
201 * Checks the name collision of a newly found particle. |
|
202 */ |
|
203 private void check( XSParticle p ) { |
|
204 if( collisionInfo==null ) |
|
205 collisionInfo = cchecker.check(p); |
|
206 } |
|
207 |
|
208 /** |
|
209 * Marks a particle that it's going to be mapped to a property. |
|
210 */ |
|
211 private void mark( XSParticle p ) { |
|
212 markedParticles.put(p,computeLabel(p)); |
|
213 } |
|
214 |
|
215 /** |
|
216 * Marked particles. |
|
217 * |
|
218 * A map from XSParticle to its label. |
|
219 */ |
|
220 public final Map<XSParticle,String> markedParticles = new HashMap<XSParticle,String>(); |
|
221 |
|
222 |
|
223 /** |
|
224 * Checks name collisions among particles that belong to sequences. |
|
225 */ |
|
226 private final class NameCollisionChecker { |
|
227 |
|
228 /** |
|
229 * Checks the label conflict of a particle. |
|
230 * This method shall be called for each marked particle. |
|
231 * |
|
232 * @return |
|
233 * a description of a collision if a name collision is |
|
234 * found. Otherwise null. |
|
235 */ |
|
236 CollisionInfo check( XSParticle p ) { |
|
237 // this can be used for particles with a property customization, |
|
238 // which may not have element declaration as its term. |
|
239 // // we only check particles with element declarations. |
|
240 // _assert( p.getTerm().isElementDecl() ); |
|
241 |
|
242 String label = computeLabel(p); |
|
243 if( occupiedLabels.containsKey(label) ) { |
|
244 // collide with occupied labels |
|
245 return new CollisionInfo(label,p.getLocator(), |
|
246 occupiedLabels.get(label).locator); |
|
247 } |
|
248 |
|
249 for( XSParticle jp : particles ) { |
|
250 if(!check( p, jp )) { |
|
251 // problem was found. no need to check further |
|
252 return new CollisionInfo( label, p.getLocator(), jp.getLocator() ); |
|
253 } |
|
254 } |
|
255 particles.add(p); |
|
256 return null; |
|
257 } |
|
258 |
|
259 /** List of particles reported through the check method. */ |
|
260 private final List<XSParticle> particles = new ArrayList<XSParticle>(); |
|
261 |
|
262 /** |
|
263 * Label names already used in the base type. |
|
264 */ |
|
265 private final Map<String,CPropertyInfo> occupiedLabels = new HashMap<String,CPropertyInfo>(); |
|
266 |
|
267 /** |
|
268 * Checks the conflict of two particles. |
|
269 * @return |
|
270 * true if the check was successful. |
|
271 */ |
|
272 private boolean check( XSParticle p1, XSParticle p2 ) { |
|
273 return !computeLabel(p1).equals(computeLabel(p2)); |
|
274 } |
|
275 |
|
276 /** |
|
277 * Reads fields of the super class and includes them |
|
278 * to name collision tests. |
|
279 */ |
|
280 void readSuperClass( CClassInfo base ) { |
|
281 for( ; base!=null; base=base.getBaseClass() ) { |
|
282 for( CPropertyInfo p : base.getProperties() ) |
|
283 occupiedLabels.put(p.getName(true),p); |
|
284 } |
|
285 } |
|
286 } |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 /** Keep the computed label names for particles. */ |
|
293 private final Map<XSParticle,String> labelCache = new Hashtable<XSParticle,String>(); |
|
294 |
|
295 /** |
|
296 * Hides the computeLabel method of the outer class |
|
297 * and adds caching. |
|
298 */ |
|
299 private String computeLabel( XSParticle p ) { |
|
300 String label = labelCache.get(p); |
|
301 if(label==null) |
|
302 labelCache.put( p, label=DefaultParticleBinder.this.computeLabel(p) ); |
|
303 return label; |
|
304 } |
|
305 } |
|
306 |
|
307 |
|
308 |
|
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 |
|
316 |
|
317 |
|
318 /** |
|
319 * Builds properties by using the result computed by Checker |
|
320 */ |
|
321 private final class Builder implements XSTermVisitor { |
|
322 Builder( Map<XSParticle,String> markedParticles ) { |
|
323 this.markedParticles = markedParticles; |
|
324 } |
|
325 |
|
326 /** All marked particles. */ |
|
327 private final Map<XSParticle,String/*label*/> markedParticles; |
|
328 |
|
329 /** |
|
330 * When we are visiting inside an optional particle, this flag |
|
331 * is set to true. |
|
332 * |
|
333 * <p> |
|
334 * This allows us to correctly generate primitive/boxed types. |
|
335 */ |
|
336 private boolean insideOptionalParticle; |
|
337 |
|
338 |
|
339 /** Returns true if a particle is marked. */ |
|
340 private boolean marked( XSParticle p ) { |
|
341 return markedParticles.containsKey(p); |
|
342 } |
|
343 /** Gets a label of a particle. */ |
|
344 private String getLabel( XSParticle p ) { |
|
345 return markedParticles.get(p); |
|
346 } |
|
347 |
|
348 public void particle( XSParticle p ) { |
|
349 XSTerm t = p.getTerm(); |
|
350 |
|
351 if(marked(p)) { |
|
352 BIProperty cust = BIProperty.getCustomization(p); |
|
353 CPropertyInfo prop = cust.createElementOrReferenceProperty( |
|
354 getLabel(p), false, p, RawTypeSetBuilder.build(p,insideOptionalParticle)); |
|
355 getCurrentBean().addProperty(prop); |
|
356 } else { |
|
357 // repeated model groups should have been marked already |
|
358 assert !p.isRepeated(); |
|
359 |
|
360 boolean oldIOP = insideOptionalParticle; |
|
361 insideOptionalParticle |= BigInteger.ZERO.equals(p.getMinOccurs()); |
|
362 // this is an unmarked particle |
|
363 t.visit(this); |
|
364 insideOptionalParticle = oldIOP; |
|
365 } |
|
366 } |
|
367 |
|
368 public void elementDecl( XSElementDecl e ) { |
|
369 // because the corresponding particle must be marked. |
|
370 assert false; |
|
371 } |
|
372 |
|
373 public void wildcard( XSWildcard wc ) { |
|
374 // because the corresponding particle must be marked. |
|
375 assert false; |
|
376 } |
|
377 |
|
378 public void modelGroupDecl( XSModelGroupDecl decl ) { |
|
379 modelGroup(decl.getModelGroup()); |
|
380 } |
|
381 |
|
382 public void modelGroup( XSModelGroup mg ) { |
|
383 boolean oldIOP = insideOptionalParticle; |
|
384 insideOptionalParticle |= mg.getCompositor()==XSModelGroup.CHOICE; |
|
385 |
|
386 for( XSParticle p : mg.getChildren()) |
|
387 particle(p); |
|
388 |
|
389 insideOptionalParticle = oldIOP; |
|
390 } |
|
391 } |
|
392 } |