Source Code Cross Referenced for UnmarshallingContext.java in  » 6.0-JDK-Modules-com.sun » xml » com » sun » xml » internal » bind » v2 » runtime » unmarshaller » 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 com.sun » xml » com.sun.xml.internal.bind.v2.runtime.unmarshaller 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package com.sun.xml.internal.bind.v2.runtime.unmarshaller;
0027:
0028:        import java.lang.reflect.InvocationTargetException;
0029:        import java.lang.reflect.Method;
0030:        import java.util.ArrayList;
0031:        import java.util.Collection;
0032:        import java.util.Collections;
0033:        import java.util.HashMap;
0034:        import java.util.Iterator;
0035:        import java.util.List;
0036:        import java.util.Map;
0037:        import java.util.concurrent.Callable;
0038:
0039:        import javax.xml.XMLConstants;
0040:        import javax.xml.bind.JAXBElement;
0041:        import javax.xml.bind.UnmarshalException;
0042:        import javax.xml.bind.Unmarshaller;
0043:        import javax.xml.bind.ValidationEvent;
0044:        import javax.xml.bind.ValidationEventHandler;
0045:        import javax.xml.bind.ValidationEventLocator;
0046:        import javax.xml.bind.helpers.ValidationEventImpl;
0047:        import javax.xml.bind.helpers.ValidationEventLocatorImpl;
0048:        import javax.xml.namespace.NamespaceContext;
0049:        import javax.xml.namespace.QName;
0050:
0051:        import com.sun.istack.internal.NotNull;
0052:        import com.sun.istack.internal.SAXParseException2;
0053:        import com.sun.xml.internal.bind.IDResolver;
0054:        import com.sun.xml.internal.bind.api.AccessorException;
0055:        import com.sun.xml.internal.bind.unmarshaller.InfosetScanner;
0056:        import com.sun.xml.internal.bind.v2.ClassFactory;
0057:        import com.sun.xml.internal.bind.v2.runtime.AssociationMap;
0058:        import com.sun.xml.internal.bind.v2.runtime.Coordinator;
0059:        import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
0060:        import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo;
0061:
0062:        import org.xml.sax.ErrorHandler;
0063:        import org.xml.sax.Locator;
0064:        import org.xml.sax.SAXException;
0065:        import org.xml.sax.helpers.LocatorImpl;
0066:
0067:        /**
0068:         * Center of the unmarshalling.
0069:         *
0070:         * <p>
0071:         * This object is responsible for coordinating {@link Loader}s to
0072:         * perform the whole unmarshalling.
0073:         *
0074:         * @author Kohsuke Kawaguchi
0075:         */
0076:        public final class UnmarshallingContext extends Coordinator implements 
0077:                NamespaceContext, ValidationEventHandler, ErrorHandler,
0078:                XmlVisitor, XmlVisitor.TextPredictor {
0079:
0080:            /**
0081:             * Root state.
0082:             */
0083:            private final State root;
0084:
0085:            /**
0086:             * The currently active state.
0087:             */
0088:            private State current;
0089:
0090:            private @NotNull
0091:            LocatorEx locator = DUMMY_INSTANCE;
0092:
0093:            /** Root object that is being unmarshalled. */
0094:            private Object result;
0095:
0096:            /**
0097:             * If non-null, this unmarshaller will unmarshal {@code JAXBElement<EXPECTEDTYPE>}
0098:             * regardless of the tag name, as opposed to deciding the root object by using
0099:             * the tag name.
0100:             *
0101:             * The property has a package-level access, because we cannot copy this value
0102:             * to {@link UnmarshallingContext} when it is created. The property
0103:             * on {@link Unmarshaller} could be changed after the handler is created.
0104:             */
0105:            private JaxBeanInfo expectedType;
0106:
0107:            /**
0108:             * Handles ID/IDREF.
0109:             */
0110:            private IDResolver idResolver;
0111:
0112:            /**
0113:             * This flag is set to true at the startDocument event
0114:             * and false at the endDocument event.
0115:             *
0116:             * Until the first document is unmarshalled, we don't
0117:             * want to return an object. So this variable is initialized
0118:             * to true.
0119:             */
0120:            private boolean isUnmarshalInProgress = true;
0121:            private boolean aborted = false;
0122:
0123:            public final UnmarshallerImpl parent;
0124:
0125:            /**
0126:             * If the unmarshaller is doing associative unmarshalling,
0127:             * this field is initialized to non-null.
0128:             */
0129:            private final AssociationMap assoc;
0130:
0131:            /**
0132:             * Indicates whether we are doing in-place unmarshalling
0133:             * or not.
0134:             *
0135:             * <p>
0136:             * This flag is unused when {@link #assoc}==null.
0137:             * If it's non-null, then <tt>true</tt> indicates
0138:             * that we are doing in-place associative unmarshalling.
0139:             * If <tt>false</tt>, then we are doing associative unmarshalling
0140:             * without object reuse.
0141:             */
0142:            private boolean isInplaceMode;
0143:
0144:            /**
0145:             * This object is consulted to get the element object for
0146:             * the current element event.
0147:             *
0148:             * This is used when we are building an association map.
0149:             */
0150:            private InfosetScanner scanner;
0151:
0152:            private Object currentElement;
0153:
0154:            /**
0155:             * @see XmlVisitor#startDocument(LocatorEx, NamespaceContext)
0156:             */
0157:            private NamespaceContext environmentNamespaceContext;
0158:
0159:            /**
0160:             * State information for each element.
0161:             */
0162:            public final class State {
0163:                /**
0164:                 * Loader that owns this element.
0165:                 */
0166:                public Loader loader;
0167:                /**
0168:                 * Once {@link #loader} is completed, this receiver
0169:                 * receives the result.
0170:                 */
0171:                public Receiver receiver;
0172:
0173:                public Intercepter intercepter;
0174:
0175:                /**
0176:                 * Object being unmarshalled by this {@link #loader}.
0177:                 */
0178:                public Object target;
0179:
0180:                /**
0181:                 * Hack for making JAXBElement unmarshalling work.
0182:                 */
0183:                public Object backup;
0184:
0185:                /**
0186:                 * Number of {@link UnmarshallingContext#nsBind}s declared thus far.
0187:                 * (The value of {@link UnmarshallingContext#nsLen} when this state is pushed.
0188:                 */
0189:                private int numNsDecl;
0190:
0191:                /**
0192:                 * If this element has an element default value.
0193:                 *
0194:                 * This should be set by either a parent {@link Loader} when
0195:                 * {@link Loader#childElement(State, TagName)} is called
0196:                 * or by a child {@link Loader} when
0197:                 * {@link Loader#startElement(State, TagName)} is called.
0198:                 */
0199:                public String elementDefaultValue;
0200:
0201:                /**
0202:                 * {@link State} for the parent element
0203:                 *
0204:                 * {@link State} objects form a doubly linked list.
0205:                 */
0206:                public final State prev;
0207:                private State next;
0208:
0209:                /**
0210:                 * Gets the context.
0211:                 */
0212:                public UnmarshallingContext getContext() {
0213:                    return UnmarshallingContext.this ;
0214:                }
0215:
0216:                private State(State prev) {
0217:                    this .prev = prev;
0218:                    if (prev != null)
0219:                        prev.next = this ;
0220:                }
0221:
0222:                private void push() {
0223:                    if (next == null)
0224:                        allocateMoreStates();
0225:                    State n = next;
0226:                    n.numNsDecl = nsLen;
0227:                    current = n;
0228:                }
0229:
0230:                private void pop() {
0231:                    assert prev != null;
0232:                    loader = null;
0233:                    receiver = null;
0234:                    intercepter = null;
0235:                    elementDefaultValue = null;
0236:                    target = null;
0237:                    current = prev;
0238:                }
0239:            }
0240:
0241:            /**
0242:             * Stub to the user-specified factory method.
0243:             */
0244:            private static class Factory {
0245:                private final Object factorInstance;
0246:                private final Method method;
0247:
0248:                public Factory(Object factorInstance, Method method) {
0249:                    this .factorInstance = factorInstance;
0250:                    this .method = method;
0251:                }
0252:
0253:                public Object createInstance() throws SAXException {
0254:                    try {
0255:                        return method.invoke(factorInstance);
0256:                    } catch (IllegalAccessException e) {
0257:                        getInstance().handleError(e, false);
0258:                    } catch (InvocationTargetException e) {
0259:                        getInstance().handleError(e, false);
0260:                    }
0261:                    return null; // can never be executed
0262:                }
0263:            }
0264:
0265:            /**
0266:             * Creates a new unmarshaller.
0267:             *
0268:             * @param assoc
0269:             *      Must be both non-null when the unmarshaller does the
0270:             *      in-place unmarshalling. Otherwise must be both null.
0271:             */
0272:            public UnmarshallingContext(UnmarshallerImpl _parent,
0273:                    AssociationMap assoc) {
0274:                this .parent = _parent;
0275:                this .assoc = assoc;
0276:                this .root = this .current = new State(null);
0277:                allocateMoreStates();
0278:            }
0279:
0280:            public void reset(InfosetScanner scanner, boolean isInplaceMode,
0281:                    JaxBeanInfo expectedType, IDResolver idResolver) {
0282:                this .scanner = scanner;
0283:                this .isInplaceMode = isInplaceMode;
0284:                this .expectedType = expectedType;
0285:                this .idResolver = idResolver;
0286:            }
0287:
0288:            public JAXBContextImpl getJAXBContext() {
0289:                return parent.context;
0290:            }
0291:
0292:            public State getCurrentState() {
0293:                return current;
0294:            }
0295:
0296:            /**
0297:             * Allocates a few more {@link State}s.
0298:             *
0299:             * Allocating multiple {@link State}s at once allows those objects
0300:             * to be allocated near each other, which reduces the working set
0301:             * of CPU. It improves the chance the relevant data is in the cache.
0302:             */
0303:            private void allocateMoreStates() {
0304:                // this method should be used only when we run out of a state.
0305:                assert current.next == null;
0306:
0307:                State s = current;
0308:                for (int i = 0; i < 8; i++)
0309:                    s = new State(s);
0310:            }
0311:
0312:            /**
0313:             * User-specified factory methods.
0314:             */
0315:            private final Map<Class, Factory> factories = new HashMap<Class, Factory>();
0316:
0317:            public void setFactories(Object factoryInstances) {
0318:                factories.clear();
0319:                if (factoryInstances == null) {
0320:                    return;
0321:                }
0322:                if (factoryInstances instanceof  Object[]) {
0323:                    for (Object factory : (Object[]) factoryInstances) {
0324:                        // look for all the public methods inlcuding derived ones
0325:                        addFactory(factory);
0326:                    }
0327:                } else {
0328:                    addFactory(factoryInstances);
0329:                }
0330:            }
0331:
0332:            private void addFactory(Object factory) {
0333:                for (Method m : factory.getClass().getMethods()) {
0334:                    // look for methods whose signature is T createXXX()
0335:                    if (!m.getName().startsWith("create"))
0336:                        continue;
0337:                    if (m.getParameterTypes().length > 0)
0338:                        continue;
0339:
0340:                    Class type = m.getReturnType();
0341:
0342:                    factories.put(type, new Factory(factory, m));
0343:                }
0344:            }
0345:
0346:            public void startDocument(LocatorEx locator,
0347:                    NamespaceContext nsContext) throws SAXException {
0348:                this .locator = locator;
0349:                this .environmentNamespaceContext = nsContext;
0350:                // reset the object
0351:                result = null;
0352:                current = root;
0353:
0354:                patchersLen = 0;
0355:                aborted = false;
0356:                isUnmarshalInProgress = true;
0357:                nsLen = 0;
0358:
0359:                startPrefixMapping("", ""); // by default, the default ns is bound to "".
0360:
0361:                setThreadAffinity();
0362:
0363:                if (expectedType != null)
0364:                    root.loader = EXPECTED_TYPE_ROOT_LOADER;
0365:                else
0366:                    root.loader = DEFAULT_ROOT_LOADER;
0367:
0368:                idResolver.startDocument(this );
0369:            }
0370:
0371:            public void startElement(TagName tagName) throws SAXException {
0372:                pushCoordinator();
0373:                try {
0374:                    _startElement(tagName);
0375:                } finally {
0376:                    popCoordinator();
0377:                }
0378:            }
0379:
0380:            private void _startElement(TagName tagName) throws SAXException {
0381:
0382:                // remember the current element if we are interested in it.
0383:                // because the inner peer might not be found while we consume
0384:                // the enter element token, we need to keep this information
0385:                // longer than this callback. That's why we assign it to a field.
0386:                if (assoc != null)
0387:                    currentElement = scanner.getCurrentElement();
0388:
0389:                Loader h = current.loader;
0390:                current.push();
0391:
0392:                // tell the parent about the new child
0393:                h.childElement(current, tagName);
0394:                assert current.loader != null; // the childElement should register this
0395:                // and tell the new child that you are activated
0396:                current.loader.startElement(current, tagName);
0397:            }
0398:
0399:            public void text(CharSequence pcdata) throws SAXException {
0400:                State cur = current;
0401:                pushCoordinator();
0402:                try {
0403:                    if (cur.elementDefaultValue != null) {
0404:                        if (pcdata.length() == 0) {
0405:                            // send the default value into the unmarshaller instead
0406:                            pcdata = cur.elementDefaultValue;
0407:                        }
0408:                    }
0409:                    cur.loader.text(cur, pcdata);
0410:                } finally {
0411:                    popCoordinator();
0412:                }
0413:            }
0414:
0415:            public final void endElement(TagName tagName) throws SAXException {
0416:                pushCoordinator();
0417:                try {
0418:                    State child = current;
0419:
0420:                    // tell the child that your time is up
0421:                    child.loader.leaveElement(child, tagName);
0422:
0423:                    // child.pop will erase them so store them now
0424:                    Object target = child.target;
0425:                    Receiver recv = child.receiver;
0426:                    Intercepter intercepter = child.intercepter;
0427:                    child.pop();
0428:
0429:                    // then let the parent know
0430:                    if (intercepter != null)
0431:                        target = intercepter.intercept(current, target);
0432:                    if (recv != null)
0433:                        recv.receive(current, target);
0434:                } finally {
0435:                    popCoordinator();
0436:                }
0437:            }
0438:
0439:            public void endDocument() throws SAXException {
0440:                runPatchers();
0441:                idResolver.endDocument();
0442:
0443:                isUnmarshalInProgress = false;
0444:                currentElement = null;
0445:                locator = DUMMY_INSTANCE;
0446:                environmentNamespaceContext = null;
0447:
0448:                // at the successful completion, scope must be all closed
0449:                assert root == current;
0450:
0451:                resetThreadAffinity();
0452:            }
0453:
0454:            /**
0455:             * You should be always calling this through {@link TextPredictor}.
0456:             */
0457:            @Deprecated
0458:            public boolean expectText() {
0459:                return current.loader.expectText;
0460:            }
0461:
0462:            /**
0463:             * You should be always getting {@link TextPredictor} from {@link XmlVisitor}.
0464:             */
0465:            @Deprecated
0466:            public TextPredictor getPredictor() {
0467:                return this ;
0468:            }
0469:
0470:            public UnmarshallingContext getContext() {
0471:                return this ;
0472:            }
0473:
0474:            /**
0475:             * Gets the result of the unmarshalling
0476:             */
0477:            public Object getResult() throws UnmarshalException {
0478:                if (isUnmarshalInProgress)
0479:                    throw new IllegalStateException();
0480:
0481:                if (!aborted)
0482:                    return result;
0483:
0484:                // there was an error.
0485:                throw new UnmarshalException((String) null);
0486:            }
0487:
0488:            /**
0489:             * Creates a new instance of the specified class.
0490:             * In the unmarshaller, we need to check the user-specified factory class.
0491:             */
0492:            public Object createInstance(Class<?> clazz) throws SAXException {
0493:                if (!factories.isEmpty()) {
0494:                    Factory factory = factories.get(clazz);
0495:                    if (factory != null)
0496:                        return factory.createInstance();
0497:                }
0498:                return ClassFactory.create(clazz);
0499:            }
0500:
0501:            /**
0502:             * Creates a new instance of the specified class.
0503:             * In the unmarshaller, we need to check the user-specified factory class.
0504:             */
0505:            public Object createInstance(JaxBeanInfo beanInfo)
0506:                    throws SAXException {
0507:                if (!factories.isEmpty()) {
0508:                    Factory factory = factories.get(beanInfo.jaxbType);
0509:                    if (factory != null)
0510:                        return factory.createInstance();
0511:                }
0512:                try {
0513:                    return beanInfo.createInstance(this );
0514:                } catch (IllegalAccessException e) {
0515:                    Loader.reportError("Unable to create an instance of "
0516:                            + beanInfo.jaxbType.getName(), e, false);
0517:                } catch (InvocationTargetException e) {
0518:                    Loader.reportError("Unable to create an instance of "
0519:                            + beanInfo.jaxbType.getName(), e, false);
0520:                } catch (InstantiationException e) {
0521:                    Loader.reportError("Unable to create an instance of "
0522:                            + beanInfo.jaxbType.getName(), e, false);
0523:                }
0524:                return null; // can never be here
0525:            }
0526:
0527:            //
0528:            //
0529:            // error handling
0530:            //
0531:            //
0532:
0533:            /**
0534:             * Reports an error to the user, and asks if s/he wants
0535:             * to recover. If the canRecover flag is false, regardless
0536:             * of the client instruction, an exception will be thrown.
0537:             *
0538:             * Only if the flag is true and the user wants to recover from an error,
0539:             * the method returns normally.
0540:             *
0541:             * The thrown exception will be catched by the unmarshaller.
0542:             */
0543:            public void handleEvent(ValidationEvent event, boolean canRecover)
0544:                    throws SAXException {
0545:                ValidationEventHandler eventHandler = parent.getEventHandler();
0546:
0547:                boolean recover = eventHandler.handleEvent(event);
0548:
0549:                // if the handler says "abort", we will not return the object
0550:                // from the unmarshaller.getResult()
0551:                if (!recover)
0552:                    aborted = true;
0553:
0554:                if (!canRecover || !recover)
0555:                    throw new SAXParseException2(event.getMessage(), locator,
0556:                            new UnmarshalException(event.getMessage(), event
0557:                                    .getLinkedException()));
0558:            }
0559:
0560:            public boolean handleEvent(ValidationEvent event) {
0561:                try {
0562:                    // if the handler says "abort", we will not return the object.
0563:                    boolean recover = parent.getEventHandler().handleEvent(
0564:                            event);
0565:                    if (!recover)
0566:                        aborted = true;
0567:                    return recover;
0568:                } catch (RuntimeException re) {
0569:                    // if client event handler causes a runtime exception, then we
0570:                    // have to return false.
0571:                    return false;
0572:                }
0573:            }
0574:
0575:            /**
0576:             * Reports an exception found during the unmarshalling to the user.
0577:             * This method is a convenience method that calls into
0578:             * {@link #handleEvent(ValidationEvent, boolean)}
0579:             */
0580:            public void handleError(Exception e) throws SAXException {
0581:                handleError(e, true);
0582:            }
0583:
0584:            public void handleError(Exception e, boolean canRecover)
0585:                    throws SAXException {
0586:                handleEvent(new ValidationEventImpl(ValidationEvent.ERROR, e
0587:                        .getMessage(), locator.getLocation(), e), canRecover);
0588:            }
0589:
0590:            public void handleError(String msg) {
0591:                handleEvent(new ValidationEventImpl(ValidationEvent.ERROR, msg,
0592:                        locator.getLocation()));
0593:            }
0594:
0595:            protected ValidationEventLocator getLocation() {
0596:                return locator.getLocation();
0597:            }
0598:
0599:            /**
0600:             * Gets the current source location information in SAX {@link Locator}.
0601:             * <p>
0602:             * Sometimes the unmarshaller works against a different kind of XML source,
0603:             * making this information meaningless.
0604:             */
0605:            public LocatorEx getLocator() {
0606:                return locator;
0607:            }
0608:
0609:            /**
0610:             * Called when there's no corresponding ID value.
0611:             */
0612:            public void errorUnresolvedIDREF(Object bean, String idref)
0613:                    throws SAXException {
0614:                handleEvent(new ValidationEventImpl(ValidationEvent.ERROR,
0615:                        Messages.UNRESOLVED_IDREF.format(idref),
0616:                        new ValidationEventLocatorImpl(bean)), true);
0617:            }
0618:
0619:            //
0620:            //
0621:            // ID/IDREF related code
0622:            //
0623:            //
0624:            /**
0625:             * Submitted patchers in the order they've submitted.
0626:             * Many XML vocabulary doesn't use ID/IDREF at all, so we
0627:             * initialize it with null.
0628:             */
0629:            private Patcher[] patchers = null;
0630:            private int patchersLen = 0;
0631:
0632:            /**
0633:             * Adds a job that will be executed at the last of the unmarshalling.
0634:             * This method is used to support ID/IDREF feature, but it can be used
0635:             * for other purposes as well.
0636:             *
0637:             * @param   job
0638:             *      The run method of this object is called.
0639:             */
0640:            public void addPatcher(Patcher job) {
0641:                // re-allocate buffer if necessary
0642:                if (patchers == null)
0643:                    patchers = new Patcher[32];
0644:                if (patchers.length == patchersLen) {
0645:                    Patcher[] buf = new Patcher[patchersLen * 2];
0646:                    System.arraycopy(patchers, 0, buf, 0, patchersLen);
0647:                    patchers = buf;
0648:                }
0649:                patchers[patchersLen++] = job;
0650:            }
0651:
0652:            /** Executes all the patchers. */
0653:            private void runPatchers() throws SAXException {
0654:                if (patchers != null) {
0655:                    for (int i = 0; i < patchersLen; i++) {
0656:                        patchers[i].run();
0657:                        patchers[i] = null; // free memory
0658:                    }
0659:                }
0660:            }
0661:
0662:            /**
0663:             * Adds the object which is currently being unmarshalled
0664:             * to the ID table.
0665:             *
0666:             * @return
0667:             *      Returns the value passed as the parameter.
0668:             *      This is a hack, but this makes it easier for ID
0669:             *      transducer to do its job.
0670:             */
0671:            // TODO: what shall we do if the ID is already declared?
0672:            //
0673:            // throwing an exception is one way. Overwriting the previous one
0674:            // is another way. The latter allows us to process invalid documents,
0675:            // while the former makes it impossible to handle them.
0676:            //
0677:            // I prefer to be flexible in terms of invalid document handling,
0678:            // so chose not to throw an exception.
0679:            //
0680:            // I believe this is an implementation choice, not the spec issue.
0681:            // -kk
0682:            public String addToIdTable(String id) throws SAXException {
0683:                // Hmm...
0684:                // in cases such as when ID is used as an attribute, or as @XmlValue
0685:                // the target wilil be current.target.
0686:                // but in some other cases, such as when ID is used as a child element
0687:                // or a value of JAXBElement, it's current.prev.target.
0688:                // I don't know if this detection logic is complete
0689:                Object o = current.target;
0690:                if (o == null)
0691:                    o = current.prev.target;
0692:                idResolver.bind(id, o);
0693:                return id;
0694:            }
0695:
0696:            /**
0697:             * Looks up the ID table and gets associated object.
0698:             *
0699:             * <p>
0700:             * The exception thrown from {@link Callable#call()} means the unmarshaller should abort
0701:             * right away.
0702:             *
0703:             * @see IDResolver#resolve(String, Class)
0704:             */
0705:            public Callable getObjectFromId(String id, Class targetType)
0706:                    throws SAXException {
0707:                return idResolver.resolve(id, targetType);
0708:            }
0709:
0710:            //
0711:            //
0712:            // namespace binding maintainance
0713:            //
0714:            //
0715:            private String[] nsBind = new String[16];
0716:            private int nsLen = 0;
0717:
0718:            public void startPrefixMapping(String prefix, String uri) {
0719:                if (nsBind.length == nsLen) {
0720:                    // expand the buffer
0721:                    String[] n = new String[nsLen * 2];
0722:                    System.arraycopy(nsBind, 0, n, 0, nsLen);
0723:                    nsBind = n;
0724:                }
0725:                nsBind[nsLen++] = prefix;
0726:                nsBind[nsLen++] = uri;
0727:            }
0728:
0729:            public void endPrefixMapping(String prefix) {
0730:                nsLen -= 2;
0731:            }
0732:
0733:            private String resolveNamespacePrefix(String prefix) {
0734:                if (prefix.equals("xml"))
0735:                    return "http://www.w3.org/XML/1998/namespace";
0736:
0737:                for (int i = nsLen - 2; i >= 0; i -= 2) {
0738:                    if (prefix.equals(nsBind[i]))
0739:                        return nsBind[i + 1];
0740:                }
0741:
0742:                if (environmentNamespaceContext != null)
0743:                    // temporary workaround until Zephyr fixes 6337180
0744:                    return environmentNamespaceContext.getNamespaceURI(prefix
0745:                            .intern());
0746:
0747:                return null;
0748:            }
0749:
0750:            /**
0751:             * Returns a list of prefixes newly declared on the current element.
0752:             *
0753:             * @return
0754:             *      A possible zero-length array of prefixes. The default prefix
0755:             *      is represented by the empty string.
0756:             */
0757:            public String[] getNewlyDeclaredPrefixes() {
0758:                return getPrefixList(current.prev.numNsDecl);
0759:            }
0760:
0761:            /**
0762:             * Returns a list of all in-scope prefixes.
0763:             *
0764:             * @return
0765:             *      A possible zero-length array of prefixes. The default prefix
0766:             *      is represented by the empty string.
0767:             */
0768:            public String[] getAllDeclaredPrefixes() {
0769:                return getPrefixList(2); // skip the default ""->"" mapping
0770:            }
0771:
0772:            private String[] getPrefixList(int startIndex) {
0773:                int size = (current.numNsDecl - startIndex) / 2;
0774:                String[] r = new String[size];
0775:                for (int i = 0; i < r.length; i++)
0776:                    r[i] = nsBind[startIndex + i * 2];
0777:                return r;
0778:            }
0779:
0780:            //
0781:            //  NamespaceContext2 implementation
0782:            //
0783:            public Iterator<String> getPrefixes(String uri) {
0784:                // TODO: could be implemented much faster
0785:                // wrap it into unmodifiable list so that the remove method
0786:                // will throw UnsupportedOperationException.
0787:                return Collections.unmodifiableList(getAllPrefixesInList(uri))
0788:                        .iterator();
0789:            }
0790:
0791:            private List<String> getAllPrefixesInList(String uri) {
0792:                List<String> a = new ArrayList<String>();
0793:
0794:                if (uri == null)
0795:                    throw new IllegalArgumentException();
0796:                if (uri.equals(XMLConstants.XML_NS_URI)) {
0797:                    a.add(XMLConstants.XML_NS_PREFIX);
0798:                    return a;
0799:                }
0800:                if (uri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
0801:                    a.add(XMLConstants.XMLNS_ATTRIBUTE);
0802:                    return a;
0803:                }
0804:
0805:                for (int i = nsLen - 2; i >= 0; i -= 2)
0806:                    if (uri.equals(nsBind[i + 1]))
0807:                        if (getNamespaceURI(nsBind[i]).equals(nsBind[i + 1]))
0808:                            // make sure that this prefix is still effective.
0809:                            a.add(nsBind[i]);
0810:
0811:                return a;
0812:            }
0813:
0814:            public String getPrefix(String uri) {
0815:                if (uri == null)
0816:                    throw new IllegalArgumentException();
0817:                if (uri.equals(XMLConstants.XML_NS_URI))
0818:                    return XMLConstants.XML_NS_PREFIX;
0819:                if (uri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI))
0820:                    return XMLConstants.XMLNS_ATTRIBUTE;
0821:
0822:                for (int i = nsLen - 2; i >= 0; i -= 2)
0823:                    if (uri.equals(nsBind[i + 1]))
0824:                        if (getNamespaceURI(nsBind[i]).equals(nsBind[i + 1]))
0825:                            // make sure that this prefix is still effective.
0826:                            return nsBind[i];
0827:
0828:                if (environmentNamespaceContext != null)
0829:                    return environmentNamespaceContext.getPrefix(uri);
0830:
0831:                return null;
0832:            }
0833:
0834:            public String getNamespaceURI(String prefix) {
0835:                if (prefix == null)
0836:                    throw new IllegalArgumentException();
0837:                if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE))
0838:                    return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
0839:
0840:                return resolveNamespacePrefix(prefix);
0841:            }
0842:
0843:            //
0844:            //
0845:            //
0846:            // scope management
0847:            //
0848:            //
0849:            //
0850:            private Scope[] scopes = new Scope[16];
0851:            /**
0852:             * Points to the top of the scope stack (=size-1).
0853:             */
0854:            private int scopeTop = 0;
0855:
0856:            {
0857:                for (int i = 0; i < scopes.length; i++)
0858:                    scopes[i] = new Scope(this );
0859:            }
0860:
0861:            /**
0862:             * Starts a new packing scope.
0863:             *
0864:             * <p>
0865:             * This method allocates a specified number of fresh {@link Scope} objects.
0866:             * They can be accessed by the {@link #getScope} method until the corresponding
0867:             * {@link #endScope} method is invoked.
0868:             *
0869:             * <p>
0870:             * A new scope will mask the currently active scope. Only one frame of {@link Scope}s
0871:             * can be accessed at any given time.
0872:             *
0873:             * @param frameSize
0874:             *      The # of slots to be allocated.
0875:             */
0876:            public void startScope(int frameSize) {
0877:                scopeTop += frameSize;
0878:
0879:                // reallocation
0880:                if (scopeTop >= scopes.length) {
0881:                    Scope[] s = new Scope[Math.max(scopeTop + 1,
0882:                            scopes.length * 2)];
0883:                    System.arraycopy(scopes, 0, s, 0, scopes.length);
0884:                    for (int i = scopes.length; i < s.length; i++)
0885:                        s[i] = new Scope(this );
0886:                    scopes = s;
0887:                }
0888:            }
0889:
0890:            /**
0891:             * Ends the current packing scope.
0892:             *
0893:             * <p>
0894:             * If any packing in progress will be finalized by this method.
0895:             *
0896:             * @param frameSize
0897:             *      The same size that gets passed to the {@link #startScope(int)}
0898:             *      method.
0899:             */
0900:            public void endScope(int frameSize) throws SAXException {
0901:                try {
0902:                    for (; frameSize > 0; frameSize--)
0903:                        scopes[scopeTop--].finish();
0904:                } catch (AccessorException e) {
0905:                    handleError(e);
0906:                }
0907:            }
0908:
0909:            /**
0910:             * Gets the currently active {@link Scope}.
0911:             *
0912:             * @param offset
0913:             *      a number between [0,frameSize)
0914:             *
0915:             * @return
0916:             *      always a valid {@link Scope} object.
0917:             */
0918:            public Scope getScope(int offset) {
0919:                return scopes[scopeTop - offset];
0920:            }
0921:
0922:            //
0923:            //
0924:            //
0925:            //
0926:            //
0927:            //
0928:            //
0929:
0930:            private static final Loader DEFAULT_ROOT_LOADER = new DefaultRootLoader();
0931:            private static final Loader EXPECTED_TYPE_ROOT_LOADER = new ExpectedTypeRootLoader();
0932:
0933:            /**
0934:             * Root loader that uses the tag name and possibly its @xsi:type
0935:             * to decide how to start unmarshalling.
0936:             */
0937:            private static final class DefaultRootLoader extends Loader
0938:                    implements  Receiver {
0939:                /**
0940:                 * Receives the root element and determines how to start
0941:                 * unmarshalling.
0942:                 */
0943:                public void childElement(UnmarshallingContext.State state,
0944:                        TagName ea) throws SAXException {
0945:                    JAXBContextImpl jaxbContext = state.getContext()
0946:                            .getJAXBContext();
0947:
0948:                    Loader loader = jaxbContext.selectRootLoader(state, ea);
0949:                    if (loader != null) {
0950:                        state.loader = loader;
0951:                        state.receiver = this ;
0952:                        return;
0953:                    }
0954:
0955:                    // the registry doesn't know about this element.
0956:                    // try its xsi:type
0957:                    JaxBeanInfo beanInfo = XsiTypeLoader
0958:                            .parseXsiType(state, ea);
0959:                    if (beanInfo == null) {
0960:                        // we don't even know its xsi:type
0961:                        reportUnexpectedChildElement(ea, false);
0962:                        return;
0963:                    }
0964:
0965:                    state.loader = beanInfo.getLoader(null, false);
0966:                    state.prev.backup = new JAXBElement<Object>(ea
0967:                            .createQName(), Object.class, null);
0968:                    state.receiver = this ;
0969:                }
0970:
0971:                @Override
0972:                public Collection<QName> getExpectedChildElements() {
0973:                    return getInstance().getJAXBContext().getValidRootNames();
0974:                }
0975:
0976:                public void receive(State state, Object o) {
0977:                    if (state.backup != null) {
0978:                        ((JAXBElement<Object>) state.backup).setValue(o);
0979:                        o = state.backup;
0980:                    }
0981:                    state.getContext().result = o;
0982:                }
0983:            }
0984:
0985:            /**
0986:             * Root loader that uses {@link UnmarshallingContext#expectedType}
0987:             * to decide how to start unmarshalling.
0988:             */
0989:            private static final class ExpectedTypeRootLoader extends Loader
0990:                    implements  Receiver {
0991:                /**
0992:                 * Receives the root element and determines how to start
0993:                 * unmarshalling.
0994:                 */
0995:                public void childElement(UnmarshallingContext.State state,
0996:                        TagName ea) {
0997:                    UnmarshallingContext context = state.getContext();
0998:
0999:                    // unmarshals the specified type
1000:                    QName qn = new QName(ea.uri, ea.local);
1001:                    state.prev.target = new JAXBElement(qn,
1002:                            context.expectedType.jaxbType, null, null);
1003:                    state.receiver = this ;
1004:                    // this is bit wasteful, as in theory we should have each expectedType keep
1005:                    // nillable version --- but that increases the combination from two to four,
1006:                    // which adds the resident memory footprint. Since XsiNilLoader is small,
1007:                    // I intentionally allocate a new instance freshly.
1008:                    state.loader = new XsiNilLoader(context.expectedType
1009:                            .getLoader(null, true));
1010:                }
1011:
1012:                public void receive(State state, Object o) {
1013:                    JAXBElement e = (JAXBElement) state.target;
1014:                    e.setValue(o);
1015:                    state.getContext().recordOuterPeer(e);
1016:                    state.getContext().result = e;
1017:                }
1018:            }
1019:
1020:            //
1021:            // in-place unmarshalling related capabilities
1022:            //
1023:            /**
1024:             * Notifies the context about the inner peer of the current element.
1025:             *
1026:             * <p>
1027:             * If the unmarshalling is building the association, the context
1028:             * will use this information. Otherwise it will be just ignored.
1029:             */
1030:            public void recordInnerPeer(Object innerPeer) {
1031:                if (assoc != null)
1032:                    assoc.addInner(currentElement, innerPeer);
1033:            }
1034:
1035:            /**
1036:             * Gets the inner peer JAXB object associated with the current element.
1037:             *
1038:             * @return
1039:             *      null if the current element doesn't have an inner peer,
1040:             *      or if we are not doing the in-place unmarshalling.
1041:             */
1042:            public Object getInnerPeer() {
1043:                if (assoc != null && isInplaceMode)
1044:                    return assoc.getInnerPeer(currentElement);
1045:                else
1046:                    return null;
1047:            }
1048:
1049:            /**
1050:             * Notifies the context about the outer peer of the current element.
1051:             *
1052:             * <p>
1053:             * If the unmarshalling is building the association, the context
1054:             * will use this information. Otherwise it will be just ignored.
1055:             */
1056:            public void recordOuterPeer(Object outerPeer) {
1057:                if (assoc != null)
1058:                    assoc.addOuter(currentElement, outerPeer);
1059:            }
1060:
1061:            /**
1062:             * Gets the outer peer JAXB object associated with the current element.
1063:             *
1064:             * @return
1065:             *      null if the current element doesn't have an inner peer,
1066:             *      or if we are not doing the in-place unmarshalling.
1067:             */
1068:            public Object getOuterPeer() {
1069:                if (assoc != null && isInplaceMode)
1070:                    return assoc.getOuterPeer(currentElement);
1071:                else
1072:                    return null;
1073:            }
1074:
1075:            /**
1076:             * Gets the xmime:contentType value for the current object.
1077:             *
1078:             * @see JAXBContextImpl#getXMIMEContentType(Object)
1079:             */
1080:            public String getXMIMEContentType() {
1081:                /*
1082:                    this won't work when the class is like
1083:
1084:                    class Foo {
1085:                        @XmlValue Image img;
1086:                    }
1087:
1088:                    because the target will return Foo, not the class enclosing Foo
1089:                    which will have xmime:contentType
1090:                 */
1091:                Object t = current.target;
1092:                if (t == null)
1093:                    return null;
1094:                return getJAXBContext().getXMIMEContentType(t);
1095:            }
1096:
1097:            /**
1098:             * When called from within the realm of the unmarshaller, this method
1099:             * returns the current {@link UnmarshallingContext} in charge.
1100:             */
1101:            public static UnmarshallingContext getInstance() {
1102:                return (UnmarshallingContext) Coordinator._getInstance();
1103:            }
1104:
1105:            private static final LocatorEx DUMMY_INSTANCE;
1106:
1107:            static {
1108:                LocatorImpl loc = new LocatorImpl();
1109:                loc.setPublicId(null);
1110:                loc.setSystemId(null);
1111:                loc.setLineNumber(-1);
1112:                loc.setColumnNumber(-1);
1113:                DUMMY_INSTANCE = new LocatorExWrapper(loc);
1114:            }
1115:        }
ww_w.___j___ava___2_s___._c__om__ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.