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.reader.xmlschema;
027:
028: import java.util.ArrayList;
029: import java.util.Collection;
030: import java.util.Collections;
031: import java.util.HashMap;
032: import java.util.Hashtable;
033: import java.util.List;
034: import java.util.Map;
035:
036: import com.sun.tools.internal.xjc.model.CClassInfo;
037: import com.sun.tools.internal.xjc.model.CPropertyInfo;
038: import com.sun.tools.internal.xjc.model.CReferencePropertyInfo;
039: import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIProperty;
040: import com.sun.xml.internal.xsom.XSElementDecl;
041: import com.sun.xml.internal.xsom.XSModelGroup;
042: import com.sun.xml.internal.xsom.XSModelGroupDecl;
043: import com.sun.xml.internal.xsom.XSParticle;
044: import com.sun.xml.internal.xsom.XSTerm;
045: import com.sun.xml.internal.xsom.XSWildcard;
046: import com.sun.xml.internal.xsom.visitor.XSTermVisitor;
047:
048: /**
049: * {@link ParticleBinder} that follows the JAXB spec.
050: *
051: * @author Kohsuke Kawaguchi
052: */
053: final class DefaultParticleBinder extends ParticleBinder {
054:
055: @Override
056: public void build(XSParticle p, Collection<XSParticle> forcedProps) {
057: Checker checker = checkCollision(p, forcedProps);
058:
059: if (checker.hasNameCollision()) {
060: CReferencePropertyInfo prop = new CReferencePropertyInfo(
061: getCurrentBean().getBaseClass() == null ? "Content"
062: : "Rest", true, false, p, builder
063: .getBindInfo(p).toCustomizationList(), p
064: .getLocator());
065: RawTypeSetBuilder.build(p, false).addTo(prop);
066: prop.javadoc = Messages.format(
067: Messages.MSG_FALLBACK_JAVADOC, checker
068: .getCollisionInfo().toString());
069:
070: getCurrentBean().addProperty(prop);
071: } else {
072: new Builder(checker.markedParticles).particle(p);
073: }
074: }
075:
076: @Override
077: public boolean checkFallback(XSParticle p) {
078: return checkCollision(p, Collections.<XSParticle> emptyList())
079: .hasNameCollision();
080: }
081:
082: private Checker checkCollision(XSParticle p,
083: Collection<XSParticle> forcedProps) {
084: // scan the tree by a checker.
085: Checker checker = new Checker(forcedProps);
086:
087: CClassInfo super Class = getCurrentBean().getBaseClass();
088:
089: if (super Class != null)
090: checker.readSuperClass(super Class);
091: checker.particle(p);
092:
093: return checker;
094: }
095:
096: /**
097: * Marks particles that need to be mapped to properties,
098: * by reading customization info.
099: */
100: private final class Checker implements XSTermVisitor {
101:
102: Checker(Collection<XSParticle> forcedProps) {
103: this .forcedProps = forcedProps;
104: }
105:
106: boolean hasNameCollision() {
107: return collisionInfo != null;
108: }
109:
110: CollisionInfo getCollisionInfo() {
111: return collisionInfo;
112: }
113:
114: /**
115: * If a collision is found, this field will be non-null.
116: */
117: private CollisionInfo collisionInfo = null;
118:
119: /** Used to check name collision. */
120: private final NameCollisionChecker cchecker = new NameCollisionChecker();
121:
122: /**
123: * @see DefaultParticleBinder#build(XSParticle, Collection<com.sun.xml.internal.xsom.XSParticle>)
124: */
125: private final Collection<XSParticle> forcedProps;
126:
127: public void particle(XSParticle p) {
128:
129: if (getLocalPropCustomization(p) != null
130: || builder.getLocalDomCustomization(p) != null) {
131: // if a property customization is specfied,
132: // check that value and turn around.
133: check(p);
134: mark(p);
135: return;
136: }
137:
138: XSTerm t = p.getTerm();
139:
140: if (p.isRepeated()
141: && (t.isModelGroup() || t.isModelGroupDecl())) {
142: // a repeated model group gets its own property
143: mark(p);
144: return;
145: }
146:
147: if (forcedProps.contains(p)) {
148: // this particle must become a property
149: mark(p);
150: return;
151: }
152:
153: outerParticle = p;
154: t.visit(this );
155: }
156:
157: /**
158: * This field points to the parent XSParticle.
159: * The value is only valid when we are processing XSTerm.
160: */
161: private XSParticle outerParticle;
162:
163: public void elementDecl(XSElementDecl decl) {
164: check(outerParticle);
165: mark(outerParticle);
166: }
167:
168: public void modelGroup(XSModelGroup mg) {
169: for (XSParticle child : mg.getChildren())
170: particle(child);
171: }
172:
173: public void modelGroupDecl(XSModelGroupDecl decl) {
174: modelGroup(decl.getModelGroup());
175: }
176:
177: public void wildcard(XSWildcard wc) {
178: mark(outerParticle);
179: }
180:
181: void readSuperClass(CClassInfo ci) {
182: cchecker.readSuperClass(ci);
183: }
184:
185: /**
186: * Checks the name collision of a newly found particle.
187: */
188: private void check(XSParticle p) {
189: if (collisionInfo == null)
190: collisionInfo = cchecker.check(p);
191: }
192:
193: /**
194: * Marks a particle that it's going to be mapped to a property.
195: */
196: private void mark(XSParticle p) {
197: markedParticles.put(p, computeLabel(p));
198: }
199:
200: /**
201: * Marked particles.
202: *
203: * A map from XSParticle to its label.
204: */
205: public final Map<XSParticle, String> markedParticles = new HashMap<XSParticle, String>();
206:
207: /**
208: * Checks name collisions among particles that belong to sequences.
209: */
210: private final class NameCollisionChecker {
211:
212: /**
213: * Checks the label conflict of a particle.
214: * This method shall be called for each marked particle.
215: *
216: * @return
217: * a description of a collision if a name collision is
218: * found. Otherwise null.
219: */
220: CollisionInfo check(XSParticle p) {
221: // this can be used for particles with a property customization,
222: // which may not have element declaration as its term.
223: // // we only check particles with element declarations.
224: // _assert( p.getTerm().isElementDecl() );
225:
226: String label = computeLabel(p);
227: if (occupiedLabels.containsKey(label)) {
228: // collide with occupied labels
229: return new CollisionInfo(label, p.getLocator(),
230: occupiedLabels.get(label).locator);
231: }
232:
233: for (XSParticle jp : particles) {
234: if (!check(p, jp)) {
235: // problem was found. no need to check further
236: return new CollisionInfo(label, p.getLocator(),
237: jp.getLocator());
238: }
239: }
240: particles.add(p);
241: return null;
242: }
243:
244: /** List of particles reported through the check method. */
245: private final List<XSParticle> particles = new ArrayList<XSParticle>();
246:
247: /**
248: * Label names already used in the base type.
249: */
250: private final Map<String, CPropertyInfo> occupiedLabels = new HashMap<String, CPropertyInfo>();
251:
252: /**
253: * Checks the conflict of two particles.
254: * @return
255: * true if the check was successful.
256: */
257: private boolean check(XSParticle p1, XSParticle p2) {
258: return !computeLabel(p1).equals(computeLabel(p2));
259: }
260:
261: /**
262: * Reads fields of the super class and includes them
263: * to name collision tests.
264: */
265: void readSuperClass(CClassInfo base) {
266: for (; base != null; base = base.getBaseClass()) {
267: for (CPropertyInfo p : base.getProperties())
268: occupiedLabels.put(p.getName(true), p);
269: }
270: }
271: }
272:
273: /** Keep the computed label names for particles. */
274: private final Map<XSParticle, String> labelCache = new Hashtable<XSParticle, String>();
275:
276: /**
277: * Hides the computeLabel method of the outer class
278: * and adds caching.
279: */
280: private String computeLabel(XSParticle p) {
281: String label = labelCache.get(p);
282: if (label == null)
283: labelCache.put(p, label = DefaultParticleBinder.this
284: .computeLabel(p));
285: return label;
286: }
287: }
288:
289: /**
290: * Builds properties by using the result computed by Checker
291: */
292: private final class Builder implements XSTermVisitor {
293: Builder(Map<XSParticle, String> markedParticles) {
294: this .markedParticles = markedParticles;
295: }
296:
297: /** All marked particles. */
298: private final Map<XSParticle, String/*label*/> markedParticles;
299:
300: /**
301: * When we are visiting inside an optional particle, this flag
302: * is set to true.
303: *
304: * <p>
305: * This allows us to correctly generate primitive/boxed types.
306: */
307: private boolean insideOptionalParticle;
308:
309: /** Returns true if a particle is marked. */
310: private boolean marked(XSParticle p) {
311: return markedParticles.containsKey(p);
312: }
313:
314: /** Gets a label of a particle. */
315: private String getLabel(XSParticle p) {
316: return markedParticles.get(p);
317: }
318:
319: public void particle(XSParticle p) {
320: XSTerm t = p.getTerm();
321:
322: if (marked(p)) {
323: BIProperty cust = BIProperty.getCustomization(p);
324: CPropertyInfo prop = cust
325: .createElementOrReferenceProperty(getLabel(p),
326: false, p, RawTypeSetBuilder.build(p,
327: insideOptionalParticle));
328: getCurrentBean().addProperty(prop);
329: } else {
330: // repeated model groups should have been marked already
331: assert !p.isRepeated();
332:
333: boolean oldIOP = insideOptionalParticle;
334: insideOptionalParticle |= p.getMinOccurs() == 0;
335: // this is an unmarked particle
336: t.visit(this );
337: insideOptionalParticle = oldIOP;
338: }
339: }
340:
341: public void elementDecl(XSElementDecl e) {
342: // because the corresponding particle must be marked.
343: assert false;
344: }
345:
346: public void wildcard(XSWildcard wc) {
347: // because the corresponding particle must be marked.
348: assert false;
349: }
350:
351: public void modelGroupDecl(XSModelGroupDecl decl) {
352: modelGroup(decl.getModelGroup());
353: }
354:
355: public void modelGroup(XSModelGroup mg) {
356: boolean oldIOP = insideOptionalParticle;
357: insideOptionalParticle |= mg.getCompositor() == XSModelGroup.CHOICE;
358:
359: for (XSParticle p : mg.getChildren())
360: particle(p);
361:
362: insideOptionalParticle = oldIOP;
363: }
364: }
365: }
|