1 /*
2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.xml.internal.bind.v2.runtime.unmarshaller;
27 
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.concurrent.Callable;
38 
39 import javax.xml.XMLConstants;
40 import javax.xml.bind.JAXBElement;
41 import javax.xml.bind.UnmarshalException;
42 import javax.xml.bind.Unmarshaller;
43 import javax.xml.bind.ValidationEvent;
44 import javax.xml.bind.ValidationEventHandler;
45 import javax.xml.bind.ValidationEventLocator;
46 import javax.xml.bind.helpers.ValidationEventImpl;
47 import javax.xml.namespace.NamespaceContext;
48 import javax.xml.namespace.QName;
49 
50 import com.sun.istack.internal.NotNull;
51 import com.sun.istack.internal.Nullable;
52 import com.sun.istack.internal.SAXParseException2;
53 import com.sun.xml.internal.bind.IDResolver;
54 import com.sun.xml.internal.bind.Util;
55 import com.sun.xml.internal.bind.api.AccessorException;
56 import com.sun.xml.internal.bind.api.ClassResolver;
57 import com.sun.xml.internal.bind.unmarshaller.InfosetScanner;
58 import com.sun.xml.internal.bind.v2.ClassFactory;
59 import com.sun.xml.internal.bind.v2.runtime.AssociationMap;
60 import com.sun.xml.internal.bind.v2.runtime.Coordinator;
61 import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
62 import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo;
63 import java.util.logging.Level;
64 import java.util.logging.Logger;
65 
66 import org.xml.sax.ErrorHandler;
67 import org.xml.sax.SAXException;
68 import org.xml.sax.helpers.LocatorImpl;
69 
70 /**
71  * Center of the unmarshalling.
72  *
73  * <p>
74  * This object is responsible for coordinating {@link Loader}s to
75  * perform the whole unmarshalling.
76  *
77  * @author Kohsuke Kawaguchi
78  */
79 public final class UnmarshallingContext extends Coordinator
80     implements NamespaceContext, ValidationEventHandler, ErrorHandler, XmlVisitor, XmlVisitor.TextPredictor {
81 
82     private static final Logger logger = Logger.getLogger(UnmarshallingContext.class.getName());
83 
84     /**
85      * Root state.
86      */
87     private final State root;
88 
89     /**
90      * The currently active state.
91      */
92     private State current;
93 
94     private static final LocatorEx DUMMY_INSTANCE;
95 
96     static {
97         LocatorImpl loc = new LocatorImpl();
98         loc.setPublicId(null);
99         loc.setSystemId(null);
100         loc.setLineNumber(-1);
101         loc.setColumnNumber(-1);
102         DUMMY_INSTANCE = new LocatorExWrapper(loc);
103     }
104 
105     private @NotNull LocatorEx locator = DUMMY_INSTANCE;
106 
107     /** Root object that is being unmarshalled. */
108     private Object result;
109 
110     /**
111      * If non-null, this unmarshaller will unmarshal {@code JAXBElement<EXPECTEDTYPE>}
112      * regardless of the tag name, as opposed to deciding the root object by using
113      * the tag name.
114      *
115      * The property has a package-level access, because we cannot copy this value
116      * to {@link UnmarshallingContext} when it is created. The property
117      * on {@link Unmarshaller} could be changed after the handler is created.
118      */
119     private JaxBeanInfo expectedType;
120 
121     /**
122      * Handles ID/IDREF.
123      */
124     private IDResolver idResolver;
125 
126     /**
127      * This flag is set to true at the startDocument event
128      * and false at the endDocument event.
129      *
130      * Until the first document is unmarshalled, we don't
131      * want to return an object. So this variable is initialized
132      * to true.
133      */
134     private boolean isUnmarshalInProgress = true;
135     private boolean aborted = false;
136 
137     public final UnmarshallerImpl parent;
138 
139     /**
140      * If the unmarshaller is doing associative unmarshalling,
141      * this field is initialized to non-null.
142      */
143     private final AssociationMap assoc;
144 
145     /**
146      * Indicates whether we are doing in-place unmarshalling
147      * or not.
148      *
149      * <p>
150      * This flag is unused when {@link #assoc}==null.
151      * If it's non-null, then <tt>true</tt> indicates
152      * that we are doing in-place associative unmarshalling.
153      * If <tt>false</tt>, then we are doing associative unmarshalling
154      * without object reuse.
155      */
156     private boolean isInplaceMode;
157 
158     /**
159      * This object is consulted to get the element object for
160      * the current element event.
161      *
162      * This is used when we are building an association map.
163      */
164     private InfosetScanner scanner;
165 
166     private Object currentElement;
167 
168     /**
169      * @see XmlVisitor#startDocument(LocatorEx, NamespaceContext)
170      */
171     private NamespaceContext environmentNamespaceContext;
172 
173     /**
174      * Used to discover additional classes when we hit unknown elements/types.
175      */
176     public @Nullable ClassResolver classResolver;
177 
178     /**
179      * User-supplied {@link ClassLoader} for converting name to {@link Class}.
180      * For backward compatibility, when null, use thread context classloader.
181      */
182     public @Nullable ClassLoader classLoader;
183 
184     /**
185      * The variable introduced to avoid reporting n^10 similar errors.
186      * After error is reported counter is decremented. When it became 0 - errors should not be reported any more.
187      *
188      * volatile is required to ensure that concurrent threads will see changed value
189      */
190     private static volatile int errorsCounter = 10;
191 
192     /**
193      * State information for each element.
194      */
195     public final class State {
196         /**
197          * Loader that owns this element.
198          */
199         private Loader loader;
200         /**
201          * Once {@link #loader} is completed, this receiver
202          * receives the result.
203          */
204         private Receiver receiver;
205 
206         private Intercepter intercepter;
207 
208         /**
209          * Object being unmarshalled by this {@link #loader}.
210          */
211         private Object target;
212 
213         /**
214          * Hack for making JAXBElement unmarshalling work.
215          *
216          * <p>
217          * While the unmarshalling is in progress, the {@link #target} field stores the object being unmarshalled.
218          * This makes it convenient to keep track of the unmarshalling activity in context of XML infoset, but
219          * since there's only one {@link State} per element, this mechanism only works when there's one object
220          * per element, which breaks down when we have {@link JAXBElement}, since the presence of JAXBElement
221          * requires that we have two objects unmarshalled (a JAXBElement X and a value object Y bound to an XML type.)
222          *
223          * <p>
224          * So to make room for storing both, this {@link #backup} field is used. When we create X instance
225          * in the above example, we set that to {@code state.prev.target} and displace its old value to
226          * {@code state.prev.backup} (where Y goes to {@code state.target}.) Upon the completion of the unmarshalling
227          * of Y, we revert this.
228          *
229          * <p>
230          * While this attributes X incorrectly to its parent element, this preserves the parent/child
231          * relationship between unmarshalled objects and {@link State} parent/child relationship, and
232          * it thereby makes {@link Receiver} mechanism simpler.
233          *
234          * <p>
235          * Yes, I know this is a hack, and no, I'm not proud of it.
236          *
237          * @see ElementBeanInfoImpl.IntercepterLoader#startElement(State, TagName)
238          * @see ElementBeanInfoImpl.IntercepterLoader#intercept(State, Object)
239          */
240         private Object backup;
241 
242         /**
243          * Number of {@link UnmarshallingContext#nsBind}s declared thus far.
244          * (The value of {@link UnmarshallingContext#nsLen} when this state is pushed.
245          */
246         private int numNsDecl;
247 
248         /**
249          * If this element has an element default value.
250          *
251          * This should be set by either a parent {@link Loader} when
252          * {@link Loader#childElement(State, TagName)} is called
253          * or by a child {@link Loader} when
254          * {@link Loader#startElement(State, TagName)} is called.
255          */
256         private String elementDefaultValue;
257 
258         /**
259          * {@link State} for the parent element
260          *
261          * {@link State} objects form a doubly linked list.
262          */
263         private State prev;
264         private State next;
265 
266         private boolean nil = false;
267 
268         /**
269          * specifies that we are working with mixed content
270          */
271         private boolean mixed = false;
272 
273         /**
274          * Gets the context.
275          */
getContext()276         public UnmarshallingContext getContext() {
277             return UnmarshallingContext.this;
278         }
279 
280         @SuppressWarnings("LeakingThisInConstructor")
State(State prev)281         private State(State prev) {
282             this.prev = prev;
283             if (prev!=null) {
284                 prev.next = this;
285                 if (prev.mixed) // parent is in mixed mode
286                     this.mixed = true;
287             }
288         }
289 
push()290         private void push() {
291             if (logger.isLoggable(Level.FINEST)) {
292                 logger.log(Level.FINEST, "State.push");
293             }
294             if (next==null) {
295                 assert current == this;
296                 next = new State(this);
297             }
298             nil = false;
299             State n = next;
300             n.numNsDecl = nsLen;
301             current = n;
302         }
303 
pop()304         private void pop() {
305             if (logger.isLoggable(Level.FINEST)) {
306                 logger.log(Level.FINEST, "State.pop");
307             }
308             assert prev!=null;
309             loader = null;
310             nil = false;
311             mixed = false;
312             receiver = null;
313             intercepter = null;
314             elementDefaultValue = null;
315             target = null;
316             current = prev;
317             next = null;
318         }
319 
isMixed()320         public boolean isMixed() {
321             return mixed;
322         }
323 
getTarget()324         public Object getTarget() {
325             return target;
326         }
327 
setLoader(Loader loader)328         public void setLoader(Loader loader) {
329             if (loader instanceof StructureLoader) // set mixed mode
330                 mixed = !((StructureLoader)loader).getBeanInfo().hasElementOnlyContentModel();
331             this.loader = loader;
332         }
333 
setReceiver(Receiver receiver)334         public void setReceiver(Receiver receiver) {
335             this.receiver = receiver;
336         }
337 
getPrev()338         public State getPrev() {
339             return prev;
340         }
341 
setIntercepter(Intercepter intercepter)342         public void setIntercepter(Intercepter intercepter) {
343             this.intercepter = intercepter;
344         }
345 
setBackup(Object backup)346         public void setBackup(Object backup) {
347             this.backup = backup;
348         }
349 
setTarget(Object target)350         public void setTarget(Object target) {
351             this.target = target;
352         }
353 
getBackup()354         public Object getBackup() {
355             return backup;
356         }
357 
isNil()358         public boolean isNil() {
359             return nil;
360         }
361 
setNil(boolean nil)362         public void setNil(boolean nil) {
363             this.nil = nil;
364         }
365 
getLoader()366         public Loader getLoader() {
367             return loader;
368         }
369 
getElementDefaultValue()370         public String getElementDefaultValue() {
371             return elementDefaultValue;
372         }
373 
setElementDefaultValue(String elementDefaultValue)374         public void setElementDefaultValue(String elementDefaultValue) {
375             this.elementDefaultValue = elementDefaultValue;
376         }
377     }
378 
379     /**
380      * Stub to the user-specified factory method.
381      */
382     private static class Factory {
383         private final Object factorInstance;
384         private final Method method;
385 
Factory(Object factorInstance, Method method)386         public Factory(Object factorInstance, Method method) {
387             this.factorInstance = factorInstance;
388             this.method = method;
389         }
390 
createInstance()391         public Object createInstance() throws SAXException {
392             try {
393                 return method.invoke(factorInstance);
394             } catch (IllegalAccessException e) {
395                 getInstance().handleError(e,false);
396             } catch (InvocationTargetException e) {
397                 getInstance().handleError(e,false);
398             }
399             return null; // can never be executed
400         }
401     }
402 
403 
404     /**
405      * Creates a new unmarshaller.
406      *
407      * @param assoc
408      *      Must be both non-null when the unmarshaller does the
409      *      in-place unmarshalling. Otherwise must be both null.
410      */
UnmarshallingContext( UnmarshallerImpl _parent, AssociationMap assoc)411     public UnmarshallingContext( UnmarshallerImpl _parent, AssociationMap assoc) {
412         this.parent = _parent;
413         this.assoc = assoc;
414         this.root = this.current = new State(null);
415     }
416 
reset(InfosetScanner scanner,boolean isInplaceMode, JaxBeanInfo expectedType, IDResolver idResolver)417     public void reset(InfosetScanner scanner,boolean isInplaceMode, JaxBeanInfo expectedType, IDResolver idResolver) {
418         this.scanner = scanner;
419         this.isInplaceMode = isInplaceMode;
420         this.expectedType = expectedType;
421         this.idResolver = idResolver;
422     }
423 
getJAXBContext()424     public JAXBContextImpl getJAXBContext() {
425         return parent.context;
426     }
427 
getCurrentState()428     public State getCurrentState() {
429         return current;
430     }
431 
432     /**
433      * On top of {@link JAXBContextImpl#selectRootLoader(State, TagName)},
434      * this method also consults {@link ClassResolver}.
435      *
436      * @throws SAXException
437      *      if {@link ValidationEventHandler} reported a failure.
438      */
selectRootLoader(State state, TagName tag)439     public Loader selectRootLoader(State state, TagName tag) throws SAXException {
440         try {
441             Loader l = getJAXBContext().selectRootLoader(state, tag);
442             if(l!=null)     return l;
443 
444             if(classResolver!=null) {
445                 Class<?> clazz = classResolver.resolveElementName(tag.uri, tag.local);
446                 if(clazz!=null) {
447                     JAXBContextImpl enhanced = getJAXBContext().createAugmented(clazz);
448                     JaxBeanInfo<?> bi = enhanced.getBeanInfo(clazz);
449                     return bi.getLoader(enhanced,true);
450                 }
451             }
452         } catch (RuntimeException e) {
453             throw e;
454         } catch (Exception e) {
455             handleError(e);
456         }
457 
458         return null;
459     }
460 
clearStates()461     public void clearStates() {
462         State last = current;
463         while (last.next != null) last = last.next;
464         while (last.prev != null) {
465             last.loader = null;
466             last.nil = false;
467             last.receiver = null;
468             last.intercepter = null;
469             last.elementDefaultValue = null;
470             last.target = null;
471             last = last.prev;
472             last.next.prev = null;
473             last.next = null;
474         }
475         current = last;
476     }
477 
478     /**
479      * User-specified factory methods.
480      */
481     private final Map<Class,Factory> factories = new HashMap<Class, Factory>();
482 
setFactories(Object factoryInstances)483     public void setFactories(Object factoryInstances) {
484         factories.clear();
485         if(factoryInstances==null) {
486             return;
487         }
488         if(factoryInstances instanceof Object[]) {
489             for( Object factory : (Object[])factoryInstances ) {
490                 // look for all the public methods inlcuding derived ones
491                 addFactory(factory);
492             }
493         } else {
494             addFactory(factoryInstances);
495         }
496     }
497 
addFactory(Object factory)498     private void addFactory(Object factory) {
499         for( Method m : factory.getClass().getMethods() ) {
500             // look for methods whose signature is T createXXX()
501             if(!m.getName().startsWith("create"))
502                 continue;
503             if(m.getParameterTypes().length>0)
504                 continue;
505 
506             Class type = m.getReturnType();
507 
508             factories.put(type,new Factory(factory,m));
509         }
510     }
511 
512     @Override
startDocument(LocatorEx locator, NamespaceContext nsContext)513     public void startDocument(LocatorEx locator, NamespaceContext nsContext) throws SAXException {
514         if(locator!=null)
515             this.locator = locator;
516         this.environmentNamespaceContext = nsContext;
517         // reset the object
518         result = null;
519         current = root;
520 
521         patchersLen=0;
522         aborted = false;
523         isUnmarshalInProgress = true;
524         nsLen=0;
525 
526         if(expectedType!=null)
527             root.loader = EXPECTED_TYPE_ROOT_LOADER;
528         else
529             root.loader = DEFAULT_ROOT_LOADER;
530 
531         idResolver.startDocument(this);
532     }
533 
534     @Override
startElement(TagName tagName)535     public void startElement(TagName tagName) throws SAXException {
536         pushCoordinator();
537         try {
538             _startElement(tagName);
539         } finally {
540             popCoordinator();
541         }
542     }
543 
_startElement(TagName tagName)544     private void _startElement(TagName tagName) throws SAXException {
545         // remember the current element if we are interested in it.
546         // because the inner peer might not be found while we consume
547         // the enter element token, we need to keep this information
548         // longer than this callback. That's why we assign it to a field.
549         if( assoc!=null )
550             currentElement = scanner.getCurrentElement();
551 
552         Loader h = current.loader;
553         current.push();
554 
555         // tell the parent about the new child
556         h.childElement(current,tagName);
557         assert current.loader!=null;   // the childElement should register this
558         // and tell the new child that you are activated
559         current.loader.startElement(current,tagName);
560     }
561 
562     @Override
text(CharSequence pcdata)563     public void text(CharSequence pcdata) throws SAXException {
564         pushCoordinator();
565         try {
566             if (current.elementDefaultValue != null) {
567                 if (pcdata.length() == 0) {
568                     // send the default value into the unmarshaller instead
569                     pcdata = current.elementDefaultValue;
570                 }
571             }
572             current.loader.text(current, pcdata);
573         } finally {
574             popCoordinator();
575         }
576     }
577 
578     @Override
endElement(TagName tagName)579     public final void endElement(TagName tagName) throws SAXException {
580         pushCoordinator();
581         try {
582             State child = current;
583 
584             // tell the child that your time is up
585             child.loader.leaveElement(child,tagName);
586 
587             // child.pop will erase them so store them now
588             Object target = child.target;
589             Receiver recv = child.receiver;
590             Intercepter intercepter = child.intercepter;
591             child.pop();
592 
593             // then let the parent know
594             if(intercepter!=null)
595                 target = intercepter.intercept(current,target);
596             if(recv!=null)
597                 recv.receive(current,target);
598         } finally {
599             popCoordinator();
600         }
601     }
602 
603     @Override
endDocument()604     public void endDocument() throws SAXException {
605         runPatchers();
606         idResolver.endDocument();
607 
608         isUnmarshalInProgress = false;
609         currentElement = null;
610         locator = DUMMY_INSTANCE;
611         environmentNamespaceContext = null;
612 
613         // at the successful completion, scope must be all closed
614         assert root==current;
615     }
616 
617     /**
618      * You should be always calling this through {@link TextPredictor}.
619      */
620     @Deprecated
621     @Override
expectText()622     public boolean expectText() {
623         return current.loader.expectText;
624     }
625 
626     /**
627      * You should be always getting {@link TextPredictor} from {@link XmlVisitor}.
628      */
629     @Deprecated
630     @Override
getPredictor()631     public TextPredictor getPredictor() {
632         return this;
633     }
634 
635     @Override
getContext()636     public UnmarshallingContext getContext() {
637         return this;
638     }
639 
640     /**
641      * Gets the result of the unmarshalling
642      */
getResult()643     public Object getResult() throws UnmarshalException {
644         if(isUnmarshalInProgress)
645             throw new IllegalStateException();
646 
647         if(!aborted)       return result;
648 
649         // there was an error.
650         throw new UnmarshalException((String)null);
651     }
652 
clearResult()653     void clearResult() {
654         if (isUnmarshalInProgress) {
655             throw new IllegalStateException();
656         }
657         result = null;
658     }
659 
660     /**
661      * Creates a new instance of the specified class.
662      * In the unmarshaller, we need to check the user-specified factory class.
663      */
createInstance( Class<?> clazz )664     public Object createInstance( Class<?> clazz ) throws SAXException {
665         if(!factories.isEmpty()) {
666             Factory factory = factories.get(clazz);
667             if(factory!=null)
668                 return factory.createInstance();
669         }
670         return ClassFactory.create(clazz);
671     }
672 
673     /**
674      * Creates a new instance of the specified class.
675      * In the unmarshaller, we need to check the user-specified factory class.
676      */
createInstance( JaxBeanInfo beanInfo )677     public Object createInstance( JaxBeanInfo beanInfo ) throws SAXException {
678         if(!factories.isEmpty()) {
679             Factory factory = factories.get(beanInfo.jaxbType);
680             if(factory!=null)
681                 return factory.createInstance();
682         }
683         try {
684             return beanInfo.createInstance(this);
685         } catch (IllegalAccessException e) {
686             Loader.reportError("Unable to create an instance of "+beanInfo.jaxbType.getName(),e,false);
687         } catch (InvocationTargetException e) {
688             Loader.reportError("Unable to create an instance of "+beanInfo.jaxbType.getName(),e,false);
689         } catch (InstantiationException e) {
690             Loader.reportError("Unable to create an instance of "+beanInfo.jaxbType.getName(),e,false);
691         }
692         return null;    // can never be here
693     }
694 
695 
696 
697 //
698 //
699 // error handling
700 //
701 //
702 
703     /**
704      * Reports an error to the user, and asks if s/he wants
705      * to recover. If the canRecover flag is false, regardless
706      * of the client instruction, an exception will be thrown.
707      *
708      * Only if the flag is true and the user wants to recover from an error,
709      * the method returns normally.
710      *
711      * The thrown exception will be catched by the unmarshaller.
712      */
handleEvent(ValidationEvent event, boolean canRecover )713     public void handleEvent(ValidationEvent event, boolean canRecover ) throws SAXException {
714         ValidationEventHandler eventHandler = parent.getEventHandler();
715 
716         boolean recover = eventHandler.handleEvent(event);
717 
718         // if the handler says "abort", we will not return the object
719         // from the unmarshaller.getResult()
720         if(!recover)    aborted = true;
721 
722         if( !canRecover || !recover )
723             throw new SAXParseException2( event.getMessage(), locator,
724                 new UnmarshalException(
725                     event.getMessage(),
726                     event.getLinkedException() ) );
727     }
728 
729     @Override
handleEvent(ValidationEvent event)730     public boolean handleEvent(ValidationEvent event) {
731         try {
732             // if the handler says "abort", we will not return the object.
733             boolean recover = parent.getEventHandler().handleEvent(event);
734             if(!recover)    aborted = true;
735             return recover;
736         } catch( RuntimeException re ) {
737             // if client event handler causes a runtime exception, then we
738             // have to return false.
739             return false;
740         }
741     }
742 
743     /**
744      * Reports an exception found during the unmarshalling to the user.
745      * This method is a convenience method that calls into
746      * {@link #handleEvent(ValidationEvent, boolean)}
747      */
handleError(Exception e)748     public void handleError(Exception e) throws SAXException {
749         handleError(e,true);
750     }
751 
handleError(Exception e,boolean canRecover)752     public void handleError(Exception e,boolean canRecover) throws SAXException {
753         handleEvent(new ValidationEventImpl(ValidationEvent.ERROR,e.getMessage(),locator.getLocation(),e),canRecover);
754     }
755 
handleError(String msg)756     public void handleError(String msg) {
757         handleEvent(new ValidationEventImpl(ValidationEvent.ERROR,msg,locator.getLocation()));
758     }
759 
760     @Override
getLocation()761     protected ValidationEventLocator getLocation() {
762         return locator.getLocation();
763     }
764 
765     /**
766      * Gets the current source location information in SAX {@link Locator}.
767      * <p>
768      * Sometimes the unmarshaller works against a different kind of XML source,
769      * making this information meaningless.
770      */
getLocator()771     public LocatorEx getLocator() { return locator; }
772 
773     /**
774      * Called when there's no corresponding ID value.
775      */
errorUnresolvedIDREF(Object bean, String idref, LocatorEx loc)776     public void errorUnresolvedIDREF(Object bean, String idref, LocatorEx loc) throws SAXException {
777         handleEvent( new ValidationEventImpl(
778             ValidationEvent.ERROR,
779             Messages.UNRESOLVED_IDREF.format(idref),
780             loc.getLocation()), true );
781     }
782 
783 
784 //
785 //
786 // ID/IDREF related code
787 //
788 //
789     /**
790      * Submitted patchers in the order they've submitted.
791      * Many XML vocabulary doesn't use ID/IDREF at all, so we
792      * initialize it with null.
793      */
794     private Patcher[] patchers = null;
795     private int patchersLen = 0;
796 
797     /**
798      * Adds a job that will be executed at the last of the unmarshalling.
799      * This method is used to support ID/IDREF feature, but it can be used
800      * for other purposes as well.
801      *
802      * @param   job
803      *      The run method of this object is called.
804      */
addPatcher( Patcher job )805     public void addPatcher( Patcher job ) {
806         // re-allocate buffer if necessary
807         if( patchers==null )
808             patchers = new Patcher[32];
809         if( patchers.length == patchersLen ) {
810             Patcher[] buf = new Patcher[patchersLen*2];
811             System.arraycopy(patchers,0,buf,0,patchersLen);
812             patchers = buf;
813         }
814         patchers[patchersLen++] = job;
815     }
816 
817     /** Executes all the patchers. */
runPatchers()818     private void runPatchers() throws SAXException {
819         if( patchers!=null ) {
820             for( int i=0; i<patchersLen; i++ ) {
821                 patchers[i].run();
822                 patchers[i] = null; // free memory
823             }
824         }
825     }
826 
827     /**
828      * Adds the object which is currently being unmarshalled
829      * to the ID table.
830      *
831      * @return
832      *      Returns the value passed as the parameter.
833      *      This is a hack, but this makes it easier for ID
834      *      transducer to do its job.
835      */
836     // TODO: what shall we do if the ID is already declared?
837     //
838     // throwing an exception is one way. Overwriting the previous one
839     // is another way. The latter allows us to process invalid documents,
840     // while the former makes it impossible to handle them.
841     //
842     // I prefer to be flexible in terms of invalid document handling,
843     // so chose not to throw an exception.
844     //
845     // I believe this is an implementation choice, not the spec issue.
846     // -kk
addToIdTable( String id )847     public String addToIdTable( String id ) throws SAXException {
848         // Hmm...
849         // in cases such as when ID is used as an attribute, or as @XmlValue
850         // the target wilil be current.target.
851         // but in some other cases, such as when ID is used as a child element
852         // or a value of JAXBElement, it's current.prev.target.
853         // I don't know if this detection logic is complete
854         Object o = current.target;
855         if(o==null)
856             o = current.prev.target;
857         idResolver.bind(id,o);
858         return id;
859     }
860 
861     /**
862      * Looks up the ID table and gets associated object.
863      *
864      * <p>
865      * The exception thrown from {@link Callable#call()} means the unmarshaller should abort
866      * right away.
867      *
868      * @see IDResolver#resolve(String, Class)
869      */
getObjectFromId( String id, Class targetType )870     public Callable getObjectFromId( String id, Class targetType ) throws SAXException {
871         return idResolver.resolve(id,targetType);
872     }
873 
874 //
875 //
876 // namespace binding maintainance
877 //
878 //
879     private String[] nsBind = new String[16];
880     private int nsLen=0;
881 
882     @Override
startPrefixMapping( String prefix, String uri )883     public void startPrefixMapping( String prefix, String uri ) {
884         if(nsBind.length==nsLen) {
885             // expand the buffer
886             String[] n = new String[nsLen*2];
887             System.arraycopy(nsBind,0,n,0,nsLen);
888             nsBind=n;
889         }
890         nsBind[nsLen++] = prefix;
891         nsBind[nsLen++] = uri;
892     }
893     @Override
endPrefixMapping( String prefix )894     public void endPrefixMapping( String prefix ) {
895         nsLen-=2;
896     }
resolveNamespacePrefix( String prefix )897     private String resolveNamespacePrefix( String prefix ) {
898         if(prefix.equals("xml"))
899             return XMLConstants.XML_NS_URI;
900 
901         for( int i=nsLen-2; i>=0; i-=2 ) {
902             if(prefix.equals(nsBind[i]))
903                 return nsBind[i+1];
904         }
905 
906         if(environmentNamespaceContext!=null)
907             // temporary workaround until Zephyr fixes 6337180
908             return environmentNamespaceContext.getNamespaceURI(prefix.intern());
909 
910         // by default, the default ns is bound to "".
911         // but allow environmentNamespaceContext to take precedence
912         if(prefix.equals(""))
913             return "";
914 
915         // unresolved. error.
916         return null;
917     }
918 
919     /**
920      * Returns a list of prefixes newly declared on the current element.
921      *
922      * @return
923      *      A possible zero-length array of prefixes. The default prefix
924      *      is represented by the empty string.
925      */
getNewlyDeclaredPrefixes()926     public String[] getNewlyDeclaredPrefixes() {
927         return getPrefixList( current.prev.numNsDecl );
928     }
929 
930     /**
931      * Returns a list of all in-scope prefixes.
932      *
933      * @return
934      *      A possible zero-length array of prefixes. The default prefix
935      *      is represented by the empty string.
936      */
getAllDeclaredPrefixes()937     public String[] getAllDeclaredPrefixes() {
938         return getPrefixList(0);
939     }
940 
getPrefixList( int startIndex )941     private String[] getPrefixList( int startIndex ) {
942         int size = (current.numNsDecl - startIndex)/2;
943         String[] r = new String[size];
944         for( int i=0; i<r.length; i++ )
945             r[i] = nsBind[startIndex+i*2];
946         return r;
947     }
948 
949     //  NamespaceContext2 implementation
950     //
951     @Override
getPrefixes(String uri)952     public Iterator<String> getPrefixes(String uri) {
953         // TODO: could be implemented much faster
954         // wrap it into unmodifiable list so that the remove method
955         // will throw UnsupportedOperationException.
956         return Collections.unmodifiableList(
957             getAllPrefixesInList(uri)).iterator();
958     }
959 
getAllPrefixesInList(String uri)960     private List<String> getAllPrefixesInList(String uri) {
961         List<String> a = new ArrayList<String>();
962 
963         if( uri==null )
964             throw new IllegalArgumentException();
965         if( uri.equals(XMLConstants.XML_NS_URI) ) {
966             a.add(XMLConstants.XML_NS_PREFIX);
967             return a;
968         }
969         if( uri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI) ) {
970             a.add(XMLConstants.XMLNS_ATTRIBUTE);
971             return a;
972         }
973 
974         for( int i=nsLen-2; i>=0; i-=2 )
975             if(uri.equals(nsBind[i+1]))
976                 if( getNamespaceURI(nsBind[i]).equals(nsBind[i+1]) )
977                     // make sure that this prefix is still effective.
978                     a.add(nsBind[i]);
979 
980         return a;
981     }
982 
983     @Override
getPrefix(String uri)984     public String getPrefix(String uri) {
985         if( uri==null )
986             throw new IllegalArgumentException();
987         if( uri.equals(XMLConstants.XML_NS_URI) )
988             return XMLConstants.XML_NS_PREFIX;
989         if( uri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI) )
990             return XMLConstants.XMLNS_ATTRIBUTE;
991 
992         for( int i=nsLen-2; i>=0; i-=2 )
993             if(uri.equals(nsBind[i+1]))
994                 if( getNamespaceURI(nsBind[i]).equals(nsBind[i+1]) )
995                     // make sure that this prefix is still effective.
996                     return nsBind[i];
997 
998         if(environmentNamespaceContext!=null)
999             return environmentNamespaceContext.getPrefix(uri);
1000 
1001         return null;
1002     }
1003 
1004     @Override
getNamespaceURI(String prefix)1005     public String getNamespaceURI(String prefix) {
1006         if (prefix == null)
1007             throw new IllegalArgumentException();
1008         if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE))
1009             return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
1010 
1011         return resolveNamespacePrefix(prefix);
1012     }
1013 
1014 //
1015 //
1016 //
1017 // scope management
1018 //
1019 //
1020 //
1021     private Scope[] scopes = new Scope[16];
1022     /**
1023      * Points to the top of the scope stack (=size-1).
1024      */
1025     private int scopeTop=0;
1026 
1027     {
1028         for( int i=0; i<scopes.length; i++ )
1029             scopes[i] = new Scope(this);
1030     }
1031 
1032     /**
1033      * Starts a new packing scope.
1034      *
1035      * <p>
1036      * This method allocates a specified number of fresh {@link Scope} objects.
1037      * They can be accessed by the {@link #getScope} method until the corresponding
1038      * {@link #endScope} method is invoked.
1039      *
1040      * <p>
1041      * A new scope will mask the currently active scope. Only one frame of {@link Scope}s
1042      * can be accessed at any given time.
1043      *
1044      * @param frameSize
1045      *      The # of slots to be allocated.
1046      */
startScope(int frameSize)1047     public void startScope(int frameSize) {
1048         scopeTop += frameSize;
1049 
1050         // reallocation
1051         if(scopeTop>=scopes.length) {
1052             Scope[] s = new Scope[Math.max(scopeTop+1,scopes.length*2)];
1053             System.arraycopy(scopes,0,s,0,scopes.length);
1054             for( int i=scopes.length; i<s.length; i++ )
1055                 s[i] = new Scope(this);
1056             scopes = s;
1057         }
1058     }
1059 
1060     /**
1061      * Ends the current packing scope.
1062      *
1063      * <p>
1064      * If any packing in progress will be finalized by this method.
1065      *
1066      * @param frameSize
1067      *      The same size that gets passed to the {@link #startScope(int)}
1068      *      method.
1069      */
endScope(int frameSize)1070     public void endScope(int frameSize) throws SAXException {
1071         try {
1072             for( ; frameSize>0; frameSize--, scopeTop-- )
1073                 scopes[scopeTop].finish();
1074         } catch (AccessorException e) {
1075             handleError(e);
1076 
1077             // the error might have left scopes in inconsistent state,
1078             // so replace them by fresh ones
1079             for( ; frameSize>0; frameSize-- )
1080                 scopes[scopeTop--] = new Scope(this);
1081         }
1082     }
1083 
1084     /**
1085      * Gets the currently active {@link Scope}.
1086      *
1087      * @param offset
1088      *      a number between [0,frameSize)
1089      *
1090      * @return
1091      *      always a valid {@link Scope} object.
1092      */
getScope(int offset)1093     public Scope getScope(int offset) {
1094         return scopes[scopeTop-offset];
1095     }
1096 
1097 //
1098 //
1099 //
1100 //
1101 //
1102 //
1103 //
1104 
1105     private static final Loader DEFAULT_ROOT_LOADER = new DefaultRootLoader();
1106     private static final Loader EXPECTED_TYPE_ROOT_LOADER = new ExpectedTypeRootLoader();
1107 
1108     /**
1109      * Root loader that uses the tag name and possibly its @xsi:type
1110      * to decide how to start unmarshalling.
1111      */
1112     private static final class DefaultRootLoader extends Loader implements Receiver {
1113         /**
1114          * Receives the root element and determines how to start
1115          * unmarshalling.
1116          */
1117         @Override
childElement(UnmarshallingContext.State state, TagName ea)1118         public void childElement(UnmarshallingContext.State state, TagName ea) throws SAXException {
1119             Loader loader = state.getContext().selectRootLoader(state,ea);
1120             if(loader!=null) {
1121                 state.loader = loader;
1122                 state.receiver = this;
1123                 return;
1124             }
1125 
1126             // the registry doesn't know about this element.
1127             // try its xsi:type
1128             JaxBeanInfo beanInfo = XsiTypeLoader.parseXsiType(state, ea, null);
1129             if(beanInfo==null) {
1130                 // we don't even know its xsi:type
1131                 reportUnexpectedChildElement(ea,false);
1132                 return;
1133             }
1134 
1135             state.loader = beanInfo.getLoader(null,false);
1136             state.prev.backup = new JAXBElement<Object>(ea.createQName(),Object.class,null);
1137             state.receiver = this;
1138         }
1139 
1140         @Override
getExpectedChildElements()1141         public Collection<QName> getExpectedChildElements() {
1142             return getInstance().getJAXBContext().getValidRootNames();
1143         }
1144 
1145         @Override
receive(State state, Object o)1146         public void receive(State state, Object o) {
1147              if(state.backup!=null) {
1148                 ((JAXBElement<Object>)state.backup).setValue(o);
1149                 o = state.backup;
1150             }
1151             if (state.nil) {
1152                 ((JAXBElement<Object>)o).setNil(true);
1153             }
1154             state.getContext().result = o;
1155         }
1156     }
1157 
1158     /**
1159      * Root loader that uses {@link UnmarshallingContext#expectedType}
1160      * to decide how to start unmarshalling.
1161      */
1162     private static final class ExpectedTypeRootLoader extends Loader implements Receiver {
1163         /**
1164          * Receives the root element and determines how to start
1165          * unmarshalling.
1166          */
1167         @Override
childElement(UnmarshallingContext.State state, TagName ea)1168         public void childElement(UnmarshallingContext.State state, TagName ea) {
1169             UnmarshallingContext context = state.getContext();
1170 
1171             // unmarshals the specified type
1172             QName qn = new QName(ea.uri,ea.local);
1173             state.prev.target = new JAXBElement(qn,context.expectedType.jaxbType,null,null);
1174             state.receiver = this;
1175             // this is bit wasteful, as in theory we should have each expectedType keep
1176             // nillable version --- but that increases the combination from two to four,
1177             // which adds the resident memory footprint. Since XsiNilLoader is small,
1178             // I intentionally allocate a new instance freshly.
1179             state.loader = new XsiNilLoader(context.expectedType.getLoader(null,true));
1180         }
1181 
1182         @Override
receive(State state, Object o)1183         public void receive(State state, Object o) {
1184             JAXBElement e = (JAXBElement)state.target;
1185             e.setValue(o);
1186             state.getContext().recordOuterPeer(e);
1187             state.getContext().result = e;
1188         }
1189     }
1190 
1191 //
1192 // in-place unmarshalling related capabilities
1193 //
1194     /**
1195      * Notifies the context about the inner peer of the current element.
1196      *
1197      * <p>
1198      * If the unmarshalling is building the association, the context
1199      * will use this information. Otherwise it will be just ignored.
1200      */
recordInnerPeer(Object innerPeer)1201     public void recordInnerPeer(Object innerPeer) {
1202         if(assoc!=null)
1203             assoc.addInner(currentElement,innerPeer);
1204     }
1205 
1206     /**
1207      * Gets the inner peer JAXB object associated with the current element.
1208      *
1209      * @return
1210      *      null if the current element doesn't have an inner peer,
1211      *      or if we are not doing the in-place unmarshalling.
1212      */
getInnerPeer()1213     public Object getInnerPeer() {
1214         if(assoc!=null && isInplaceMode)
1215             return assoc.getInnerPeer(currentElement);
1216         else
1217             return null;
1218     }
1219 
1220     /**
1221      * Notifies the context about the outer peer of the current element.
1222      *
1223      * <p>
1224      * If the unmarshalling is building the association, the context
1225      * will use this information. Otherwise it will be just ignored.
1226      */
recordOuterPeer(Object outerPeer)1227     public void recordOuterPeer(Object outerPeer) {
1228         if(assoc!=null)
1229             assoc.addOuter(currentElement,outerPeer);
1230     }
1231 
1232     /**
1233      * Gets the outer peer JAXB object associated with the current element.
1234      *
1235      * @return
1236      *      null if the current element doesn't have an inner peer,
1237      *      or if we are not doing the in-place unmarshalling.
1238      */
getOuterPeer()1239     public Object getOuterPeer() {
1240         if(assoc!=null && isInplaceMode)
1241             return assoc.getOuterPeer(currentElement);
1242         else
1243             return null;
1244     }
1245 
1246     /**
1247      * Gets the xmime:contentType value for the current object.
1248      *
1249      * @see JAXBContextImpl#getXMIMEContentType(Object)
1250      */
getXMIMEContentType()1251     public String getXMIMEContentType() {
1252         /*
1253             this won't work when the class is like
1254 
1255             class Foo {
1256                 @XmlValue Image img;
1257             }
1258 
1259             because the target will return Foo, not the class enclosing Foo
1260             which will have xmime:contentType
1261         */
1262         Object t = current.target;
1263         if(t==null)     return null;
1264         return getJAXBContext().getXMIMEContentType(t);
1265     }
1266 
1267     /**
1268      * When called from within the realm of the unmarshaller, this method
1269      * returns the current {@link UnmarshallingContext} in charge.
1270      */
getInstance()1271     public static UnmarshallingContext getInstance() {
1272         return (UnmarshallingContext) Coordinator._getInstance();
1273     }
1274 
1275     /**
1276      * Allows to access elements which are expected in current state.
1277      * Useful for getting elements for current parent.
1278      *
1279      * @return
1280      */
getCurrentExpectedElements()1281     public Collection<QName> getCurrentExpectedElements() {
1282         pushCoordinator();
1283         try {
1284             State s = getCurrentState();
1285             Loader l = s.loader;
1286             return (l != null) ? l.getExpectedChildElements() : null;
1287         } finally {
1288             popCoordinator();
1289         }
1290     }
1291 
1292     /**
1293      * Allows to access attributes which are expected in current state.
1294      * Useful for getting attributes for current parent.
1295      *
1296      * @return
1297      */
getCurrentExpectedAttributes()1298     public Collection<QName> getCurrentExpectedAttributes() {
1299         pushCoordinator();
1300         try {
1301             State s = getCurrentState();
1302             Loader l = s.loader;
1303             return (l != null) ? l.getExpectedAttributes() : null;
1304         } finally {
1305             popCoordinator();
1306         }
1307     }
1308 
1309     /**
1310      * Gets StructureLoader if used as loader.
1311      * Useful when determining if element is mixed or not.
1312      *
1313      */
getStructureLoader()1314     public StructureLoader getStructureLoader() {
1315         if(current.loader instanceof StructureLoader)
1316             return (StructureLoader)current.loader;
1317 
1318         return null;
1319     }
1320 
1321     /**
1322      * Based on current {@link Logger} {@link Level} and errorCounter value determines if error should be reported.
1323      *
1324      * If the method called and return true it is expected that error will be reported. And that's why
1325      * errorCounter is automatically decremented during the check.
1326      *
1327      * NOT THREAD SAFE!!! In case of heave concurrency access several additional errors could be reported. It's not expected to be the
1328      * problem. Otherwise add synchronization here.
1329      *
1330      * @return true in case if {@link Level#FINEST} is set OR we haven't exceed errors reporting limit.
1331      */
shouldErrorBeReported()1332     public boolean shouldErrorBeReported() throws SAXException {
1333         if (logger.isLoggable(Level.FINEST))
1334             return true;
1335 
1336         if (errorsCounter >= 0) {
1337             --errorsCounter;
1338             if (errorsCounter == 0) // it's possible to miss this because of concurrency. If required add synchronization here
1339                 handleEvent(new ValidationEventImpl(ValidationEvent.WARNING, Messages.ERRORS_LIMIT_EXCEEDED.format(),
1340                         getLocator().getLocation(), null), true);
1341         }
1342         return errorsCounter >= 0;
1343     }
1344 }
1345