Source Code Cross Referenced for SimpleTypeBuilder.java in  » 6.0-JDK-Modules » jaxb-xjc » com » sun » tools » xjc » reader » xmlschema » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » jaxb xjc » com.sun.tools.xjc.reader.xmlschema 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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;
037:
038:        import java.io.StringWriter;
039:        import java.math.BigInteger;
040:        import java.text.ParseException;
041:        import java.util.ArrayList;
042:        import java.util.Collections;
043:        import java.util.HashMap;
044:        import java.util.HashSet;
045:        import java.util.List;
046:        import java.util.Map;
047:        import java.util.Set;
048:        import java.util.Stack;
049:
050:        import javax.activation.MimeTypeParseException;
051:
052:        import com.sun.codemodel.JJavaName;
053:        import com.sun.codemodel.util.JavadocEscapeWriter;
054:        import com.sun.tools.xjc.ErrorReceiver;
055:        import com.sun.tools.xjc.model.CBuiltinLeafInfo;
056:        import com.sun.tools.xjc.model.CClassInfo;
057:        import com.sun.tools.xjc.model.CClassInfoParent;
058:        import com.sun.tools.xjc.model.CClassRef;
059:        import com.sun.tools.xjc.model.CEnumConstant;
060:        import com.sun.tools.xjc.model.CEnumLeafInfo;
061:        import com.sun.tools.xjc.model.CNonElement;
062:        import com.sun.tools.xjc.model.Model;
063:        import com.sun.tools.xjc.model.TypeUse;
064:        import com.sun.tools.xjc.model.TypeUseFactory;
065:        import com.sun.tools.xjc.reader.Ring;
066:        import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIConversion;
067:        import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIEnum;
068:        import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIEnumMember;
069:        import com.sun.tools.xjc.reader.xmlschema.bindinfo.BIProperty;
070:        import com.sun.tools.xjc.reader.xmlschema.bindinfo.BindInfo;
071:        import com.sun.tools.xjc.reader.xmlschema.bindinfo.EnumMemberMode;
072:        import com.sun.tools.xjc.util.MimeTypeRange;
073:        import com.sun.xml.bind.DatatypeConverterImpl;
074:        import com.sun.xml.bind.v2.WellKnownNamespace;
075:        import static com.sun.xml.bind.v2.WellKnownNamespace.XML_MIME_URI;
076:        import com.sun.xml.bind.v2.runtime.SwaRefAdapter;
077:        import com.sun.xml.xsom.XSAttributeDecl;
078:        import com.sun.xml.xsom.XSComplexType;
079:        import com.sun.xml.xsom.XSComponent;
080:        import com.sun.xml.xsom.XSElementDecl;
081:        import com.sun.xml.xsom.XSFacet;
082:        import com.sun.xml.xsom.XSListSimpleType;
083:        import com.sun.xml.xsom.XSRestrictionSimpleType;
084:        import com.sun.xml.xsom.XSSimpleType;
085:        import com.sun.xml.xsom.XSUnionSimpleType;
086:        import com.sun.xml.xsom.XSVariety;
087:        import com.sun.xml.xsom.impl.util.SchemaWriter;
088:        import com.sun.xml.xsom.visitor.XSSimpleTypeFunction;
089:        import com.sun.xml.xsom.visitor.XSVisitor;
090:
091:        import org.xml.sax.Locator;
092:
093:        /**
094:         * Builds {@link TypeUse} from simple types.
095:         *
096:         * <p>
097:         * This code consists of two main portions. The {@link #compose(XSSimpleType)} method
098:         * and {@link #composer} forms an outer cycle, which gradually ascends the type
099:         * inheritance chain until it finds the suitable binding. When it does this
100:         * {@link #initiatingType} is set to the type which started binding, so that we can refer
101:         * to the actual constraint facets and such that are applicable on the type.
102:         *
103:         * <p>
104:         * For each intermediate type in the chain, the {@link #find(XSSimpleType)} method
105:         * is used to find the binding on that type, sine the outer loop is doing the ascending,
106:         * this method only sees if the current type has some binding available.
107:         *
108:         * <p>
109:         * There is at least one ugly code that you need to aware of
110:         * when you are modifying the code. See the documentation
111:         * about <a href="package.html#stref_cust">
112:         * "simple type customization at the point of reference."</a>
113:         *
114:         *
115:         * @author
116:         *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
117:         */
118:        public final class SimpleTypeBuilder extends BindingComponent {
119:
120:            protected final BGMBuilder builder = Ring.get(BGMBuilder.class);
121:
122:            private final Model model = Ring.get(Model.class);
123:
124:            /**
125:             * The component that is refering to the simple type
126:             * which we are building. This is ugly but necessary
127:             * to support the customization of simple types at
128:             * its point of reference. See my comment at the header
129:             * of this class for details.
130:             *
131:             * UGLY: Implemented as a Stack of XSComponent to fix a bug
132:             */
133:            public final Stack<XSComponent> refererStack = new Stack<XSComponent>();
134:
135:            /**
136:             * The type that was originally passed to this {@link SimpleTypeBuilder#build(XSSimpleType)}.
137:             * Never null.
138:             */
139:            private XSSimpleType initiatingType;
140:
141:            /** {@link TypeUse}s for the built-in types. Read-only. */
142:            public static final Map<String, TypeUse> builtinConversions = new HashMap<String, TypeUse>();
143:
144:            /**
145:             * Entry point from outside. Builds a BGM type expression
146:             * from a simple type schema component.
147:             *
148:             * @param type
149:             *      the simple type to be bound.
150:             */
151:            public TypeUse build(XSSimpleType type) {
152:                XSSimpleType oldi = initiatingType;
153:                this .initiatingType = type;
154:
155:                TypeUse e = checkRefererCustomization(type);
156:                if (e == null)
157:                    e = compose(type);
158:
159:                initiatingType = oldi;
160:
161:                return e;
162:            }
163:
164:            /**
165:             * A version of the {@link #build(XSSimpleType)} method
166:             * used to bind the definition of a class generated from
167:             * the given simple type.
168:             */
169:            public TypeUse buildDef(XSSimpleType type) {
170:                XSSimpleType oldi = initiatingType;
171:                this .initiatingType = type;
172:
173:                TypeUse e = type.apply(composer);
174:
175:                initiatingType = oldi;
176:
177:                return e;
178:            }
179:
180:            /**
181:             * Returns a javaType customization specified to the referer, if present.
182:             * @return can be null.
183:             */
184:            private BIConversion getRefererCustomization() {
185:                BindInfo info = builder.getBindInfo(getReferer());
186:                BIProperty prop = info.get(BIProperty.class);
187:                if (prop == null)
188:                    return null;
189:                return prop.getConv();
190:            }
191:
192:            public XSComponent getReferer() {
193:                return refererStack.peek();
194:            }
195:
196:            /**
197:             * Checks if the referer has a conversion customization or not.
198:             * If it does, use it to bind this simple type. Otherwise
199:             * return null;
200:             */
201:            private TypeUse checkRefererCustomization(XSSimpleType type) {
202:
203:                // assertion check. referer must be set properly
204:                // before the build method is called.
205:                // since the handling of the simple type point-of-reference
206:                // customization is very error prone, it deserves a strict
207:                // assertion check.
208:                // UGLY CODE WARNING
209:                XSComponent top = getReferer();
210:
211:                if (top instanceof  XSElementDecl) {
212:                    // if the parent is element type, its content type must be us.
213:                    XSElementDecl eref = (XSElementDecl) top;
214:                    assert eref.getType() == type;
215:
216:                    // for elements, you can't use <property>,
217:                    // so we allow javaType to appear directly.
218:                    BindInfo info = builder.getBindInfo(top);
219:                    BIConversion conv = info.get(BIConversion.class);
220:                    if (conv != null) {
221:                        conv.markAsAcknowledged();
222:                        // the conversion is given.
223:                        return conv.getTypeUse(type);
224:                    }
225:                    detectJavaTypeCustomization();
226:                } else if (top instanceof  XSAttributeDecl) {
227:                    XSAttributeDecl aref = (XSAttributeDecl) top;
228:                    assert aref.getType() == type;
229:                    detectJavaTypeCustomization();
230:                } else if (top instanceof  XSComplexType) {
231:                    XSComplexType tref = (XSComplexType) top;
232:                    assert tref.getBaseType() == type
233:                            || tref.getContentType() == type;
234:                    detectJavaTypeCustomization();
235:                } else if (top == type) {
236:                    // this means the simple type is built by itself and
237:                    // not because it's referenced by something.
238:                } else
239:                    // unexpected referer type.
240:                    assert false;
241:
242:                // now we are certain that the referer is OK.
243:                // see if it has a conversion customization.
244:                BIConversion conv = getRefererCustomization();
245:                if (conv != null) {
246:                    conv.markAsAcknowledged();
247:                    // the conversion is given.
248:                    return conv.getTypeUse(type);
249:                } else
250:                    // not found
251:                    return null;
252:            }
253:
254:            /**
255:             * Detect "javaType" customizations placed directly on simple types, rather
256:             * than being enclosed by "property" and "baseType" customizations (see
257:             * sec 6.8.1 of the spec).
258:             *
259:             * Report an error if any exist.
260:             */
261:            private void detectJavaTypeCustomization() {
262:                BindInfo info = builder.getBindInfo(getReferer());
263:                BIConversion conv = info.get(BIConversion.class);
264:
265:                if (conv != null) {
266:                    // ack this conversion to prevent further error messages
267:                    conv.markAsAcknowledged();
268:
269:                    // report the error
270:                    getErrorReporter()
271:                            .error(
272:                                    conv.getLocation(),
273:                                    Messages.ERR_UNNESTED_JAVATYPE_CUSTOMIZATION_ON_SIMPLETYPE);
274:                }
275:            }
276:
277:            /**
278:             * Recursively decend the type inheritance chain to find a binding.
279:             */
280:            TypeUse compose(XSSimpleType t) {
281:                TypeUse e = find(t);
282:                if (e != null)
283:                    return e;
284:                return t.apply(composer);
285:            }
286:
287:            public final XSSimpleTypeFunction<TypeUse> composer = new XSSimpleTypeFunction<TypeUse>() {
288:
289:                public TypeUse listSimpleType(XSListSimpleType type) {
290:                    // bind item type individually and then compose them into a list
291:                    // facets on the list shouldn't be taken account when binding item types,
292:                    // so weed to call build(), not compose().
293:                    XSSimpleType itemType = type.getItemType();
294:                    refererStack.push(itemType);
295:                    TypeUse tu = TypeUseFactory.makeCollection(build(type
296:                            .getItemType()));
297:                    refererStack.pop();
298:                    return tu;
299:                }
300:
301:                public TypeUse unionSimpleType(XSUnionSimpleType type) {
302:                    boolean isCollection = false;
303:                    for (int i = 0; i < type.getMemberSize(); i++)
304:                        if (type.getMember(i).getVariety() == XSVariety.LIST) {
305:                            isCollection = true;
306:                            break;
307:                        }
308:
309:                    TypeUse r = CBuiltinLeafInfo.STRING;
310:                    if (isCollection)
311:                        r = TypeUseFactory.makeCollection(r);
312:                    return r;
313:                }
314:
315:                public TypeUse restrictionSimpleType(
316:                        XSRestrictionSimpleType type) {
317:                    // just process the base type.
318:                    return compose(type.getSimpleBaseType());
319:                }
320:            };
321:
322:            /**
323:             * Checks if there's any binding available on the given type.
324:             *
325:             * @return
326:             *      null if not (which causes the {@link #compose(XSSimpleType)} method
327:             *      to do ascending.
328:             */
329:            private TypeUse find(XSSimpleType type) {
330:                TypeUse r;
331:                boolean noAutoEnum = false;
332:
333:                // check for user specified conversion
334:                BindInfo info = builder.getBindInfo(type);
335:                BIConversion conv = info.get(BIConversion.class);
336:
337:                if (conv != null) {
338:                    // a conversion was found
339:                    conv.markAsAcknowledged();
340:                    return conv.getTypeUse(type);
341:                }
342:
343:                // look for enum customization, which is another user specified conversion
344:                BIEnum en = info.get(BIEnum.class);
345:                if (en != null) {
346:                    en.markAsAcknowledged();
347:
348:                    if (!en.isMapped()) {
349:                        noAutoEnum = true;
350:                    } else {
351:                        // if an enum customization is specified, make sure
352:                        // the type is OK
353:                        if (!canBeMappedToTypeSafeEnum(type)) {
354:                            getErrorReporter().error(en.getLocation(),
355:                                    Messages.ERR_CANNOT_BE_TYPE_SAFE_ENUM);
356:                            getErrorReporter()
357:                                    .error(
358:                                            type.getLocator(),
359:                                            Messages.ERR_CANNOT_BE_TYPE_SAFE_ENUM_LOCATION);
360:                            // recover by ignoring this customization
361:                            return null;
362:                        }
363:
364:                        // reference?
365:                        if (en.ref != null) {
366:                            if (!JJavaName.isFullyQualifiedClassName(en.ref)) {
367:                                Ring
368:                                        .get(ErrorReceiver.class)
369:                                        .error(
370:                                                en.getLocation(),
371:                                                Messages
372:                                                        .format(
373:                                                                Messages.ERR_INCORRECT_CLASS_NAME,
374:                                                                en.ref));
375:                                // recover by ignoring @ref
376:                                return null;
377:                            }
378:
379:                            return new CClassRef(model, type, en, info
380:                                    .toCustomizationList());
381:                        }
382:
383:                        // list and union cannot be mapped to a type-safe enum,
384:                        // so in this stage we can safely cast it to XSRestrictionSimpleType
385:                        return bindToTypeSafeEnum(
386:                                (XSRestrictionSimpleType) type, en.className,
387:                                en.javadoc, en.members, getEnumMemberMode()
388:                                        .getModeWithEnum(), en.getLocation());
389:                    }
390:                }
391:
392:                // if the type is built in, look for the default binding
393:                if (type.getTargetNamespace().equals(
394:                        WellKnownNamespace.XML_SCHEMA)) {
395:                    String name = type.getName();
396:                    if (name != null) {
397:                        r = lookupBuiltin(name);
398:                        if (r != null)
399:                            return r;
400:                    }
401:                }
402:
403:                // also check for swaRef
404:                if (type.getTargetNamespace()
405:                        .equals(WellKnownNamespace.SWA_URI)) {
406:                    String name = type.getName();
407:                    if (name != null && name.equals("swaRef"))
408:                        return CBuiltinLeafInfo.STRING.makeAdapted(
409:                                SwaRefAdapter.class, false);
410:                }
411:
412:                // see if this type should be mapped to a type-safe enumeration by default.
413:                // if so, built a EnumXDucer from it and return it.
414:                if (type.isRestriction() && !noAutoEnum) {
415:                    XSRestrictionSimpleType rst = type.asRestriction();
416:                    if (shouldBeMappedToTypeSafeEnumByDefault(rst)) {
417:                        r = bindToTypeSafeEnum(rst, null, null, Collections
418:                                .<String, BIEnumMember> emptyMap(),
419:                                getEnumMemberMode(), null);
420:                        if (r != null)
421:                            return r;
422:                    }
423:                }
424:
425:                return (CNonElement) getClassSelector()._bindToClass(type,
426:                        null, false);
427:            }
428:
429:            /**
430:             * Returns true if a type-safe enum should be created from
431:             * the given simple type by default without an explicit &lt;jaxb:enum> customization.
432:             */
433:            private boolean shouldBeMappedToTypeSafeEnumByDefault(
434:                    XSRestrictionSimpleType type) {
435:
436:                // if not, there will be a problem wrt the class name of this type safe enum type.
437:                if (type.isLocal())
438:                    return false;
439:
440:                // if redefined, we should map the new definition, not the old one.
441:                if (type.getRedefinedBy() != null)
442:                    return false;
443:
444:                List<XSFacet> facets = type
445:                        .getDeclaredFacets(XSFacet.FACET_ENUMERATION);
446:                if (facets.isEmpty()
447:                        || facets.size() > builder.getGlobalBinding()
448:                                .getDefaultEnumMemberSizeCap())
449:                    // if the type itself doesn't have the enumeration facet,
450:                    // it won't be mapped to a type-safe enum.
451:                    //
452:                    // if there are too many facets, it's not very useful
453:                    return false;
454:
455:                if (!canBeMappedToTypeSafeEnum(type))
456:                    // we simply can't map this to an enumeration
457:                    return false;
458:
459:                // check for collisions among constant names. if a collision will happen,
460:                // don't try to bind it to an enum.
461:
462:                // return true only when this type is derived from one of the "enum base type".
463:                for (XSSimpleType t = type; t != null; t = t
464:                        .getSimpleBaseType())
465:                    if (t.isGlobal()
466:                            && builder.getGlobalBinding()
467:                                    .canBeMappedToTypeSafeEnum(t))
468:                        return true;
469:
470:                return false;
471:            }
472:
473:            private static final Set<String> builtinTypeSafeEnumCapableTypes;
474:
475:            static {
476:                Set<String> s = new HashSet<String>();
477:
478:                // see a bullet of 6.5.1 of the spec.
479:                String[] typeNames = new String[] { "string", "boolean",
480:                        "float", "decimal", "double", "anyURI" };
481:
482:                for (String type : typeNames)
483:                    s.add(type);
484:
485:                builtinTypeSafeEnumCapableTypes = Collections
486:                        .unmodifiableSet(s);
487:            }
488:
489:            /**
490:             * Returns true if the given simple type can be mapped to a
491:             * type-safe enum class.
492:             *
493:             * <p>
494:             * JAXB spec places a restrictrion as to what type can be
495:             * mapped to a type-safe enum. This method enforces this
496:             * constraint.
497:             */
498:            public static boolean canBeMappedToTypeSafeEnum(XSSimpleType type) {
499:                do {
500:                    if (WellKnownNamespace.XML_SCHEMA.equals(type
501:                            .getTargetNamespace())) {
502:                        // type must be derived from one of these types
503:                        String localName = type.getName();
504:                        if (localName != null) {
505:                            if (localName.equals("anySimpleType"))
506:                                return false; // catch all case
507:                            if (localName.equals("ID")
508:                                    || localName.equals("IDREF"))
509:                                return false; // not ID/IDREF
510:
511:                            // other allowed list
512:                            if (builtinTypeSafeEnumCapableTypes
513:                                    .contains(localName))
514:                                return true;
515:                        }
516:                    }
517:
518:                    type = type.getSimpleBaseType();
519:                } while (type != null);
520:
521:                return false;
522:            }
523:
524:            /**
525:             * Builds a type-safe enum conversion from a simple type
526:             * with enumeration facets.
527:             *
528:             * @param className
529:             *      The class name of the type-safe enum. Or null to
530:             *      create a default name.
531:             * @param javadoc
532:             *      Additional javadoc that will be added at the beginning of the
533:             *      class, or null if none is necessary.
534:             * @param members
535:             *      A map from enumeration values (as String) to BIEnumMember objects.
536:             *      if some of the value names need to be overrided.
537:             *      Cannot be null, but the map may not contain entries
538:             *      for all enumeration values.
539:             * @param loc
540:             *      The source location where the above customizations are
541:             *      specified, or null if none is available.
542:             */
543:            private TypeUse bindToTypeSafeEnum(XSRestrictionSimpleType type,
544:                    String className, String javadoc,
545:                    Map<String, BIEnumMember> members, EnumMemberMode mode,
546:                    Locator loc) {
547:
548:                if (loc == null) // use the location of the simple type as the default
549:                    loc = type.getLocator();
550:
551:                if (className == null) {
552:                    // infer the class name. For this to be possible,
553:                    // the simple type must be a global one.
554:                    if (!type.isGlobal()) {
555:                        getErrorReporter().error(loc,
556:                                Messages.ERR_NO_ENUM_NAME_AVAILABLE);
557:                        // recover by returning a meaningless conversion
558:                        return CBuiltinLeafInfo.STRING;
559:                    }
560:                    className = type.getName();
561:                }
562:
563:                // we apply name conversion in any case
564:                className = builder.deriveName(className, type);
565:
566:                {// compute Javadoc
567:                    StringWriter out = new StringWriter();
568:                    SchemaWriter sw = new SchemaWriter(new JavadocEscapeWriter(
569:                            out));
570:                    type.visit((XSVisitor) sw);
571:
572:                    if (javadoc != null)
573:                        javadoc += "\n\n";
574:                    else
575:                        javadoc = "";
576:
577:                    javadoc += Messages.format(Messages.JAVADOC_HEADING, type
578:                            .getName())
579:                            + "\n<p>\n<pre>\n" + out.getBuffer() + "</pre>";
580:
581:                }
582:
583:                // build base type
584:                refererStack.push(type.getSimpleBaseType());
585:                TypeUse use = build(type.getSimpleBaseType());
586:                refererStack.pop();
587:
588:                if (use.isCollection())
589:                    return null; // can't bind a list to enum constant
590:
591:                CNonElement baseDt = use.getInfo(); // for now just ignore that case
592:
593:                if (baseDt instanceof  CClassInfo)
594:                    return null; // can't bind to an enum if the base is a class, since we don't have the value constrctor
595:
596:                // if the member names collide, re-generate numbered constant names.
597:                XSFacet[] errorRef = new XSFacet[1];
598:                List<CEnumConstant> memberList = buildCEnumConstants(type,
599:                        false, members, errorRef);
600:                if (memberList == null
601:                        || checkMemberNameCollision(memberList) != null) {
602:                    switch (mode) {
603:                    case SKIP:
604:                        // abort
605:                        return null;
606:                    case ERROR:
607:                        // error
608:                        if (memberList == null) {
609:                            getErrorReporter().error(errorRef[0].getLocator(),
610:                                    Messages.ERR_CANNOT_GENERATE_ENUM_NAME,
611:                                    errorRef[0].getValue());
612:                        } else {
613:                            CEnumConstant[] collision = checkMemberNameCollision(memberList);
614:                            getErrorReporter().error(collision[0].getLocator(),
615:                                    Messages.ERR_ENUM_MEMBER_NAME_COLLISION,
616:                                    collision[0].getName());
617:                            getErrorReporter()
618:                                    .error(
619:                                            collision[1].getLocator(),
620:                                            Messages.ERR_ENUM_MEMBER_NAME_COLLISION_RELATED);
621:                        }
622:                        return null; // recover from error
623:                    case GENERATE:
624:                        // generate
625:                        memberList = buildCEnumConstants(type, true, members,
626:                                null);
627:                        break;
628:                    }
629:                }
630:
631:                // use the name of the simple type as the name of the class.
632:                CClassInfoParent scope;
633:                if (type.isGlobal())
634:                    scope = new CClassInfoParent.Package(getClassSelector()
635:                            .getPackage(type.getTargetNamespace()));
636:                else
637:                    scope = getClassSelector().getClassScope();
638:                CEnumLeafInfo xducer = new CEnumLeafInfo(model, BGMBuilder
639:                        .getName(type), scope, className, baseDt, memberList,
640:                        type, builder.getBindInfo(type).toCustomizationList(),
641:                        loc);
642:                xducer.javadoc = javadoc;
643:
644:                BIConversion conv = new BIConversion.Static(type.getLocator(),
645:                        xducer);
646:                conv.markAsAcknowledged();
647:
648:                // attach this new conversion object to this simple type
649:                // so that successive look up will use the same object.
650:                builder.getOrCreateBindInfo(type).addDecl(conv);
651:
652:                return conv.getTypeUse(type);
653:            }
654:
655:            /**
656:             *
657:             * @param errorRef
658:             *      if constant names couldn't be generated, return a reference to that enum facet.
659:             * @return
660:             *      null if unable to generate names for some of the constants.
661:             */
662:            private List<CEnumConstant> buildCEnumConstants(
663:                    XSRestrictionSimpleType type,
664:                    boolean needsToGenerateMemberName,
665:                    Map<String, BIEnumMember> members, XSFacet[] errorRef) {
666:                List<CEnumConstant> memberList = new ArrayList<CEnumConstant>();
667:                int idx = 1;
668:                Set<String> enums = new HashSet<String>(); // to avoid duplicates. See issue #366
669:
670:                for (XSFacet facet : type
671:                        .getDeclaredFacets(XSFacet.FACET_ENUMERATION)) {
672:                    String name = null;
673:                    String mdoc = builder.getBindInfo(facet).getDocumentation();
674:
675:                    if (!enums.add(facet.getValue().value))
676:                        continue; // ignore the 2nd occasion
677:
678:                    if (needsToGenerateMemberName) {
679:                        // generate names for all member names.
680:                        // this will even override names specified by the user. that's crazy.
681:                        name = "VALUE_" + (idx++);
682:                    } else {
683:                        String facetValue = facet.getValue().value;
684:                        BIEnumMember mem = members.get(facetValue);
685:                        if (mem == null)
686:                            // look at the one attached to the facet object
687:                            mem = builder.getBindInfo(facet).get(
688:                                    BIEnumMember.class);
689:
690:                        if (mem != null) {
691:                            name = mem.name;
692:                            mdoc = mem.javadoc;
693:                        }
694:
695:                        if (name == null) {
696:                            StringBuilder sb = new StringBuilder();
697:                            for (int i = 0; i < facetValue.length(); i++) {
698:                                char ch = facetValue.charAt(i);
699:                                if (Character.isJavaIdentifierPart(ch))
700:                                    sb.append(ch);
701:                                else
702:                                    sb.append('_');
703:                            }
704:                            name = model.getNameConverter().toConstantName(
705:                                    sb.toString());
706:                        }
707:                    }
708:
709:                    if (!JJavaName.isJavaIdentifier(name)) {
710:                        if (errorRef != null)
711:                            errorRef[0] = facet;
712:                        return null; // unable to generate a name
713:                    }
714:
715:                    memberList.add(new CEnumConstant(name, mdoc, facet
716:                            .getValue().value, facet.getLocator()));
717:                }
718:                return memberList;
719:            }
720:
721:            /**
722:             * Returns non-null if {@link CEnumConstant}s have name collisions among them.
723:             *
724:             * @return
725:             *      if there's a collision, return two {@link CEnumConstant}s that collided.
726:             *      otherwise return null.
727:             */
728:            private CEnumConstant[] checkMemberNameCollision(
729:                    List<CEnumConstant> memberList) {
730:                Map<String, CEnumConstant> names = new HashMap<String, CEnumConstant>();
731:                for (CEnumConstant c : memberList) {
732:                    CEnumConstant old = names.put(c.getName(), c);
733:                    if (old != null)
734:                        // collision detected
735:                        return new CEnumConstant[] { old, c };
736:                }
737:                return null;
738:            }
739:
740:            private EnumMemberMode getEnumMemberMode() {
741:                return builder.getGlobalBinding().getEnumMemberMode();
742:            }
743:
744:            private TypeUse lookupBuiltin(String typeLocalName) {
745:                if (typeLocalName.equals("integer")
746:                        || typeLocalName.equals("long")) {
747:                    /*
748:                        attempt an optimization so that we can
749:                        improve the binding for types like this:
750:
751:                        <simpleType>
752:                          <restriciton baseType="integer">
753:                            <maxInclusive value="100" />
754:                          </
755:                        </
756:
757:                        ... to int, not BigInteger.
758:                     */
759:
760:                    BigInteger xe = readFacet(XSFacet.FACET_MAXEXCLUSIVE, -1);
761:                    BigInteger xi = readFacet(XSFacet.FACET_MAXINCLUSIVE, 0);
762:                    BigInteger max = min(xe, xi); // most restrictive one takes precedence
763:
764:                    if (max != null) {
765:                        BigInteger ne = readFacet(XSFacet.FACET_MINEXCLUSIVE,
766:                                +1);
767:                        BigInteger ni = readFacet(XSFacet.FACET_MININCLUSIVE, 0);
768:                        BigInteger min = max(ne, ni);
769:
770:                        if (min != null) {
771:                            if (min.compareTo(INT_MIN) >= 0
772:                                    && max.compareTo(INT_MAX) <= 0)
773:                                typeLocalName = "int";
774:                            else if (min.compareTo(LONG_MIN) >= 0
775:                                    && max.compareTo(LONG_MAX) <= 0)
776:                                typeLocalName = "long";
777:                        }
778:                    }
779:                } else if (typeLocalName.equals("boolean")
780:                        && isRestrictedTo0And1()) {
781:                    // this is seen in the SOAP schema and too common to ignore
782:                    return CBuiltinLeafInfo.BOOLEAN_ZERO_OR_ONE;
783:                } else if (typeLocalName.equals("base64Binary")) {
784:                    return lookupBinaryTypeBinding();
785:                } else if (typeLocalName.equals("anySimpleType")) {
786:                    if (getReferer() instanceof  XSAttributeDecl
787:                            || getReferer() instanceof  XSSimpleType)
788:                        return CBuiltinLeafInfo.STRING;
789:                    else
790:                        return CBuiltinLeafInfo.ANYTYPE;
791:                }
792:                return builtinConversions.get(typeLocalName);
793:            }
794:
795:            /**
796:             * Decides the way xs:base64Binary binds.
797:             *
798:             * This method checks the expected media type.
799:             */
800:            private TypeUse lookupBinaryTypeBinding() {
801:                XSComponent referer = getReferer();
802:                String emt = referer.getForeignAttribute(XML_MIME_URI,
803:                        "expectedContentTypes");
804:                if (emt != null) {
805:                    try {
806:                        // see http://www.xml.com/lpt/a/2004/07/21/dive.html
807:                        List<MimeTypeRange> types = MimeTypeRange
808:                                .parseRanges(emt);
809:                        MimeTypeRange mt = MimeTypeRange.merge(types);
810:
811:                        // see spec table I-1 in appendix I section 2.1.1 for bindings
812:                        if (mt.majorType.equals("image"))
813:                            return CBuiltinLeafInfo.IMAGE.makeMimeTyped(mt
814:                                    .toMimeType());
815:
816:                        if ((mt.majorType.equals("application") || mt.majorType
817:                                .equals("text"))
818:                                && isXml(mt.subType))
819:                            return CBuiltinLeafInfo.XML_SOURCE.makeMimeTyped(mt
820:                                    .toMimeType());
821:
822:                        if ((mt.majorType.equals("text") && (mt.subType
823:                                .equals("plain")))) {
824:                            return CBuiltinLeafInfo.STRING.makeMimeTyped(mt
825:                                    .toMimeType());
826:                        }
827:
828:                        return CBuiltinLeafInfo.DATA_HANDLER.makeMimeTyped(mt
829:                                .toMimeType());
830:                    } catch (ParseException e) {
831:                        getErrorReporter()
832:                                .error(
833:                                        referer.getLocator(),
834:                                        Messages
835:                                                .format(
836:                                                        Messages.ERR_ILLEGAL_EXPECTED_MIME_TYPE,
837:                                                        emt, e.getMessage()));
838:                        // recover by using the default
839:                    } catch (MimeTypeParseException e) {
840:                        getErrorReporter()
841:                                .error(
842:                                        referer.getLocator(),
843:                                        Messages
844:                                                .format(
845:                                                        Messages.ERR_ILLEGAL_EXPECTED_MIME_TYPE,
846:                                                        emt, e.getMessage()));
847:                    }
848:                }
849:                // default
850:                return CBuiltinLeafInfo.BASE64_BYTE_ARRAY;
851:            }
852:
853:            /**
854:             * Returns true if the specified sub-type is an XML type.
855:             */
856:            private boolean isXml(String subType) {
857:                return subType.equals("xml") || subType.endsWith("+xml");
858:            }
859:
860:            /**
861:             * Returns true if the {@link #initiatingType} is restricted
862:             * to '0' and '1'. This logic is not complete, but it at least
863:             * finds the such definition in SOAP @mustUnderstand.
864:             */
865:            private boolean isRestrictedTo0And1() {
866:                XSFacet pattern = initiatingType
867:                        .getFacet(XSFacet.FACET_PATTERN);
868:                if (pattern != null) {
869:                    String v = pattern.getValue().value;
870:                    if (v.equals("0|1") || v.equals("1|0") || v.equals("\\d"))
871:                        return true;
872:                }
873:                XSFacet enumf = initiatingType
874:                        .getFacet(XSFacet.FACET_ENUMERATION);
875:                if (enumf != null) {
876:                    String v = enumf.getValue().value;
877:                    if (v.equals("0") || v.equals("1"))
878:                        return true;
879:                }
880:                return false;
881:            }
882:
883:            private BigInteger readFacet(String facetName, int offset) {
884:                XSFacet me = initiatingType.getFacet(facetName);
885:                if (me == null)
886:                    return null;
887:                BigInteger bi = DatatypeConverterImpl._parseInteger(me
888:                        .getValue().value);
889:                if (offset != 0)
890:                    bi = bi.add(BigInteger.valueOf(offset));
891:                return bi;
892:            }
893:
894:            private BigInteger min(BigInteger a, BigInteger b) {
895:                if (a == null)
896:                    return b;
897:                if (b == null)
898:                    return a;
899:                return a.min(b);
900:            }
901:
902:            private BigInteger max(BigInteger a, BigInteger b) {
903:                if (a == null)
904:                    return b;
905:                if (b == null)
906:                    return a;
907:                return a.max(b);
908:            }
909:
910:            private static final BigInteger LONG_MIN = BigInteger
911:                    .valueOf(Long.MIN_VALUE);
912:            private static final BigInteger LONG_MAX = BigInteger
913:                    .valueOf(Long.MAX_VALUE);
914:            private static final BigInteger INT_MIN = BigInteger
915:                    .valueOf(Integer.MIN_VALUE);
916:            private static final BigInteger INT_MAX = BigInteger
917:                    .valueOf(Integer.MAX_VALUE);
918:
919:            static {
920:                // list of datatypes which have built-in conversions.
921:                // note that although xs:token and xs:normalizedString are not
922:                // specified in the spec, they need to be here because they
923:                // have different whitespace normalization semantics.
924:                Map<String, TypeUse> m = builtinConversions;
925:
926:                // TODO: this is so dumb
927:                m.put("string", CBuiltinLeafInfo.STRING);
928:                m.put("anyURI", CBuiltinLeafInfo.STRING);
929:                m.put("boolean", CBuiltinLeafInfo.BOOLEAN);
930:                // we'll also look at the expected media type, so don't just add this to the map
931:                // m.put("base64Binary",   CBuiltinLeafInfo.BASE64_BYTE_ARRAY);
932:                m.put("hexBinary", CBuiltinLeafInfo.HEXBIN_BYTE_ARRAY);
933:                m.put("float", CBuiltinLeafInfo.FLOAT);
934:                m.put("decimal", CBuiltinLeafInfo.BIG_DECIMAL);
935:                m.put("integer", CBuiltinLeafInfo.BIG_INTEGER);
936:                m.put("long", CBuiltinLeafInfo.LONG);
937:                m.put("unsignedInt", CBuiltinLeafInfo.LONG);
938:                m.put("int", CBuiltinLeafInfo.INT);
939:                m.put("unsignedShort", CBuiltinLeafInfo.INT);
940:                m.put("short", CBuiltinLeafInfo.SHORT);
941:                m.put("unsignedByte", CBuiltinLeafInfo.SHORT);
942:                m.put("byte", CBuiltinLeafInfo.BYTE);
943:                m.put("double", CBuiltinLeafInfo.DOUBLE);
944:                m.put("QName", CBuiltinLeafInfo.QNAME);
945:                m.put("NOTATION", CBuiltinLeafInfo.QNAME);
946:                m.put("dateTime", CBuiltinLeafInfo.CALENDAR);
947:                m.put("date", CBuiltinLeafInfo.CALENDAR);
948:                m.put("time", CBuiltinLeafInfo.CALENDAR);
949:                m.put("gYearMonth", CBuiltinLeafInfo.CALENDAR);
950:                m.put("gYear", CBuiltinLeafInfo.CALENDAR);
951:                m.put("gMonthDay", CBuiltinLeafInfo.CALENDAR);
952:                m.put("gDay", CBuiltinLeafInfo.CALENDAR);
953:                m.put("gMonth", CBuiltinLeafInfo.CALENDAR);
954:                m.put("duration", CBuiltinLeafInfo.DURATION);
955:                m.put("token", CBuiltinLeafInfo.TOKEN);
956:                m.put("normalizedString", CBuiltinLeafInfo.NORMALIZED_STRING);
957:                m.put("ID", CBuiltinLeafInfo.ID);
958:                m.put("IDREF", CBuiltinLeafInfo.IDREF);
959:                // TODO: handling dateTime, time, and date type
960:                //        String[] names = {
961:                //            "date", "dateTime", "time", "hexBinary" };
962:            }
963:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.