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.bindinfo;
027:
028: import java.util.Collections;
029: import java.util.HashMap;
030: import java.util.Map;
031: import java.util.Set;
032:
033: import javax.xml.bind.annotation.XmlAttribute;
034: import javax.xml.bind.annotation.XmlElement;
035: import javax.xml.bind.annotation.XmlEnumValue;
036: import javax.xml.bind.annotation.XmlRootElement;
037: import javax.xml.bind.annotation.XmlTransient;
038: import javax.xml.namespace.QName;
039:
040: import com.sun.codemodel.internal.ClassType;
041: import com.sun.codemodel.internal.JClassAlreadyExistsException;
042: import com.sun.codemodel.internal.JCodeModel;
043: import com.sun.codemodel.internal.JDefinedClass;
044: import com.sun.tools.internal.xjc.ErrorReceiver;
045: import com.sun.tools.internal.xjc.generator.bean.ImplStructureStrategy;
046: import static com.sun.tools.internal.xjc.generator.bean.ImplStructureStrategy.BEAN_ONLY;
047: import com.sun.tools.internal.xjc.model.Model;
048: import com.sun.tools.internal.xjc.reader.Const;
049: import com.sun.tools.internal.xjc.reader.Ring;
050: import com.sun.tools.internal.xjc.reader.xmlschema.SimpleTypeBuilder;
051: import com.sun.tools.internal.xjc.util.ReadOnlyAdapter;
052: import com.sun.xml.internal.bind.api.impl.NameConverter;
053: import com.sun.xml.internal.bind.v2.WellKnownNamespace;
054: import com.sun.xml.internal.xsom.XSDeclaration;
055: import com.sun.xml.internal.xsom.XSSchemaSet;
056: import com.sun.xml.internal.xsom.XSSimpleType;
057:
058: /**
059: * Global binding customization. The code is highly temporary.
060: *
061: * <p>
062: * One of the information contained in a global customization
063: * is the default binding for properties. This object contains a
064: * BIProperty object to keep this information.
065: *
066: * @author
067: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
068: */
069: @XmlRootElement(name="globalBindings")
070: public final class BIGlobalBinding extends AbstractDeclarationImpl {
071:
072: /**
073: * Gets the name converter that will govern the XML->Java
074: * name conversion process for this compilation.
075: *
076: * <p>
077: * The "underscoreBinding" customization will determine
078: * the exact object returned from this method. The rest of XJC
079: * should just use the NameConverter interface.
080: *
081: * <p>
082: * Always non-null.
083: */
084: @XmlTransient
085: public NameConverter nameConverter = NameConverter.standard;
086:
087: // JAXB will use this property to set nameConverter
088: @XmlAttribute
089: void setUnderscoreBinding(UnderscoreBinding ub) {
090: nameConverter = ub.nc;
091: }
092:
093: UnderscoreBinding getUnderscoreBinding() {
094: throw new IllegalStateException(); // no need for this
095: }
096:
097: public JDefinedClass getSuperClass() {
098: if (super Class == null)
099: return null;
100: return super Class.getClazz(ClassType.CLASS);
101: }
102:
103: public JDefinedClass getSuperInterface() {
104: if (super Interface == null)
105: return null;
106: return super Interface.getClazz(ClassType.INTERFACE);
107: }
108:
109: public BIProperty getDefaultProperty() {
110: return defaultProperty;
111: }
112:
113: public boolean isJavaNamingConventionEnabled() {
114: return isJavaNamingConventionEnabled;
115: }
116:
117: public BISerializable getSerializable() {
118: return serializable;
119: }
120:
121: public boolean isGenerateElementClass() {
122: return generateElementClass;
123: }
124:
125: public boolean isChoiceContentPropertyEnabled() {
126: return choiceContentProperty;
127: }
128:
129: public int getDefaultEnumMemberSizeCap() {
130: return defaultEnumMemberSizeCap;
131: }
132:
133: public boolean isSimpleMode() {
134: return simpleMode != null;
135: }
136:
137: public EnumMemberMode getEnumMemberMode() {
138: return generateEnumMemberName;
139: }
140:
141: public boolean isSimpleTypeSubstitution() {
142: return simpleTypeSubstitution;
143: }
144:
145: public ImplStructureStrategy getCodeGenerationStrategy() {
146: return codeGenerationStrategy;
147: }
148:
149: public LocalScoping getFlattenClasses() {
150: return flattenClasses;
151: }
152:
153: /**
154: * Performs error check
155: */
156: public void errorCheck() {
157: ErrorReceiver er = Ring.get(ErrorReceiver.class);
158: for (QName n : enumBaseTypes) {
159: XSSchemaSet xs = Ring.get(XSSchemaSet.class);
160: XSSimpleType st = xs.getSimpleType(n.getNamespaceURI(), n
161: .getLocalPart());
162: if (st == null) {
163: er.error(loc, Messages.ERR_UNDEFINED_SIMPLE_TYPE
164: .format(n));
165: continue;
166: }
167:
168: if (!SimpleTypeBuilder.canBeMappedToTypeSafeEnum(st)) {
169: er.error(loc,
170: Messages.ERR_CANNOT_BE_BOUND_TO_SIMPLETYPE
171: .format(n));
172: continue;
173: }
174: }
175: }
176:
177: private static enum UnderscoreBinding {
178: @XmlEnumValue("asWordSeparator")
179: WORD_SEPARATOR(NameConverter.standard), @XmlEnumValue("asCharInWord")
180: CHAR_IN_WORD(NameConverter.jaxrpcCompatible);
181:
182: final NameConverter nc;
183:
184: UnderscoreBinding(NameConverter nc) {
185: this .nc = nc;
186: }
187: }
188:
189: /**
190: * Returns true if the "isJavaNamingConventionEnabled" option is turned on.
191: *
192: * In this mode, the compiler is expected to apply XML-to-Java name
193: * conversion algorithm even to names given by customizations.
194: *
195: * This method is intended to be called by other BIXXX classes.
196: * The effect of this switch should be hidden inside this package.
197: * IOW, the reader.xmlschema package shouldn't be aware of this switch.
198: */
199: @XmlAttribute(name="enableJavaNamingConventions")
200: /*package*/boolean isJavaNamingConventionEnabled = true;
201:
202: /**
203: * True to generate classes for every simple type.
204: */
205: @XmlAttribute(name="mapSimpleTypeDef")
206: boolean simpleTypeSubstitution = false;
207:
208: /**
209: * Gets the default defaultProperty customization.
210: */
211: @XmlTransient
212: private BIProperty defaultProperty;
213:
214: /*
215: Three properties used to construct a default property
216: */
217: @XmlAttribute
218: private boolean fixedAttributeAsConstantProperty = false;
219: @XmlAttribute
220: private CollectionTypeAttribute collectionType = new CollectionTypeAttribute();
221:
222: @XmlAttribute
223: void setGenerateIsSetMethod(boolean b) {
224: optionalProperty = b ? OptionalPropertyMode.ISSET
225: : OptionalPropertyMode.WRAPPER;
226: }
227:
228: /**
229: * Returns true if the compiler needs to generate type-safe enum
230: * member names when enumeration values cannot be used as constant names.
231: */
232: @XmlAttribute(name="typesafeEnumMemberName")
233: EnumMemberMode generateEnumMemberName = EnumMemberMode.SKIP;
234:
235: /**
236: * The code generation strategy.
237: */
238: @XmlAttribute(name="generateValueClass")
239: ImplStructureStrategy codeGenerationStrategy = BEAN_ONLY;
240:
241: /**
242: * Set of datatype names. For a type-safe enum class
243: * to be generated, the underlying XML datatype must be derived from
244: * one of the types in this set.
245: */
246: // default value is set in the post-init action
247: @XmlAttribute(name="typesafeEnumBase")
248: private Set<QName> enumBaseTypes;
249:
250: /**
251: * Returns {@link BISerializable} if the extension is specified,
252: * or null otherwise.
253: */
254: @XmlElement
255: private BISerializable serializable = null;
256:
257: /**
258: * If <xjc:superClass> extension is specified,
259: * returns the specified root class. Otherwise null.
260: */
261: @XmlElement(namespace=Const.XJC_EXTENSION_URI)
262: ClassNameBean super Class = null;
263:
264: /**
265: * If <xjc:superInterface> extension is specified,
266: * returns the specified root class. Otherwise null.
267: */
268: @XmlElement(namespace=Const.XJC_EXTENSION_URI)
269: ClassNameBean super Interface = null;
270:
271: /**
272: * Generate the simpler optimized code, but not necessarily
273: * conforming to the spec.
274: */
275: @XmlElement(name="simple",namespace=Const.XJC_EXTENSION_URI)
276: String simpleMode = null;
277:
278: /**
279: * True to generate a class for elements by default.
280: */
281: @XmlAttribute
282: boolean generateElementClass = false;
283:
284: @XmlElement(namespace=Const.XJC_EXTENSION_URI)
285: Boolean generateElementProperty = null;
286:
287: @XmlAttribute
288: boolean choiceContentProperty = false;
289:
290: @XmlAttribute
291: OptionalPropertyMode optionalProperty = OptionalPropertyMode.WRAPPER;
292:
293: /**
294: * Default cap to the number of constants in the enum.
295: * We won't attempt to produce a type-safe enum by default
296: * if there are more enumeration facets than specified in this field.
297: */
298: @XmlAttribute(name="typesafeEnumMaxMembers")
299: int defaultEnumMemberSizeCap = 256;
300:
301: /**
302: * If true, interfaces/classes that are normally generated as a nested interface/class
303: * will be generated into the package, allowing the generated classes to be flat.
304: *
305: * See <a href="http://monaco.sfbay/detail.jsf?cr=4969415">Bug 4969415</a> for the motivation.
306: */
307: @XmlAttribute(name="localScoping")
308: LocalScoping flattenClasses = LocalScoping.NESTED;
309:
310: /**
311: * Globally-defined conversion customizations.
312: *
313: * @see #setGlobalConversions
314: */
315: @XmlTransient
316: private final Map<QName, BIConversion> globalConversions = new HashMap<QName, BIConversion>();
317:
318: // method for JAXB unmarshaller
319: @XmlElement(name="javaType")
320: private void setGlobalConversions(GlobalStandardConversion[] convs) {
321: for (GlobalStandardConversion u : convs) {
322: globalConversions.put(u.xmlType, u);
323: }
324: }
325:
326: @XmlElement(name="javaType",namespace=Const.XJC_EXTENSION_URI)
327: private void setGlobalConversions2(GlobalVendorConversion[] convs) {
328: for (GlobalVendorConversion u : convs) {
329: globalConversions.put(u.xmlType, u);
330: }
331: }
332:
333: //
334: // these customizations were valid in 1.0, but in 2.0 we don't
335: // use them. OTOH, we don't want to issue an error for them,
336: // so we just define a mapping and ignore the value.
337: //
338: @XmlElement(namespace=Const.XJC_EXTENSION_URI)
339: String noMarshaller = null;
340: @XmlElement(namespace=Const.XJC_EXTENSION_URI)
341: String noUnmarshaller = null;
342: @XmlElement(namespace=Const.XJC_EXTENSION_URI)
343: String noValidator = null;
344: @XmlElement(namespace=Const.XJC_EXTENSION_URI)
345: String noValidatingUnmarshaller = null;
346: @XmlElement(namespace=Const.XJC_EXTENSION_URI)
347: TypeSubstitutionElement typeSubstitution = null;
348:
349: /**
350: * Another 1.0 compatibility customization (but we accept it
351: * and treat it as {@link #serializable})
352: */
353: @XmlElement(name="serializable",namespace=Const.XJC_EXTENSION_URI)
354: void setXjcSerializable(BISerializable s) {
355: this .serializable = s;
356: }
357:
358: private static final class TypeSubstitutionElement {
359: @XmlAttribute
360: String type;
361: }
362:
363: public void onSetOwner() {
364: super .onSetOwner();
365: // if one is given by options, use that
366: NameConverter nc = Ring.get(Model.class).options
367: .getNameConverter();
368: if (nc != null)
369: nameConverter = nc;
370: }
371:
372: /**
373: * Creates a bind info object with the default values
374: */
375: public BIGlobalBinding() {
376: }
377:
378: public void setParent(BindInfo parent) {
379: super .setParent(parent);
380: // fill in the remaining default values
381: if (enumBaseTypes == null)
382: enumBaseTypes = Collections.singleton(new QName(
383: WellKnownNamespace.XML_SCHEMA, "string"));
384:
385: this .defaultProperty = new BIProperty(getLocation(), null,
386: null, null, collectionType,
387: fixedAttributeAsConstantProperty, optionalProperty,
388: generateElementProperty);
389: defaultProperty.setParent(parent); // don't forget to initialize the defaultProperty
390: }
391:
392: /**
393: * Moves global BIConversion to the right object.
394: */
395: public void dispatchGlobalConversions(XSSchemaSet schema) {
396: // also set parent to the global conversions
397: for (Map.Entry<QName, BIConversion> e : globalConversions
398: .entrySet()) {
399:
400: QName name = e.getKey();
401: BIConversion conv = e.getValue();
402:
403: XSSimpleType st = schema.getSimpleType(name
404: .getNamespaceURI(), name.getLocalPart());
405: if (st == null) {
406: Ring.get(ErrorReceiver.class)
407: .error(
408: getLocation(),
409: Messages.ERR_UNDEFINED_SIMPLE_TYPE
410: .format(name));
411: continue; // abort
412: }
413:
414: getBuilder().getOrCreateBindInfo(st).addDecl(conv);
415: }
416: }
417:
418: /**
419: * Checks if the given XML Schema built-in type can be mapped to
420: * a type-safe enum class.
421: *
422: * @param typeName
423: */
424: public boolean canBeMappedToTypeSafeEnum(QName typeName) {
425: return enumBaseTypes.contains(typeName);
426: }
427:
428: public boolean canBeMappedToTypeSafeEnum(String nsUri,
429: String localName) {
430: return canBeMappedToTypeSafeEnum(new QName(nsUri, localName));
431: }
432:
433: public boolean canBeMappedToTypeSafeEnum(XSDeclaration decl) {
434: return canBeMappedToTypeSafeEnum(decl.getTargetNamespace(),
435: decl.getName());
436: }
437:
438: public QName getName() {
439: return NAME;
440: }
441:
442: public static final QName NAME = new QName(Const.JAXB_NSURI,
443: "globalBindings");
444:
445: /**
446: * Used to unmarshal
447: * <xmp>
448: * <[element] name="className" />
449: * </xmp>
450: */
451: static final class ClassNameBean {
452: @XmlAttribute(required=true)
453: String name;
454:
455: /**
456: * Computed from {@link #name} on demand.
457: */
458: @XmlTransient
459: JDefinedClass clazz;
460:
461: JDefinedClass getClazz(ClassType t) {
462: if (clazz != null)
463: return clazz;
464: try {
465: JCodeModel codeModel = Ring.get(JCodeModel.class);
466: clazz = codeModel._class(name, t);
467: clazz.hide();
468: return clazz;
469: } catch (JClassAlreadyExistsException e) {
470: return e.getExistingClass();
471: }
472: }
473: }
474:
475: static final class ClassNameAdapter extends
476: ReadOnlyAdapter<ClassNameBean, String> {
477: public String unmarshal(ClassNameBean bean) throws Exception {
478: return bean.name;
479: }
480: }
481:
482: /**
483: * Global <jaxb:javaType>.
484: */
485: static final class GlobalStandardConversion extends
486: BIConversion.User {
487: @XmlAttribute
488: QName xmlType;
489: }
490:
491: /**
492: * Global <xjc:javaType>.
493: */
494: static final class GlobalVendorConversion extends
495: BIConversion.UserAdapter {
496: @XmlAttribute
497: QName xmlType;
498: }
499: }
|