< prev index next >

src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/DTMManagerDefault.java

Print this page
rev 1072 : 8172974: [JAXP] XALAN: Wrong result when transforming namespace unaware StAX Input
   1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 1999-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at

  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: DTMManagerDefault.java,v 1.2.4.1 2005/09/15 08:15:02 suresh_emailid Exp $
  22  */
  23 package com.sun.org.apache.xml.internal.dtm.ref;
  24 
  25 import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
  26 import javax.xml.parsers.DocumentBuilder;
  27 import javax.xml.parsers.DocumentBuilderFactory;
  28 import javax.xml.transform.Source;
  29 import javax.xml.transform.dom.DOMSource;
  30 import javax.xml.transform.sax.SAXSource;
  31 import javax.xml.transform.stream.StreamSource;
  32 
  33 import com.sun.org.apache.xml.internal.dtm.DTM;
  34 import com.sun.org.apache.xml.internal.dtm.DTMException;
  35 import com.sun.org.apache.xml.internal.dtm.DTMFilter;
  36 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  37 import com.sun.org.apache.xml.internal.dtm.DTMManager;
  38 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  39 import com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTM;

  40 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM;
  41 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2RTFDTM;
  42 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
  43 import com.sun.org.apache.xml.internal.res.XMLMessages;
  44 import com.sun.org.apache.xml.internal.utils.PrefixResolver;
  45 import com.sun.org.apache.xml.internal.utils.SystemIDResolver;

  46 import com.sun.org.apache.xml.internal.utils.XMLReaderManager;
  47 import com.sun.org.apache.xml.internal.utils.XMLStringFactory;
  48 






  49 import org.w3c.dom.Document;
  50 import org.w3c.dom.Node;
  51 
  52 import org.xml.sax.InputSource;
  53 import org.xml.sax.SAXException;
  54 import org.xml.sax.SAXNotRecognizedException;
  55 import org.xml.sax.SAXNotSupportedException;
  56 import org.xml.sax.XMLReader;
  57 import org.xml.sax.helpers.DefaultHandler;
  58 
  59 /**
  60  * The default implementation for the DTMManager.
  61  *
  62  * %REVIEW% There is currently a reentrancy issue, since the finalizer
  63  * for XRTreeFrag (which runs in the GC thread) wants to call
  64  * DTMManager.release(), and may do so at the same time that the main
  65  * transformation thread is accessing the manager. Our current solution is
  66  * to make most of the manager's methods <code>synchronized</code>.
  67  * Early tests suggest that doing so is not causing a significant
  68  * performance hit in Xalan. However, it should be noted that there
  69  * is a possible alternative solution: rewrite release() so it merely
  70  * posts a request for release onto a threadsafe queue, and explicitly
  71  * process that queue on an infrequent basis during main-thread
  72  * activity (eg, when getDTM() is invoked). The downside of that solution
  73  * would be a greater delay before the DTM's storage is actually released
  74  * for reuse.
  75  * */
  76 public class DTMManagerDefault extends DTMManager
  77 {
  78   //static final boolean JKESS_XNI_EXPERIMENT=true;
  79 
  80   /** Set this to true if you want a dump of the DTM after creation. */
  81   private static final boolean DUMPTREE = false;
  82 
  83   /** Set this to true if you want a basic diagnostics. */
  84   private static final boolean DEBUG = false;
  85 
  86   /**
  87    * Map from DTM identifier numbers to DTM objects that this manager manages.
  88    * One DTM may have several prefix numbers, if extended node indexing
  89    * is in use; in that case, m_dtm_offsets[] will used to control which
  90    * prefix maps to which section of the DTM.
  91    *
  92    * This array grows as necessary; see addDTM().
  93    *
  94    * This array grows as necessary; see addDTM(). Growth is uncommon... but
  95    * access needs to be blindingly fast since it's used in node addressing.
  96    */
  97   protected DTM m_dtms[] = new DTM[256];
  98 
  99   /** Map from DTM identifier numbers to offsets. For small DTMs with a
 100    * single identifier, this will always be 0. In overflow addressing, where
 101    * additional identifiers are allocated to access nodes beyond the range of
 102    * a single Node Handle, this table is used to map the handle's node field
 103    * into the actual node identifier.
 104    *


 113 
 114   /**
 115    * The cache for XMLReader objects to be used if the user did not
 116    * supply an XMLReader for a SAXSource or supplied a StreamSource.
 117    */
 118   protected XMLReaderManager m_readerManager = null;
 119 
 120   /**
 121    * The default implementation of ContentHandler, DTDHandler and ErrorHandler.
 122    */
 123   protected DefaultHandler m_defaultHandler = new DefaultHandler();
 124 
 125   /**
 126    * Add a DTM to the DTM table. This convenience call adds it as the
 127    * "base DTM ID", with offset 0. The other version of addDTM should
 128    * be used if you want to add "extended" DTM IDs with nonzero offsets.
 129    *
 130    * @param dtm Should be a valid reference to a DTM.
 131    * @param id Integer DTM ID to be bound to this DTM
 132    */
 133   synchronized public void addDTM(DTM dtm, int id) {    addDTM(dtm,id,0); }
 134 

 135 
 136   /**
 137    * Add a DTM to the DTM table.
 138    *
 139    * @param dtm Should be a valid reference to a DTM.
 140    * @param id Integer DTM ID to be bound to this DTM.
 141    * @param offset Integer addressing offset. The internal DTM Node ID is
 142    * obtained by adding this offset to the node-number field of the
 143    * public DTM Handle. For the first DTM ID accessing each DTM, this is 0;
 144    * for overflow addressing it will be a multiple of 1<<IDENT_DTM_NODE_BITS.
 145    */
 146   synchronized public void addDTM(DTM dtm, int id, int offset)
 147   {
 148                 if(id>=IDENT_MAX_DTMS)
 149                 {
 150                         // TODO: %REVIEW% Not really the right error message.
 151             throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_DTMIDS_AVAIL, null)); //"No more DTM IDs are available!");
 152                 }
 153 
 154                 // We used to just allocate the array size to IDENT_MAX_DTMS.
 155                 // But we expect to increase that to 16 bits, and I'm not willing
 156                 // to allocate that much space unless needed. We could use one of our
 157                 // handy-dandy Fast*Vectors, but this will do for now.
 158                 // %REVIEW%
 159                 int oldlen=m_dtms.length;
 160                 if(oldlen<=id)
 161                 {
 162                         // Various growth strategies are possible. I think we don't want
 163                         // to over-allocate excessively, and I'm willing to reallocate
 164                         // more often to get that. See also Fast*Vector classes.
 165                         //
 166                         // %REVIEW% Should throw a more diagnostic error if we go over the max...
 167                         int newlen=Math.min((id+256),IDENT_MAX_DTMS);
 168 
 169                         DTM new_m_dtms[] = new DTM[newlen];
 170                         System.arraycopy(m_dtms,0,new_m_dtms,0,oldlen);
 171                         m_dtms=new_m_dtms;
 172                         int new_m_dtm_offsets[] = new int[newlen];
 173                         System.arraycopy(m_dtm_offsets,0,new_m_dtm_offsets,0,oldlen);
 174                         m_dtm_offsets=new_m_dtm_offsets;
 175                 }
 176 
 177     m_dtms[id] = dtm;
 178                 m_dtm_offsets[id]=offset;
 179     dtm.documentRegistration();
 180                 // The DTM should have been told who its manager was when we created it.
 181                 // Do we need to allow for adopting DTMs _not_ created by this manager?
 182   }
 183 
 184   /**
 185    * Get the first free DTM ID available. %OPT% Linear search is inefficient!
 186    */
 187   synchronized public int getFirstFreeDTMID()
 188   {
 189     int n = m_dtms.length;
 190     for (int i = 1; i < n; i++)
 191     {
 192       if(null == m_dtms[i])
 193       {
 194         return i;
 195       }
 196     }
 197                 return n; // count on addDTM() to throw exception if out of range
 198   }
 199 
 200   /**
 201    * The default table for exandedNameID lookups.
 202    */
 203   private ExpandedNameTable m_expandedNameTable =
 204     new ExpandedNameTable();
 205 
 206   /**
 207    * Constructor DTMManagerDefault
 208    *
 209    */
 210   public DTMManagerDefault(){}
 211 
 212 
 213   /**
 214    * Get an instance of a DTM, loaded with the content from the
 215    * specified source.  If the unique flag is true, a new instance will
 216    * always be returned.  Otherwise it is up to the DTMManager to return a
 217    * new instance or an instance that it already created and may be being used
 218    * by someone else.
 219    *
 220    * A bit of magic in this implementation: If the source is null, unique is true,
 221    * and incremental and doIndexing are both false, we return an instance of
 222    * SAX2RTFDTM, which see.
 223    *
 224    * (I think more parameters will need to be added for error handling, and entity
 225    * resolution, and more explicit control of the RTF situation).
 226    *
 227    * @param source the specification of the source object.
 228    * @param unique true if the returned DTM must be unique, probably because it
 229    * is going to be mutated.
 230    * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
 231    *                         be null.
 232    * @param incremental true if the DTM should be built incrementally, if
 233    *                    possible.
 234    * @param doIndexing true if the caller considers it worth it to use
 235    *                   indexing schemes.
 236    *
 237    * @return a non-null DTM reference.
 238    */
 239   synchronized public DTM getDTM(Source source, boolean unique,
 240                                  DTMWSFilter whiteSpaceFilter,
 241                                  boolean incremental, boolean doIndexing)
 242   {
 243 
 244     if(DEBUG && null != source)
 245       System.out.println("Starting "+
 246                          (unique ? "UNIQUE" : "shared")+
 247                          " source: "+source.getSystemId()
 248                          );

 249 
 250     XMLStringFactory xstringFactory = m_xsf;
 251     int dtmPos = getFirstFreeDTMID();
 252     int documentID = dtmPos << IDENT_DTM_NODE_BITS;
 253 
 254     if ((null != source) && source instanceof DOMSource)
 255     {
 256       DOM2DTM dtm = new DOM2DTM(this, (DOMSource) source, documentID,
 257                                 whiteSpaceFilter, xstringFactory, doIndexing);
 258 
 259       addDTM(dtm, dtmPos, 0);
 260 
 261       //      if (DUMPTREE)
 262       //      {
 263       //        dtm.dumpDTM();
 264       //      }
 265 
 266       return dtm;
 267     }
 268     else
 269     {
 270       boolean isSAXSource = (null != source)
 271         ? (source instanceof SAXSource) : true;
 272       boolean isStreamSource = (null != source)
 273         ? (source instanceof StreamSource) : false;
 274 
 275       if (isSAXSource || isStreamSource) {
 276         XMLReader reader = null;
 277         SAX2DTM dtm;
 278 
 279         try {
 280           InputSource xmlSource;
 281 
 282           if (null == source) {
 283             xmlSource = null;
 284           } else {
 285             reader = getXMLReader(source);
 286             xmlSource = SAXSource.sourceToInputSource(source);
 287 
 288             String urlOfSource = xmlSource.getSystemId();
 289 
 290             if (null != urlOfSource) {
 291               try {
 292                 urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource);
 293               } catch (Exception e) {
 294                 // %REVIEW% Is there a better way to send a warning?
 295                 System.err.println("Can not absolutize URL: " + urlOfSource);
 296               }
 297 
 298               xmlSource.setSystemId(urlOfSource);
 299             }
 300           }
 301 
 302           if (source==null && unique && !incremental && !doIndexing) {
 303             // Special case to support RTF construction into shared DTM.
 304             // It should actually still work for other uses,
 305             // but may be slightly deoptimized relative to the base
 306             // to allow it to deal with carrying multiple documents.
 307             //
 308             // %REVIEW% This is a sloppy way to request this mode;
 309             // we need to consider architectural improvements.
 310             dtm = new SAX2RTFDTM(this, source, documentID, whiteSpaceFilter,
 311                                  xstringFactory, doIndexing);
 312           }
 313           /**************************************************************
 314           // EXPERIMENTAL 3/22/02
 315           else if(JKESS_XNI_EXPERIMENT && m_incremental) {
 316             dtm = new XNI2DTM(this, source, documentID, whiteSpaceFilter,
 317                               xstringFactory, doIndexing);
 318           }
 319           **************************************************************/
 320           // Create the basic SAX2DTM.
 321           else {
 322             dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
 323                               xstringFactory, doIndexing);
 324           }
 325 
 326           // Go ahead and add the DTM to the lookup table.  This needs to be
 327           // done before any parsing occurs. Note offset 0, since we've just
 328           // created a new DTM.
 329           addDTM(dtm, dtmPos, 0);
 330 
 331 
 332           boolean haveXercesParser =
 333                      (null != reader)
 334                      && (reader.getClass()
 335                                .getName()
 336                                .equals("com.sun.org.apache.xerces.internal.parsers.SAXParser") );
 337 
 338           if (haveXercesParser) {
 339             incremental = true;  // No matter what.  %REVIEW%
 340           }
 341 
 342           // If the reader is null, but they still requested an incremental
 343           // build, then we still want to set up the IncrementalSAXSource stuff.
 344           if (m_incremental && incremental
 345                /* || ((null == reader) && incremental) */) {
 346             IncrementalSAXSource coParser=null;
 347 
 348             if (haveXercesParser) {
 349               // IncrementalSAXSource_Xerces to avoid threading.
 350               try {
 351                 coParser = new com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Xerces();
 352               }  catch( Exception ex ) {
 353                 ex.printStackTrace();
 354                 coParser=null;
 355               }
 356             }
 357 
 358             if (coParser==null ) {
 359               // Create a IncrementalSAXSource to run on the secondary thread.
 360               if (null == reader) {
 361                 coParser = new IncrementalSAXSource_Filter();
 362               } else {
 363                 IncrementalSAXSource_Filter filter =
 364                          new IncrementalSAXSource_Filter();
 365                 filter.setXMLReader(reader);
 366                 coParser=filter;
 367               }
 368             }
 369 
 370 
 371             /**************************************************************
 372             // EXPERIMENTAL 3/22/02
 373             if (JKESS_XNI_EXPERIMENT && m_incremental &&
 374                   dtm instanceof XNI2DTM &&
 375                   coParser instanceof IncrementalSAXSource_Xerces) {
 376                 com.sun.org.apache.xerces.internal.xni.parser.XMLPullParserConfiguration xpc=
 377                       ((IncrementalSAXSource_Xerces)coParser)
 378                                            .getXNIParserConfiguration();
 379               if (xpc!=null) {
 380                 // Bypass SAX; listen to the XNI stream
 381                 ((XNI2DTM)dtm).setIncrementalXNISource(xpc);
 382               } else {
 383                   // Listen to the SAX stream (will fail, diagnostically...)
 384                 dtm.setIncrementalSAXSource(coParser);
 385               }
 386             } else
 387             ***************************************************************/
 388 
 389             // Have the DTM set itself up as IncrementalSAXSource's listener.
 390             dtm.setIncrementalSAXSource(coParser);
 391 
 392             if (null == xmlSource) {
 393 
 394               // Then the user will construct it themselves.
 395               return dtm;
 396             }
 397 
 398             if (null == reader.getErrorHandler()) {
 399               reader.setErrorHandler(dtm);
 400             }
 401             reader.setDTDHandler(dtm);
 402 
 403             try {
 404               // Launch parsing coroutine.  Launches a second thread,
 405               // if we're using IncrementalSAXSource.filter().
 406 
 407               coParser.startParse(xmlSource);
 408             } catch (RuntimeException re) {
 409 
 410               dtm.clearCoRoutine();
 411 
 412               throw re;
 413             } catch (Exception e) {
 414 
 415               dtm.clearCoRoutine();
 416 
 417               throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
 418             }
 419           } else {
 420             if (null == reader) {
 421 
 422               // Then the user will construct it themselves.
 423               return dtm;
 424             }
 425 
 426             // not incremental
 427             reader.setContentHandler(dtm);
 428             reader.setDTDHandler(dtm);
 429             if (null == reader.getErrorHandler()) {
 430               reader.setErrorHandler(dtm);
 431             }
 432 
 433             try {
 434               reader.setProperty(
 435                                "http://xml.org/sax/properties/lexical-handler",
 436                                dtm);
 437             } catch (SAXNotRecognizedException e){}
 438               catch (SAXNotSupportedException e){}
 439 
 440             try {
 441               reader.parse(xmlSource);
 442             } catch (RuntimeException re) {
 443               dtm.clearCoRoutine();
 444 
 445               throw re;
 446             } catch (Exception e) {
 447               dtm.clearCoRoutine();
 448 
 449               throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
 450             }
 451           }
 452 
 453           if (DUMPTREE) {
 454             System.out.println("Dumping SAX2DOM");
 455             dtm.dumpDTM(System.err);
 456           }
 457 
 458           return dtm;
 459         } finally {
 460           // Reset the ContentHandler, DTDHandler, ErrorHandler to the DefaultHandler
 461           // after creating the DTM.
 462           if (reader != null && !(m_incremental && incremental)) {
 463             reader.setContentHandler(m_defaultHandler);
 464             reader.setDTDHandler(m_defaultHandler);
 465             reader.setErrorHandler(m_defaultHandler);
 466 
 467             // Reset the LexicalHandler to null after creating the DTM.
 468             try {
 469               reader.setProperty("http://xml.org/sax/properties/lexical-handler", null);
 470             }
 471             catch (Exception e) {}
 472           }
 473           releaseXMLReader(reader);
 474         }
 475       } else {
 476 
 477         // It should have been handled by a derived class or the caller
 478         // made a mistake.
 479         throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NOT_SUPPORTED, new Object[]{source})); //"Not supported: " + source);
 480       }
 481     }
 482   }
 483 
 484   /**
 485    * Given a W3C DOM node, try and return a DTM handle.
 486    * Note: calling this may be non-optimal, and there is no guarantee that
 487    * the node will be found in any particular DTM.
 488    *
 489    * @param node Non-null reference to a DOM node.
 490    *
 491    * @return a valid DTM handle.
 492    */
 493   synchronized public int getDTMHandleFromNode(org.w3c.dom.Node node)
 494   {
 495     if(null == node)
 496       throw new IllegalArgumentException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NODE_NON_NULL, null)); //"node must be non-null for getDTMHandleFromNode!");

 497 
 498     if (node instanceof com.sun.org.apache.xml.internal.dtm.ref.DTMNodeProxy)
 499       return ((com.sun.org.apache.xml.internal.dtm.ref.DTMNodeProxy) node).getDTMNodeNumber();
 500 
 501     else
 502     {
 503       // Find the DOM2DTMs wrapped around this Document (if any)
 504       // and check whether they contain the Node in question.
 505       //
 506       // NOTE that since a DOM2DTM may represent a subtree rather
 507       // than a full document, we have to be prepared to check more
 508       // than one -- and there is no guarantee that we will find
 509       // one that contains ancestors or siblings of the node we're
 510       // seeking.
 511       //
 512       // %REVIEW% We could search for the one which contains this
 513       // node at the deepest level, and thus covers the widest
 514       // subtree, but that's going to entail additional work
 515       // checking more DTMs... and getHandleOfNode is not a
 516       // cheap operation in most implementations.
 517                         //
 518                         // TODO: %REVIEW% If overflow addressing, we may recheck a DTM
 519                         // already examined. Ouch. But with the increased number of DTMs,
 520                         // scanning back to check this is painful.
 521                         // POSSIBLE SOLUTIONS:
 522                         //   Generate a list of _unique_ DTM objects?
 523                         //   Have each DTM cache last DOM node search?
 524                         int max = m_dtms.length;
 525       for(int i = 0; i < max; i++)
 526         {
 527           DTM thisDTM=m_dtms[i];
 528           if((null != thisDTM) && thisDTM instanceof DOM2DTM)
 529           {
 530             int handle=((DOM2DTM)thisDTM).getHandleOfNode(node);
 531             if(handle!=DTM.NULL) return handle;
 532           }
 533          }

 534 
 535                         // Not found; generate a new DTM.
 536                         //
 537                         // %REVIEW% Is this really desirable, or should we return null
 538                         // and make folks explicitly instantiate from a DOMSource? The
 539                         // latter is more work but gives the caller the opportunity to
 540                         // explicitly add the DTM to a DTMManager... and thus to know when
 541                         // it can be discarded again, which is something we need to pay much
 542                         // more attention to. (Especially since only DTMs which are assigned
 543                         // to a manager can use the overflow addressing scheme.)
 544                         //
 545                         // %BUG% If the source node was a DOM2DTM$defaultNamespaceDeclarationNode
 546                         // and the DTM wasn't registered with this DTMManager, we will create
 547                         // a new DTM and _still_ not be able to find the node (since it will
 548                         // be resynthesized). Another reason to push hard on making all DTMs
 549                         // be managed DTMs.
 550 
 551                         // Since the real root of our tree may be a DocumentFragment, we need to
 552       // use getParent to find the root, instead of getOwnerDocument.  Otherwise
 553       // DOM2DTM#getHandleOfNode will be very unhappy.
 554       Node root = node;
 555       Node p = (root.getNodeType() == Node.ATTRIBUTE_NODE) ? ((org.w3c.dom.Attr)root).getOwnerElement() : root.getParentNode();
 556       for (; p != null; p = p.getParentNode())
 557       {
 558         root = p;
 559       }
 560 
 561       DOM2DTM dtm = (DOM2DTM) getDTM(new javax.xml.transform.dom.DOMSource(root),
 562                                                                                                                                                  false, null, true, true);
 563 
 564       int handle;
 565 
 566       if(node instanceof com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTMdefaultNamespaceDeclarationNode)
 567       {
 568                                 // Can't return the same node since it's unique to a specific DTM,
 569                                 // but can return the equivalent node -- find the corresponding
 570                                 // Document Element, then ask it for the xml: namespace decl.
 571                                 handle=dtm.getHandleOfNode(((org.w3c.dom.Attr)node).getOwnerElement());
 572                                 handle=dtm.getAttributeNode(handle,node.getNamespaceURI(),node.getLocalName());

 573       }
 574       else
 575                                 handle = ((DOM2DTM)dtm).getHandleOfNode(node);
 576 
 577       if(DTM.NULL == handle)
 578         throw new RuntimeException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COULD_NOT_RESOLVE_NODE, null)); //"Could not resolve the node to a handle!");

 579 
 580       return handle;
 581     }
 582   }
 583 
 584   /**
 585    * This method returns the SAX2 parser to use with the InputSource
 586    * obtained from this URI.
 587    * It may return null if any SAX2-conformant XML parser can be used,
 588    * or if getInputSource() will also return null. The parser must
 589    * be free for use (i.e., not currently in use for another parse().
 590    * After use of the parser is completed, the releaseXMLReader(XMLReader)
 591    * must be called.
 592    *
 593    * @param inputSource The value returned from the URIResolver.
 594    * @return  a SAX2 XMLReader to use to resolve the inputSource argument.
 595    *
 596    * @return non-null XMLReader reference ready to parse.
 597    */
 598   synchronized public XMLReader getXMLReader(Source inputSource)
 599   {
 600 
 601     try
 602     {
 603       XMLReader reader = (inputSource instanceof SAXSource)
 604                          ? ((SAXSource) inputSource).getXMLReader() : null;
 605 
 606       // If user did not supply a reader, ask for one from the reader manager
 607       if (null == reader) {
 608         if (m_readerManager == null) {
 609             m_readerManager = XMLReaderManager.getInstance(super.useServicesMechnism());
 610         }
 611 
 612         reader = m_readerManager.getXMLReader();
 613       }
 614 
 615       return reader;
 616 
 617     } catch (SAXException se) {
 618       throw new DTMException(se.getMessage(), se);
 619     }
 620   }
 621 
 622   /**
 623    * Indicates that the XMLReader object is no longer in use for the transform.
 624    *
 625    * Note that the getXMLReader method may return an XMLReader that was
 626    * specified on the SAXSource object by the application code.  Such a
 627    * reader should still be passed to releaseXMLReader, but the reader manager
 628    * will only re-use XMLReaders that it created.
 629    *
 630    * @param reader The XMLReader to be released.
 631    */
 632   synchronized public void releaseXMLReader(XMLReader reader) {
 633     if (m_readerManager != null) {
 634       m_readerManager.releaseXMLReader(reader);
 635     }
 636   }
 637 
 638   /**
 639    * Return the DTM object containing a representation of this node.
 640    *
 641    * @param nodeHandle DTM Handle indicating which node to retrieve
 642    *
 643    * @return a reference to the DTM object containing this node.
 644    */
 645   synchronized public DTM getDTM(int nodeHandle)
 646   {
 647     try
 648     {
 649       // Performance critical function.
 650       return m_dtms[nodeHandle >>> IDENT_DTM_NODE_BITS];
 651     }
 652     catch(java.lang.ArrayIndexOutOfBoundsException e)
 653     {
 654       if(nodeHandle==DTM.NULL)
 655                                 return null;            // Accept as a special case.
 656       else
 657                                 throw e;                // Programming error; want to know about it.
 658     }
 659   }
 660 
 661   /**
 662    * Given a DTM, find the ID number in the DTM tables which addresses
 663    * the start of the document. If overflow addressing is in use, other
 664    * DTM IDs may also be assigned to this DTM.
 665    *
 666    * @param dtm The DTM which (hopefully) contains this node.
 667    *
 668    * @return The DTM ID (as the high bits of a NodeHandle, not as our
 669    * internal index), or -1 if the DTM doesn't belong to this manager.
 670    */
 671   synchronized public int getDTMIdentity(DTM dtm)
 672   {
 673         // Shortcut using DTMDefaultBase's extension hooks
 674         // %REVIEW% Should the lookup be part of the basic DTM API?
 675         if(dtm instanceof DTMDefaultBase)
 676         {
 677                 DTMDefaultBase dtmdb=(DTMDefaultBase)dtm;
 678                 if(dtmdb.getManager()==this)
 679                         return dtmdb.getDTMIDs().elementAt(0);
 680                 else
 681                         return -1;
 682         }
 683 
 684     int n = m_dtms.length;
 685 
 686     for (int i = 0; i < n; i++)
 687     {
 688       DTM tdtm = m_dtms[i];
 689 
 690       if (tdtm == dtm && m_dtm_offsets[i]==0)
 691         return i << IDENT_DTM_NODE_BITS;
 692     }
 693 
 694     return -1;
 695   }
 696 
 697   /**
 698    * Release the DTMManager's reference(s) to a DTM, making it unmanaged.
 699    * This is typically done as part of returning the DTM to the heap after
 700    * we're done with it.
 701    *
 702    * @param dtm the DTM to be released.
 703    *
 704    * @param shouldHardDelete If false, this call is a suggestion rather than an
 705    * order, and we may not actually release the DTM. This is intended to
 706    * support intelligent caching of documents... which is not implemented
 707    * in this version of the DTM manager.
 708    *
 709    * @return true if the DTM was released, false if shouldHardDelete was set
 710    * and we decided not to.
 711    */
 712   synchronized public boolean release(DTM dtm, boolean shouldHardDelete)
 713   {
 714     if(DEBUG)
 715     {
 716       System.out.println("Releasing "+
 717                          (shouldHardDelete ? "HARD" : "soft")+
 718                          " dtm="+
 719                          // Following shouldn't need a nodeHandle, but does...
 720                          // and doesn't seem to report the intended value
 721                          dtm.getDocumentBaseURI()
 722                          );
 723     }
 724 
 725     if (dtm instanceof SAX2DTM)
 726     {
 727       ((SAX2DTM) dtm).clearCoRoutine();
 728     }
 729 
 730                 // Multiple DTM IDs may be assigned to a single DTM.
 731                 // The Right Answer is to ask which (if it supports
 732                 // extension, the DTM will need a list anyway). The
 733                 // Wrong Answer, applied if the DTM can't help us,
 734                 // is to linearly search them all; this may be very
 735                 // painful.
 736                 //
 737                 // %REVIEW% Should the lookup move up into the basic DTM API?
 738                 if(dtm instanceof DTMDefaultBase)
 739                 {
 740                         com.sun.org.apache.xml.internal.utils.SuballocatedIntVector ids=((DTMDefaultBase)dtm).getDTMIDs();
 741                         for(int i=ids.size()-1;i>=0;--i)
 742                                 m_dtms[ids.elementAt(i)>>>DTMManager.IDENT_DTM_NODE_BITS]=null;
 743                 }
 744                 else
 745                 {
 746                         int i = getDTMIdentity(dtm);
 747                     if (i >= 0)
 748                         {
 749                                 m_dtms[i >>> DTMManager.IDENT_DTM_NODE_BITS] = null;
 750                         }
 751                 }
 752 
 753     dtm.documentRelease();
 754     return true;
 755   }
 756 
 757   /**
 758    * Method createDocumentFragment
 759    *
 760    *
 761    * NEEDSDOC (createDocumentFragment) @return
 762    */
 763   synchronized public DTM createDocumentFragment()
 764   {
 765 
 766     try
 767     {
 768       DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(super.useServicesMechnism());
 769       dbf.setNamespaceAware(true);
 770 
 771       DocumentBuilder db = dbf.newDocumentBuilder();
 772       Document doc = db.newDocument();
 773       Node df = doc.createDocumentFragment();
 774 
 775       return getDTM(new DOMSource(df), true, null, false, false);
 776     }
 777     catch (Exception e)
 778     {
 779       throw new DTMException(e);
 780     }
 781   }
 782 
 783   /**
 784    * NEEDSDOC Method createDTMIterator
 785    *
 786    *
 787    * NEEDSDOC @param whatToShow
 788    * NEEDSDOC @param filter
 789    * NEEDSDOC @param entityReferenceExpansion
 790    *
 791    * NEEDSDOC (createDTMIterator) @return
 792    */
 793   synchronized public DTMIterator createDTMIterator(int whatToShow, DTMFilter filter,
 794                                        boolean entityReferenceExpansion)
 795   {
 796 
 797     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */
 798     return null;
 799   }
 800 
 801   /**
 802    * NEEDSDOC Method createDTMIterator
 803    *
 804    *
 805    * NEEDSDOC @param xpathString
 806    * NEEDSDOC @param presolver
 807    *
 808    * NEEDSDOC (createDTMIterator) @return
 809    */
 810   synchronized public DTMIterator createDTMIterator(String xpathString,
 811                                        PrefixResolver presolver)
 812   {
 813 
 814     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */
 815     return null;
 816   }
 817 
 818   /**
 819    * NEEDSDOC Method createDTMIterator
 820    *
 821    *
 822    * NEEDSDOC @param node
 823    *
 824    * NEEDSDOC (createDTMIterator) @return
 825    */
 826   synchronized public DTMIterator createDTMIterator(int node)
 827   {
 828 
 829     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */
 830     return null;
 831   }
 832 
 833   /**
 834    * NEEDSDOC Method createDTMIterator
 835    *
 836    *
 837    * NEEDSDOC @param xpathCompiler
 838    * NEEDSDOC @param pos
 839    *
 840    * NEEDSDOC (createDTMIterator) @return
 841    */
 842   synchronized public DTMIterator createDTMIterator(Object xpathCompiler, int pos)
 843   {
 844 
 845     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */
 846     return null;
 847   }
 848 
 849   /**
 850    * return the expanded name table.
 851    *
 852    * NEEDSDOC @param dtm
 853    *
 854    * NEEDSDOC ($objectName$) @return
 855    */
 856   public ExpandedNameTable getExpandedNameTable(DTM dtm)
 857   {
 858     return m_expandedNameTable;
 859   }
 860 }
   1 /*
   2  * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.

   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 


  21 package com.sun.org.apache.xml.internal.dtm.ref;
  22 
  23 import com.sun.org.apache.xalan.internal.utils.FactoryImpl;







  24 import com.sun.org.apache.xml.internal.dtm.DTM;
  25 import com.sun.org.apache.xml.internal.dtm.DTMException;
  26 import com.sun.org.apache.xml.internal.dtm.DTMFilter;
  27 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  28 import com.sun.org.apache.xml.internal.dtm.DTMManager;
  29 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  30 import com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTM;
  31 import com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTMdefaultNamespaceDeclarationNode;
  32 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM;
  33 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2RTFDTM;
  34 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
  35 import com.sun.org.apache.xml.internal.res.XMLMessages;
  36 import com.sun.org.apache.xml.internal.utils.PrefixResolver;
  37 import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
  38 import com.sun.org.apache.xml.internal.utils.WrappedRuntimeException;
  39 import com.sun.org.apache.xml.internal.utils.XMLReaderManager;
  40 import com.sun.org.apache.xml.internal.utils.XMLStringFactory;
  41 import javax.xml.parsers.DocumentBuilder;
  42 import javax.xml.parsers.DocumentBuilderFactory;
  43 import javax.xml.transform.Source;
  44 import javax.xml.transform.dom.DOMSource;
  45 import javax.xml.transform.sax.SAXSource;
  46 import javax.xml.transform.stream.StreamSource;
  47 import jdk.xml.internal.JdkXmlUtils;
  48 import org.w3c.dom.Document;
  49 import org.w3c.dom.Node;

  50 import org.xml.sax.InputSource;
  51 import org.xml.sax.SAXException;
  52 import org.xml.sax.SAXNotRecognizedException;
  53 import org.xml.sax.SAXNotSupportedException;
  54 import org.xml.sax.XMLReader;
  55 import org.xml.sax.helpers.DefaultHandler;
  56 
  57 /**
  58  * The default implementation for the DTMManager.
  59  *
  60  * %REVIEW% There is currently a reentrancy issue, since the finalizer
  61  * for XRTreeFrag (which runs in the GC thread) wants to call
  62  * DTMManager.release(), and may do so at the same time that the main
  63  * transformation thread is accessing the manager. Our current solution is
  64  * to make most of the manager's methods <code>synchronized</code>.
  65  * Early tests suggest that doing so is not causing a significant
  66  * performance hit in Xalan. However, it should be noted that there
  67  * is a possible alternative solution: rewrite release() so it merely
  68  * posts a request for release onto a threadsafe queue, and explicitly
  69  * process that queue on an infrequent basis during main-thread
  70  * activity (eg, when getDTM() is invoked). The downside of that solution
  71  * would be a greater delay before the DTM's storage is actually released
  72  * for reuse.
  73  * */
  74 public class DTMManagerDefault extends DTMManager {








  75 
  76   /**
  77    * Map from DTM identifier numbers to DTM objects that this manager manages.
  78    * One DTM may have several prefix numbers, if extended node indexing
  79    * is in use; in that case, m_dtm_offsets[] will used to control which
  80    * prefix maps to which section of the DTM.
  81    *
  82    * This array grows as necessary; see addDTM().
  83    *
  84    * This array grows as necessary; see addDTM(). Growth is uncommon... but
  85    * access needs to be blindingly fast since it's used in node addressing.
  86    */
  87   protected DTM m_dtms[] = new DTM[256];
  88 
  89   /** Map from DTM identifier numbers to offsets. For small DTMs with a
  90    * single identifier, this will always be 0. In overflow addressing, where
  91    * additional identifiers are allocated to access nodes beyond the range of
  92    * a single Node Handle, this table is used to map the handle's node field
  93    * into the actual node identifier.
  94    *


 103 
 104   /**
 105    * The cache for XMLReader objects to be used if the user did not
 106    * supply an XMLReader for a SAXSource or supplied a StreamSource.
 107    */
 108   protected XMLReaderManager m_readerManager = null;
 109 
 110   /**
 111    * The default implementation of ContentHandler, DTDHandler and ErrorHandler.
 112    */
 113   protected DefaultHandler m_defaultHandler = new DefaultHandler();
 114 
 115   /**
 116    * Add a DTM to the DTM table. This convenience call adds it as the
 117    * "base DTM ID", with offset 0. The other version of addDTM should
 118    * be used if you want to add "extended" DTM IDs with nonzero offsets.
 119    *
 120    * @param dtm Should be a valid reference to a DTM.
 121    * @param id Integer DTM ID to be bound to this DTM
 122    */
 123   synchronized public void addDTM(DTM dtm, int id) {
 124     addDTM(dtm,id,0);
 125   }
 126 
 127   /**
 128    * Add a DTM to the DTM table.
 129    *
 130    * @param dtm Should be a valid reference to a DTM.
 131    * @param id Integer DTM ID to be bound to this DTM.
 132    * @param offset Integer addressing offset. The internal DTM Node ID is
 133    * obtained by adding this offset to the node-number field of the
 134    * public DTM Handle. For the first DTM ID accessing each DTM, this is 0;
 135    * for overflow addressing it will be a multiple of 1<<IDENT_DTM_NODE_BITS.
 136    */
 137   synchronized public void addDTM(DTM dtm, int id, int offset) {
 138     if (id >= IDENT_MAX_DTMS) {
 139       // TODO: %REVIEW% Not really the right error message.
 140       throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_DTMIDS_AVAIL, null)); //"No more DTM IDs are available!");
 141     }
 142 
 143     // We used to just allocate the array size to IDENT_MAX_DTMS.
 144     // But we expect to increase that to 16 bits, and I'm not willing
 145     // to allocate that much space unless needed. We could use one of our
 146     // handy-dandy Fast*Vectors, but this will do for now.
 147     // %REVIEW%
 148     int oldlen = m_dtms.length;
 149     if(oldlen <= id) {
 150       // Various growth strategies are possible. I think we don't want
 151       // to over-allocate excessively, and I'm willing to reallocate
 152       // more often to get that. See also Fast*Vector classes.
 153       //
 154       // %REVIEW% Should throw a more diagnostic error if we go over the max...
 155       int newlen = Math.min((id+256),IDENT_MAX_DTMS);
 156       DTM new_m_dtms[] = new DTM[newlen];
 157       System.arraycopy(m_dtms,0,new_m_dtms,0,oldlen);
 158       m_dtms=new_m_dtms;
 159       int new_m_dtm_offsets[] = new int[newlen];
 160       System.arraycopy(m_dtm_offsets,0,new_m_dtm_offsets,0,oldlen);
 161       m_dtm_offsets=new_m_dtm_offsets;
 162     }




 163 
 164     m_dtms[id] = dtm;
 165     m_dtm_offsets[id]=offset;
 166     dtm.documentRegistration();
 167     // The DTM should have been told who its manager was when we created it.
 168     // Do we need to allow for adopting DTMs _not_ created by this manager?
 169   }
 170 
 171   /**
 172    * Get the first free DTM ID available. %OPT% Linear search is inefficient!
 173    */
 174   synchronized public int getFirstFreeDTMID() {

 175     int n = m_dtms.length;
 176     for (int i = 1; i < n; i++) {
 177       if(null == m_dtms[i]) {


 178         return i;
 179       }
 180     }
 181     return n; // count on addDTM() to throw exception if out of range
 182   }
 183 
 184   /**
 185    * The default table for exandedNameID lookups.
 186    */
 187   private ExpandedNameTable m_expandedNameTable = new ExpandedNameTable();

 188 
 189   /**
 190    * Constructor DTMManagerDefault
 191    *
 192    */
 193   public DTMManagerDefault() {}

 194 
 195   /**
 196    * Get an instance of a DTM, loaded with the content from the
 197    * specified source.  If the unique flag is true, a new instance will
 198    * always be returned.  Otherwise it is up to the DTMManager to return a
 199    * new instance or an instance that it already created and may be being used
 200    * by someone else.
 201    *
 202    * A bit of magic in this implementation: If the source is null, unique is true,
 203    * and incremental and doIndexing are both false, we return an instance of
 204    * SAX2RTFDTM, which see.
 205    *
 206    * (I think more parameters will need to be added for error handling, and entity
 207    * resolution, and more explicit control of the RTF situation).
 208    *
 209    * @param source the specification of the source object.
 210    * @param unique true if the returned DTM must be unique, probably because it
 211    * is going to be mutated.
 212    * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
 213    *                         be null.
 214    * @param incremental true if the DTM should be built incrementally, if
 215    *                    possible.
 216    * @param doIndexing true if the caller considers it worth it to use
 217    *                   indexing schemes.
 218    *
 219    * @return a non-null DTM reference.
 220    */
 221   synchronized public DTM getDTM(Source source, boolean unique,
 222                                  DTMWSFilter whiteSpaceFilter,
 223                                  boolean incremental, boolean doIndexing)
 224   {
 225     /* Uncomment for debugging
 226     if (null != source) {
 227       System.out.println("Starting " +
 228                          (unique ? "UNIQUE" : "shared") +
 229                          " source: " + source.getSystemId());
 230     }
 231     */
 232 
 233     XMLStringFactory xstringFactory = m_xsf;
 234     int dtmPos = getFirstFreeDTMID();
 235     int documentID = dtmPos << IDENT_DTM_NODE_BITS;
 236 
 237     if ((null != source) && source instanceof DOMSource) {

 238       DOM2DTM dtm = new DOM2DTM(this, (DOMSource) source, documentID,
 239                                 whiteSpaceFilter, xstringFactory, doIndexing);
 240 
 241       addDTM(dtm, dtmPos, 0);
 242 
 243       /* Uncomment for debugging
 244       dtm.dumpDTM();
 245       */

 246 
 247       return dtm;
 248     } else {
 249       boolean isSAXSource = (null != source) ? (source instanceof SAXSource) : true;
 250       boolean isStreamSource = (null != source) ? (source instanceof StreamSource) : false;




 251 
 252       if (isSAXSource || isStreamSource) {
 253         XMLReader reader = null;
 254         SAX2DTM dtm;
 255 
 256         try {
 257           InputSource xmlSource;
 258 
 259           if (null == source) {
 260             xmlSource = null;
 261           } else {
 262             reader = getXMLReader(source);
 263             xmlSource = SAXSource.sourceToInputSource(source);
 264 
 265             String urlOfSource = xmlSource.getSystemId();
 266 
 267             if (null != urlOfSource) {
 268               try {
 269                 urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource);
 270               } catch (Exception e) {
 271                 // %REVIEW% Is there a better way to send a warning?
 272                 System.err.println("Can not absolutize URL: " + urlOfSource);
 273               }
 274 
 275               xmlSource.setSystemId(urlOfSource);
 276             }
 277           }
 278 
 279           if (source==null && unique && !incremental && !doIndexing) {
 280             // Special case to support RTF construction into shared DTM.
 281             // It should actually still work for other uses,
 282             // but may be slightly deoptimized relative to the base
 283             // to allow it to deal with carrying multiple documents.
 284             //
 285             // %REVIEW% This is a sloppy way to request this mode;
 286             // we need to consider architectural improvements.
 287             dtm = new SAX2RTFDTM(this, source, documentID, whiteSpaceFilter,
 288                                  xstringFactory, doIndexing);
 289           } else {
 290             // Create the basic SAX2DTM.








 291             dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
 292                               xstringFactory, doIndexing);
 293           }
 294 
 295           // Go ahead and add the DTM to the lookup table.  This needs to be
 296           // done before any parsing occurs. Note offset 0, since we've just
 297           // created a new DTM.
 298           addDTM(dtm, dtmPos, 0);
 299 

 300           boolean haveXercesParser =
 301                      (null != reader)
 302                      && (reader.getClass()
 303                                .getName()
 304                                .equals("com.sun.org.apache.xerces.internal.parsers.SAXParser"));
 305 
 306           if (haveXercesParser) {
 307             incremental = true;  // No matter what.  %REVIEW%
 308           }
 309 
 310           // If the reader is null, but they still requested an incremental
 311           // build, then we still want to set up the IncrementalSAXSource stuff.
 312           if (m_incremental && incremental) {

 313             IncrementalSAXSource coParser=null;
 314 
 315             if (haveXercesParser) {
 316               // IncrementalSAXSource_Xerces to avoid threading.
 317               try {
 318                 coParser = new IncrementalSAXSource_Xerces();
 319               }  catch( Exception ex ) {
 320                 ex.printStackTrace();
 321                 coParser=null;
 322               }
 323             }
 324 
 325             if (coParser==null ) {
 326               // Create a IncrementalSAXSource to run on the secondary thread.
 327               if (null == reader) {
 328                 coParser = new IncrementalSAXSource_Filter();
 329               } else {
 330                 IncrementalSAXSource_Filter filter =
 331                          new IncrementalSAXSource_Filter();
 332                 filter.setXMLReader(reader);
 333                 coParser=filter;
 334               }
 335             }
 336 



















 337             // Have the DTM set itself up as IncrementalSAXSource's listener.
 338             dtm.setIncrementalSAXSource(coParser);
 339 
 340             if (null == xmlSource) {

 341               // Then the user will construct it themselves.
 342               return dtm;
 343             }
 344 
 345             if (null == reader.getErrorHandler()) {
 346               reader.setErrorHandler(dtm);
 347             }
 348             reader.setDTDHandler(dtm);
 349 
 350             try {
 351               // Launch parsing coroutine.  Launches a second thread,
 352               // if we're using IncrementalSAXSource.filter().
 353 
 354               coParser.startParse(xmlSource);
 355             } catch (RuntimeException re) {

 356               dtm.clearCoRoutine();

 357               throw re;
 358             } catch (Exception e) {

 359               dtm.clearCoRoutine();
 360               throw new WrappedRuntimeException(e);

 361             }
 362           } else {
 363             if (null == reader) {

 364               // Then the user will construct it themselves.
 365               return dtm;
 366             }
 367 
 368             // not incremental
 369             reader.setContentHandler(dtm);
 370             reader.setDTDHandler(dtm);
 371             if (null == reader.getErrorHandler()) {
 372               reader.setErrorHandler(dtm);
 373             }
 374 
 375             JdkXmlUtils.setXMLReaderPropertyIfSupport(reader,
 376                 "http://xml.org/sax/properties/lexical-handler", dtm, false);




 377 
 378             try {
 379               reader.parse(xmlSource);
 380             } catch (RuntimeException re) {
 381               dtm.clearCoRoutine();

 382               throw re;
 383             } catch (Exception e) {
 384               dtm.clearCoRoutine();
 385               throw new WrappedRuntimeException(e);

 386             }
 387           }
 388 
 389           /* Uncomment for debugging
 390           System.out.println("Dumping SAX2DOM");
 391           dtm.dumpDTM(System.err);
 392           */
 393 
 394           return dtm;
 395         } finally {
 396           // Reset the ContentHandler, DTDHandler, ErrorHandler to the DefaultHandler
 397           // after creating the DTM.
 398           if (reader != null && !(m_incremental && incremental)) {
 399             reader.setContentHandler(m_defaultHandler);
 400             reader.setDTDHandler(m_defaultHandler);
 401             reader.setErrorHandler(m_defaultHandler);
 402 
 403             // Reset the LexicalHandler to null after creating the DTM.
 404             try {
 405               reader.setProperty("http://xml.org/sax/properties/lexical-handler", null);
 406             }
 407             catch (Exception e) {}
 408           }
 409           releaseXMLReader(reader);
 410         }
 411       } else {

 412         // It should have been handled by a derived class or the caller
 413         // made a mistake.
 414         throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NOT_SUPPORTED, new Object[]{source})); //"Not supported: " + source);
 415       }
 416     }
 417   }
 418 
 419   /**
 420    * Given a W3C DOM node, try and return a DTM handle.
 421    * Note: calling this may be non-optimal, and there is no guarantee that
 422    * the node will be found in any particular DTM.
 423    *
 424    * @param node Non-null reference to a DOM node.
 425    *
 426    * @return a valid DTM handle.
 427    */
 428   synchronized public int getDTMHandleFromNode(Node node)
 429   {
 430     if (node == null) {
 431       throw new IllegalArgumentException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NODE_NON_NULL, null)); //"node must be non-null for getDTMHandleFromNode!");
 432     }
 433 
 434     if (node instanceof DTMNodeProxy) {
 435       return ((DTMNodeProxy)node).getDTMNodeNumber();
 436     } else {


 437       // Find the DOM2DTMs wrapped around this Document (if any)
 438       // and check whether they contain the Node in question.
 439       //
 440       // NOTE that since a DOM2DTM may represent a subtree rather
 441       // than a full document, we have to be prepared to check more
 442       // than one -- and there is no guarantee that we will find
 443       // one that contains ancestors or siblings of the node we're
 444       // seeking.
 445       //
 446       // %REVIEW% We could search for the one which contains this
 447       // node at the deepest level, and thus covers the widest
 448       // subtree, but that's going to entail additional work
 449       // checking more DTMs... and getHandleOfNode is not a
 450       // cheap operation in most implementations.
 451       //
 452       // TODO: %REVIEW% If overflow addressing, we may recheck a DTM
 453       // already examined. Ouch. But with the increased number of DTMs,
 454       // scanning back to check this is painful.
 455       // POSSIBLE SOLUTIONS:
 456       //   Generate a list of _unique_ DTM objects?
 457       //   Have each DTM cache last DOM node search?
 458       int max = m_dtms.length;
 459       for (int i = 0; i < max; i++) {
 460         DTM thisDTM = m_dtms[i];
 461         if ((null != thisDTM) && thisDTM instanceof DOM2DTM) {
 462           int handle=((DOM2DTM)thisDTM).getHandleOfNode(node);
 463           if (handle!=DTM.NULL) {
 464             return handle;

 465           }
 466         }
 467       }
 468 
 469       // Not found; generate a new DTM.
 470       //
 471       // %REVIEW% Is this really desirable, or should we return null
 472       // and make folks explicitly instantiate from a DOMSource? The
 473       // latter is more work but gives the caller the opportunity to
 474       // explicitly add the DTM to a DTMManager... and thus to know when
 475       // it can be discarded again, which is something we need to pay much
 476       // more attention to. (Especially since only DTMs which are assigned
 477       // to a manager can use the overflow addressing scheme.)
 478       //
 479       // %BUG% If the source node was a DOM2DTM$defaultNamespaceDeclarationNode
 480       // and the DTM wasn't registered with this DTMManager, we will create
 481       // a new DTM and _still_ not be able to find the node (since it will
 482       // be resynthesized). Another reason to push hard on making all DTMs
 483       // be managed DTMs.
 484 
 485       // Since the real root of our tree may be a DocumentFragment, we need to
 486       // use getParent to find the root, instead of getOwnerDocument.  Otherwise
 487       // DOM2DTM#getHandleOfNode will be very unhappy.
 488       Node root = node;
 489       Node p = (root.getNodeType() == Node.ATTRIBUTE_NODE) ? ((org.w3c.dom.Attr)root).getOwnerElement() : root.getParentNode();
 490       for (; p != null; p = p.getParentNode()) {

 491         root = p;
 492       }
 493 
 494       DOM2DTM dtm = (DOM2DTM) getDTM(new javax.xml.transform.dom.DOMSource(root), false, null, true, true);

 495 
 496       int handle;
 497 
 498       if (node instanceof DOM2DTMdefaultNamespaceDeclarationNode) {
 499         // Can't return the same node since it's unique to a specific DTM,
 500         // but can return the equivalent node -- find the corresponding
 501         // Document Element, then ask it for the xml: namespace decl.
 502         handle = dtm.getHandleOfNode(((org.w3c.dom.Attr)node).getOwnerElement());
 503         handle = dtm.getAttributeNode(handle, node.getNamespaceURI(), node.getLocalName());
 504       } else {
 505         handle = ((DOM2DTM)dtm).getHandleOfNode(node);
 506       }


 507 
 508       if (DTM.NULL == handle) {
 509         throw new RuntimeException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COULD_NOT_RESOLVE_NODE, null)); //"Could not resolve the node to a handle!");
 510       }
 511 
 512       return handle;
 513     }
 514   }
 515 
 516   /**
 517    * This method returns the SAX2 parser to use with the InputSource
 518    * obtained from this URI.
 519    * It may return null if any SAX2-conformant XML parser can be used,
 520    * or if getInputSource() will also return null. The parser must
 521    * be free for use (i.e., not currently in use for another parse().
 522    * After use of the parser is completed, the releaseXMLReader(XMLReader)
 523    * must be called.
 524    *
 525    * @param inputSource The value returned from the URIResolver.
 526    * @return  a SAX2 XMLReader to use to resolve the inputSource argument.
 527    *
 528    * @return non-null XMLReader reference ready to parse.
 529    */
 530   synchronized public XMLReader getXMLReader(Source inputSource) {
 531     try {



 532       XMLReader reader = (inputSource instanceof SAXSource)
 533                          ? ((SAXSource) inputSource).getXMLReader() : null;
 534 
 535       // If user did not supply a reader, ask for one from the reader manager
 536       if (null == reader) {
 537         if (m_readerManager == null) {
 538             m_readerManager = XMLReaderManager.getInstance(super.useServicesMechnism());
 539         }
 540 
 541         reader = m_readerManager.getXMLReader();
 542       }
 543 
 544       return reader;

 545     } catch (SAXException se) {
 546       throw new DTMException(se.getMessage(), se);
 547     }
 548   }
 549 
 550   /**
 551    * Indicates that the XMLReader object is no longer in use for the transform.
 552    *
 553    * Note that the getXMLReader method may return an XMLReader that was
 554    * specified on the SAXSource object by the application code.  Such a
 555    * reader should still be passed to releaseXMLReader, but the reader manager
 556    * will only re-use XMLReaders that it created.
 557    *
 558    * @param reader The XMLReader to be released.
 559    */
 560   synchronized public void releaseXMLReader(XMLReader reader) {
 561     if (m_readerManager != null) {
 562       m_readerManager.releaseXMLReader(reader);
 563     }
 564   }
 565 
 566   /**
 567    * Return the DTM object containing a representation of this node.
 568    *
 569    * @param nodeHandle DTM Handle indicating which node to retrieve
 570    *
 571    * @return a reference to the DTM object containing this node.
 572    */
 573   synchronized public DTM getDTM(int nodeHandle) {
 574     try {


 575       // Performance critical function.
 576       return m_dtms[nodeHandle >>> IDENT_DTM_NODE_BITS];
 577     } catch(java.lang.ArrayIndexOutOfBoundsException e) {
 578       if (nodeHandle==DTM.NULL)
 579         return null;            // Accept as a special case.


 580       else
 581         throw e;                // Programming error; want to know about it.
 582     }
 583   }
 584 
 585   /**
 586    * Given a DTM, find the ID number in the DTM tables which addresses
 587    * the start of the document. If overflow addressing is in use, other
 588    * DTM IDs may also be assigned to this DTM.
 589    *
 590    * @param dtm The DTM which (hopefully) contains this node.
 591    *
 592    * @return The DTM ID (as the high bits of a NodeHandle, not as our
 593    * internal index), or -1 if the DTM doesn't belong to this manager.
 594    */
 595   synchronized public int getDTMIdentity(DTM dtm) {
 596     // Shortcut using DTMDefaultBase's extension hooks
 597     // %REVIEW% Should the lookup be part of the basic DTM API?
 598     if (dtm instanceof DTMDefaultBase) {
 599       DTMDefaultBase dtmdb = (DTMDefaultBase)dtm;
 600       if (dtmdb.getManager() == this)
 601         return dtmdb.getDTMIDs().elementAt(0);
 602       else
 603         return -1;
 604     }


 605 
 606     int n = m_dtms.length;
 607 
 608     for (int i = 0; i < n; i++) {

 609       DTM tdtm = m_dtms[i];
 610 
 611       if (tdtm == dtm && m_dtm_offsets[i]==0)
 612         return i << IDENT_DTM_NODE_BITS;
 613     }
 614 
 615     return -1;
 616   }
 617 
 618   /**
 619    * Release the DTMManager's reference(s) to a DTM, making it unmanaged.
 620    * This is typically done as part of returning the DTM to the heap after
 621    * we're done with it.
 622    *
 623    * @param dtm the DTM to be released.
 624    *
 625    * @param shouldHardDelete If false, this call is a suggestion rather than an
 626    * order, and we may not actually release the DTM. This is intended to
 627    * support intelligent caching of documents... which is not implemented
 628    * in this version of the DTM manager.
 629    *
 630    * @return true if the DTM was released, false if shouldHardDelete was set
 631    * and we decided not to.
 632    */
 633   synchronized public boolean release(DTM dtm, boolean shouldHardDelete) {
 634     /* Uncomment for debugging
 635     System.out.println("Releasing "+
 636                        (shouldHardDelete ? "HARD" : "soft") +
 637                        " dtm=" +
 638                        // Following shouldn't need a nodeHandle, but does...
 639                        // and doesn't seem to report the intended value
 640                        dtm.getDocumentBaseURI());
 641     */
 642 
 643     if (dtm instanceof SAX2DTM) {
 644       ((SAX2DTM)dtm).clearCoRoutine();
 645     }
 646 
 647     // Multiple DTM IDs may be assigned to a single DTM.
 648     // The Right Answer is to ask which (if it supports
 649     // extension, the DTM will need a list anyway). The
 650     // Wrong Answer, applied if the DTM can't help us,
 651     // is to linearly search them all; this may be very
 652     // painful.
 653     //
 654     // %REVIEW% Should the lookup move up into the basic DTM API?
 655     if (dtm instanceof DTMDefaultBase) {
 656       com.sun.org.apache.xml.internal.utils.SuballocatedIntVector ids=((DTMDefaultBase)dtm).getDTMIDs();
 657       for (int i=ids.size() - 1; i >= 0; --i) {
 658         m_dtms[ids.elementAt(i)>>>DTMManager.IDENT_DTM_NODE_BITS] = null;
 659       }
 660     } else {
 661       int i = getDTMIdentity(dtm);
 662       if (i >= 0) {
 663         m_dtms[i >>> DTMManager.IDENT_DTM_NODE_BITS] = null;
 664       }
 665     }







 666 
 667     dtm.documentRelease();
 668     return true;
 669   }
 670 
 671   /**
 672    * Method createDocumentFragment
 673    *
 674    *
 675    * NEEDSDOC (createDocumentFragment) @return
 676    */
 677   synchronized public DTM createDocumentFragment() {
 678     try {



 679       DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(super.useServicesMechnism());
 680       dbf.setNamespaceAware(true);
 681 
 682       DocumentBuilder db = dbf.newDocumentBuilder();
 683       Document doc = db.newDocument();
 684       Node df = doc.createDocumentFragment();
 685 
 686       return getDTM(new DOMSource(df), true, null, false, false);
 687     } catch (Exception e) {


 688       throw new DTMException(e);
 689     }
 690   }
 691 
 692   /**
 693    * NEEDSDOC Method createDTMIterator
 694    *
 695    *
 696    * NEEDSDOC @param whatToShow
 697    * NEEDSDOC @param filter
 698    * NEEDSDOC @param entityReferenceExpansion
 699    *
 700    * NEEDSDOC (createDTMIterator) @return
 701    */
 702   synchronized public DTMIterator createDTMIterator(int whatToShow, DTMFilter filter,
 703                                        boolean entityReferenceExpansion) {


 704     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */
 705     return null;
 706   }
 707 
 708   /**
 709    * NEEDSDOC Method createDTMIterator
 710    *
 711    *
 712    * NEEDSDOC @param xpathString
 713    * NEEDSDOC @param presolver
 714    *
 715    * NEEDSDOC (createDTMIterator) @return
 716    */
 717   synchronized public DTMIterator createDTMIterator(String xpathString,
 718                                        PrefixResolver presolver) {


 719     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */
 720     return null;
 721   }
 722 
 723   /**
 724    * NEEDSDOC Method createDTMIterator
 725    *
 726    *
 727    * NEEDSDOC @param node
 728    *
 729    * NEEDSDOC (createDTMIterator) @return
 730    */
 731   synchronized public DTMIterator createDTMIterator(int node) {


 732     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */
 733     return null;
 734   }
 735 
 736   /**
 737    * NEEDSDOC Method createDTMIterator
 738    *
 739    *
 740    * NEEDSDOC @param xpathCompiler
 741    * NEEDSDOC @param pos
 742    *
 743    * NEEDSDOC (createDTMIterator) @return
 744    */
 745   synchronized public DTMIterator createDTMIterator(Object xpathCompiler, int pos) {


 746     /** @todo: implement this com.sun.org.apache.xml.internal.dtm.DTMManager abstract method */
 747     return null;
 748   }
 749 
 750   /**
 751    * return the expanded name table.
 752    *
 753    * NEEDSDOC @param dtm
 754    *
 755    * NEEDSDOC ($objectName$) @return
 756    */
 757   public ExpandedNameTable getExpandedNameTable(DTM dtm) {

 758     return m_expandedNameTable;
 759   }
 760 }
< prev index next >