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.text.ParseException;
029: import java.util.Collection;
030: import java.util.Collections;
031:
032: import com.sun.codemodel.internal.JJavaName;
033: import com.sun.tools.internal.xjc.model.CClassInfo;
034: import com.sun.tools.internal.xjc.model.CPropertyInfo;
035: import com.sun.tools.internal.xjc.reader.Ring;
036: import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIDeclaration;
037: import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIProperty;
038: import com.sun.xml.internal.xsom.XSElementDecl;
039: import com.sun.xml.internal.xsom.XSModelGroup;
040: import com.sun.xml.internal.xsom.XSModelGroupDecl;
041: import com.sun.xml.internal.xsom.XSParticle;
042: import com.sun.xml.internal.xsom.XSTerm;
043: import com.sun.xml.internal.xsom.XSWildcard;
044: import com.sun.xml.internal.xsom.visitor.XSTermVisitor;
045:
046: /**
047: * Binds the content models of {@link XSParticle} as properties of the class that's being built.
048: *
049: * @author
050: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
051: */
052: public abstract class ParticleBinder {
053:
054: protected final BGMBuilder builder = Ring.get(BGMBuilder.class);
055:
056: protected ParticleBinder() {
057: // make sure that this object is available as ParticleBinder, not as their actual implementation classes
058: Ring.add(ParticleBinder.class, this );
059: }
060:
061: /**
062: * Builds the {@link CPropertyInfo}s from the given particle
063: * (and its descendants), and set them to the class returned by
064: * {@link ClassSelector#getCurrentBean()}.
065: */
066: public final void build(XSParticle p) {
067: build(p, Collections.<XSParticle> emptySet());
068: }
069:
070: /**
071: * The version of the build method that forces a specified set of particles
072: * to become a property.
073: */
074: public abstract void build(XSParticle p,
075: Collection<XSParticle> forcedProps);
076:
077: /**
078: * Similar to the build method but this method only checks if
079: * the BGM that will be built by the build method will
080: * do the fallback (map all the properties into one list) or not.
081: *
082: * @return
083: * false if the fallback will not happen.
084: */
085: public abstract boolean checkFallback(XSParticle p);
086:
087: //
088: //
089: // convenient utility methods
090: //
091: //
092:
093: protected final CClassInfo getCurrentBean() {
094: return getClassSelector().getCurrentBean();
095: }
096:
097: /**
098: * Gets the BIProperty object that applies to the given particle.
099: */
100: protected final BIProperty getLocalPropCustomization(XSParticle p) {
101: return getLocalCustomization(p, BIProperty.class);
102: }
103:
104: protected final <T extends BIDeclaration> T getLocalCustomization(
105: XSParticle p, Class<T> type) {
106: // check the property customization of this component first
107: T cust = builder.getBindInfo(p).get(type);
108: if (cust != null)
109: return cust;
110:
111: // if not, the term might have one.
112: cust = builder.getBindInfo(p.getTerm()).get(type);
113: if (cust != null)
114: return cust;
115:
116: return null;
117: }
118:
119: /**
120: * Computes the label of a given particle.
121: * Usually, the getLabel method should be used instead.
122: */
123: protected final String computeLabel(XSParticle p) {
124: // if the particle carries a customization, use that value.
125: // since we are binding content models, it's always non-constant properties.
126: BIProperty cust = getLocalPropCustomization(p);
127: if (cust != null && cust.getPropertyName(false) != null)
128: return cust.getPropertyName(false);
129:
130: // no explicit property name is given. Compute one.
131:
132: XSTerm t = p.getTerm();
133:
134: // // first, check if a term is going to be a class, if so, use that name.
135: // ClassItem ci = owner.selector.select(t);
136: // if(ci!=null) {
137: // return makeJavaName(ci.getTypeAsDefined().name());
138: // }
139:
140: // if it fails, compute the default name according to the spec.
141: if (t.isElementDecl())
142: // for element, take the element name.
143: return makeJavaName(p, t.asElementDecl().getName());
144: if (t.isModelGroupDecl())
145: // for named model groups, take that name
146: return makeJavaName(p, t.asModelGroupDecl().getName());
147: if (t.isWildcard())
148: // the spec says it will map to "any" by default.
149: return makeJavaName(p, "Any");
150: if (t.isModelGroup()) {
151: try {
152: return getSpecDefaultName(t.asModelGroup(), p
153: .isRepeated());
154: } catch (ParseException e) {
155: // unable to generate a name.
156: getErrorReporter()
157: .error(
158: t.getLocator(),
159: Messages.ERR_UNABLE_TO_GENERATE_NAME_FROM_MODELGROUP);
160: return "undefined"; // recover from error by assuming something
161: }
162: }
163:
164: // there are only four types of XSTerm.
165: throw new AssertionError();
166: }
167:
168: /** Converts an XML name to the corresponding Java name. */
169: protected final String makeJavaName(boolean isRepeated,
170: String xmlName) {
171: String name = builder.getNameConverter()
172: .toPropertyName(xmlName);
173: if (builder.getGlobalBinding().isSimpleMode() && isRepeated)
174: name = JJavaName.getPluralForm(name);
175: return name;
176: }
177:
178: protected final String makeJavaName(XSParticle p, String xmlName) {
179: return makeJavaName(p.isRepeated(), xmlName);
180: }
181:
182: /**
183: * Computes a name from unnamed model group by following the spec.
184: *
185: * Taking first three elements and combine them.
186: *
187: * @param repeated
188: * if the said model group is repeated more than once
189: *
190: * @exception ParseException
191: * If the method cannot generate a name. For example, when
192: * a model group doesn't contain any element reference/declaration
193: * at all.
194: */
195: protected final String getSpecDefaultName(XSModelGroup mg,
196: final boolean repeated) throws ParseException {
197:
198: final StringBuilder name = new StringBuilder();
199:
200: mg.visit(new XSTermVisitor() {
201: /**
202: * Count the number of tokens we combined.
203: * We will concat up to 3.
204: */
205: private int count = 0;
206:
207: /**
208: * Is the current particple/term repeated?
209: */
210: private boolean rep = repeated;
211:
212: public void wildcard(XSWildcard wc) {
213: append("any");
214: }
215:
216: public void modelGroupDecl(XSModelGroupDecl mgd) {
217: modelGroup(mgd.getModelGroup());
218: }
219:
220: public void modelGroup(XSModelGroup mg) {
221: String operator;
222: if (mg.getCompositor() == XSModelGroup.CHOICE)
223: operator = "Or";
224: else
225: operator = "And";
226:
227: int size = mg.getSize();
228: for (int i = 0; i < size; i++) {
229: XSParticle p = mg.getChild(i);
230: boolean oldRep = rep;
231: rep |= p.isRepeated();
232: p.getTerm().visit(this );
233: rep = oldRep;
234:
235: if (count == 3)
236: return; // we have enough
237: if (i != size - 1)
238: name.append(operator);
239: }
240: }
241:
242: public void elementDecl(XSElementDecl ed) {
243: append(ed.getName());
244: }
245:
246: private void append(String token) {
247: if (count < 3) {
248: name.append(makeJavaName(rep, token));
249: count++;
250: }
251: }
252: });
253:
254: if (name.length() == 0)
255: throw new ParseException("no element", -1);
256:
257: return name.toString();
258: }
259:
260: protected final ErrorReporter getErrorReporter() {
261: return Ring.get(ErrorReporter.class);
262: }
263:
264: protected final ClassSelector getClassSelector() {
265: return Ring.get(ClassSelector.class);
266: }
267: }
|