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