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