~vcs-imports/xena/trunk

« back to all changes in this revision

Viewing changes to ext/src/xalan-j_2_7_1/src/org/apache/xml/dtm/ref/DTMManagerDefault.java

  • Committer: matthewoliver
  • Date: 2009-12-10 03:18:07 UTC
  • Revision ID: vcs-imports@canonical.com-20091210031807-l086qguzdlljtkl9
Merged Xena Testing into Xena Stable for the Xena 5 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Licensed to the Apache Software Foundation (ASF) under one
 
3
 * or more contributor license agreements. See the NOTICE file
 
4
 * distributed with this work for additional information
 
5
 * regarding copyright ownership. The ASF licenses this file
 
6
 * to you under the Apache License, Version 2.0 (the  "License");
 
7
 * you may not use this file except in compliance with the License.
 
8
 * You may obtain a copy of the License at
 
9
 *
 
10
 *     http://www.apache.org/licenses/LICENSE-2.0
 
11
 *
 
12
 * Unless required by applicable law or agreed to in writing, software
 
13
 * distributed under the License is distributed on an "AS IS" BASIS,
 
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
15
 * See the License for the specific language governing permissions and
 
16
 * limitations under the License.
 
17
 */
 
18
/*
 
19
 * $Id: DTMManagerDefault.java,v 1.2 2009/12/10 03:18:39 matthewoliver Exp $
 
20
 */
 
21
package org.apache.xml.dtm.ref;
 
22
 
 
23
import javax.xml.parsers.DocumentBuilder;
 
24
import javax.xml.parsers.DocumentBuilderFactory;
 
25
import javax.xml.transform.Source;
 
26
import javax.xml.transform.dom.DOMSource;
 
27
import javax.xml.transform.sax.SAXSource;
 
28
import javax.xml.transform.stream.StreamSource;
 
29
 
 
30
import org.apache.xml.dtm.DTM;
 
31
import org.apache.xml.dtm.DTMException;
 
32
import org.apache.xml.dtm.DTMFilter;
 
33
import org.apache.xml.dtm.DTMIterator;
 
34
import org.apache.xml.dtm.DTMManager;
 
35
import org.apache.xml.dtm.DTMWSFilter;
 
36
import org.apache.xml.dtm.ref.dom2dtm.DOM2DTM;
 
37
import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM;
 
38
import org.apache.xml.dtm.ref.sax2dtm.SAX2RTFDTM;
 
39
import org.apache.xml.res.XMLErrorResources;
 
40
import org.apache.xml.res.XMLMessages;
 
41
import org.apache.xml.utils.PrefixResolver;
 
42
import org.apache.xml.utils.SystemIDResolver;
 
43
import org.apache.xml.utils.XMLReaderManager;
 
44
import org.apache.xml.utils.XMLStringFactory;
 
45
 
 
46
import org.w3c.dom.Document;
 
47
import org.w3c.dom.Node;
 
48
 
 
49
import org.xml.sax.InputSource;
 
50
import org.xml.sax.SAXException;
 
51
import org.xml.sax.SAXNotRecognizedException;
 
52
import org.xml.sax.SAXNotSupportedException;
 
53
import org.xml.sax.XMLReader;
 
54
import org.xml.sax.helpers.DefaultHandler;
 
55
 
 
56
/**
 
57
 * The default implementation for the DTMManager.
 
58
 *
 
59
 * %REVIEW% There is currently a reentrancy issue, since the finalizer
 
60
 * for XRTreeFrag (which runs in the GC thread) wants to call
 
61
 * DTMManager.release(), and may do so at the same time that the main
 
62
 * transformation thread is accessing the manager. Our current solution is
 
63
 * to make most of the manager's methods <code>synchronized</code>.
 
64
 * Early tests suggest that doing so is not causing a significant
 
65
 * performance hit in Xalan. However, it should be noted that there
 
66
 * is a possible alternative solution: rewrite release() so it merely
 
67
 * posts a request for release onto a threadsafe queue, and explicitly
 
68
 * process that queue on an infrequent basis during main-thread
 
69
 * activity (eg, when getDTM() is invoked). The downside of that solution
 
70
 * would be a greater delay before the DTM's storage is actually released
 
71
 * for reuse.
 
72
 * */
 
73
public class DTMManagerDefault extends DTMManager
 
74
{
 
75
  //static final boolean JKESS_XNI_EXPERIMENT=true;
 
76
 
 
77
  /** Set this to true if you want a dump of the DTM after creation. */
 
78
  private static final boolean DUMPTREE = false;
 
79
 
 
80
  /** Set this to true if you want a basic diagnostics. */
 
81
  private static final boolean DEBUG = false;
 
82
 
 
83
  /**
 
84
   * Map from DTM identifier numbers to DTM objects that this manager manages.
 
85
   * One DTM may have several prefix numbers, if extended node indexing
 
86
   * is in use; in that case, m_dtm_offsets[] will used to control which
 
87
   * prefix maps to which section of the DTM.
 
88
   * 
 
89
   * This array grows as necessary; see addDTM().
 
90
   * 
 
91
   * This array grows as necessary; see addDTM(). Growth is uncommon... but
 
92
   * access needs to be blindingly fast since it's used in node addressing.
 
93
   */
 
94
  protected DTM m_dtms[] = new DTM[256];
 
95
        
 
96
  /** Map from DTM identifier numbers to offsets. For small DTMs with a 
 
97
   * single identifier, this will always be 0. In overflow addressing, where
 
98
   * additional identifiers are allocated to access nodes beyond the range of
 
99
   * a single Node Handle, this table is used to map the handle's node field
 
100
   * into the actual node identifier.
 
101
   * 
 
102
   * This array grows as necessary; see addDTM().
 
103
   * 
 
104
   * This array grows as necessary; see addDTM(). Growth is uncommon... but
 
105
   * access needs to be blindingly fast since it's used in node addressing.
 
106
   * (And at the moment, that includes accessing it from DTMDefaultBase,
 
107
   * which is why this is not Protected or Private.)
 
108
   */
 
109
  int m_dtm_offsets[] = new int[256];
 
110
 
 
111
  /**
 
112
   * The cache for XMLReader objects to be used if the user did not
 
113
   * supply an XMLReader for a SAXSource or supplied a StreamSource.
 
114
   */
 
115
  protected XMLReaderManager m_readerManager = null;
 
116
  
 
117
  /**
 
118
   * The default implementation of ContentHandler, DTDHandler and ErrorHandler.
 
119
   */
 
120
  protected DefaultHandler m_defaultHandler = new DefaultHandler();
 
121
 
 
122
  /**
 
123
   * Add a DTM to the DTM table. This convenience call adds it as the 
 
124
   * "base DTM ID", with offset 0. The other version of addDTM should 
 
125
   * be used if you want to add "extended" DTM IDs with nonzero offsets.
 
126
   *
 
127
   * @param dtm Should be a valid reference to a DTM.
 
128
   * @param id Integer DTM ID to be bound to this DTM
 
129
   */
 
130
  synchronized public void addDTM(DTM dtm, int id) {    addDTM(dtm,id,0); }
 
131
 
 
132
        
 
133
  /**
 
134
   * Add a DTM to the DTM table.
 
135
   *
 
136
   * @param dtm Should be a valid reference to a DTM.
 
137
   * @param id Integer DTM ID to be bound to this DTM.
 
138
   * @param offset Integer addressing offset. The internal DTM Node ID is
 
139
   * obtained by adding this offset to the node-number field of the 
 
140
   * public DTM Handle. For the first DTM ID accessing each DTM, this is 0;
 
141
   * for overflow addressing it will be a multiple of 1<<IDENT_DTM_NODE_BITS.
 
142
   */
 
143
  synchronized public void addDTM(DTM dtm, int id, int offset)
 
144
  {
 
145
                if(id>=IDENT_MAX_DTMS)
 
146
                {
 
147
                        // TODO: %REVIEW% Not really the right error message.
 
148
            throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_DTMIDS_AVAIL, null)); //"No more DTM IDs are available!");                       
 
149
                }
 
150
                
 
151
                // We used to just allocate the array size to IDENT_MAX_DTMS.
 
152
                // But we expect to increase that to 16 bits, and I'm not willing
 
153
                // to allocate that much space unless needed. We could use one of our
 
154
                // handy-dandy Fast*Vectors, but this will do for now.
 
155
                // %REVIEW%
 
156
                int oldlen=m_dtms.length;
 
157
                if(oldlen<=id)
 
158
                {
 
159
                        // Various growth strategies are possible. I think we don't want 
 
160
                        // to over-allocate excessively, and I'm willing to reallocate
 
161
                        // more often to get that. See also Fast*Vector classes.
 
162
                        //
 
163
                        // %REVIEW% Should throw a more diagnostic error if we go over the max...
 
164
                        int newlen=Math.min((id+256),IDENT_MAX_DTMS);
 
165
 
 
166
                        DTM new_m_dtms[] = new DTM[newlen];
 
167
                        System.arraycopy(m_dtms,0,new_m_dtms,0,oldlen);
 
168
                        m_dtms=new_m_dtms;
 
169
                        int new_m_dtm_offsets[] = new int[newlen];
 
170
                        System.arraycopy(m_dtm_offsets,0,new_m_dtm_offsets,0,oldlen);
 
171
                        m_dtm_offsets=new_m_dtm_offsets;
 
172
                }
 
173
                
 
174
    m_dtms[id] = dtm;
 
175
                m_dtm_offsets[id]=offset;
 
176
    dtm.documentRegistration();
 
177
                // The DTM should have been told who its manager was when we created it.
 
178
                // Do we need to allow for adopting DTMs _not_ created by this manager?
 
179
  }
 
180
 
 
181
  /**
 
182
   * Get the first free DTM ID available. %OPT% Linear search is inefficient!
 
183
   */
 
184
  synchronized public int getFirstFreeDTMID()
 
185
  {
 
186
    int n = m_dtms.length;
 
187
    for (int i = 1; i < n; i++)
 
188
    {
 
189
      if(null == m_dtms[i])
 
190
      {
 
191
        return i;
 
192
      }
 
193
    }
 
194
                return n; // count on addDTM() to throw exception if out of range
 
195
  }
 
196
 
 
197
  /**
 
198
   * The default table for exandedNameID lookups.
 
199
   */
 
200
  private ExpandedNameTable m_expandedNameTable =
 
201
    new ExpandedNameTable();
 
202
 
 
203
  /**
 
204
   * Constructor DTMManagerDefault
 
205
   *
 
206
   */
 
207
  public DTMManagerDefault(){}
 
208
 
 
209
 
 
210
  /**
 
211
   * Get an instance of a DTM, loaded with the content from the
 
212
   * specified source.  If the unique flag is true, a new instance will
 
213
   * always be returned.  Otherwise it is up to the DTMManager to return a
 
214
   * new instance or an instance that it already created and may be being used
 
215
   * by someone else.
 
216
   * 
 
217
   * A bit of magic in this implementation: If the source is null, unique is true,
 
218
   * and incremental and doIndexing are both false, we return an instance of
 
219
   * SAX2RTFDTM, which see.
 
220
   * 
 
221
   * (I think more parameters will need to be added for error handling, and entity
 
222
   * resolution, and more explicit control of the RTF situation).
 
223
   *
 
224
   * @param source the specification of the source object.
 
225
   * @param unique true if the returned DTM must be unique, probably because it
 
226
   * is going to be mutated.
 
227
   * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
 
228
   *                         be null.
 
229
   * @param incremental true if the DTM should be built incrementally, if
 
230
   *                    possible.
 
231
   * @param doIndexing true if the caller considers it worth it to use
 
232
   *                   indexing schemes.
 
233
   *
 
234
   * @return a non-null DTM reference.
 
235
   */
 
236
  synchronized public DTM getDTM(Source source, boolean unique,
 
237
                                 DTMWSFilter whiteSpaceFilter,
 
238
                                 boolean incremental, boolean doIndexing)
 
239
  {
 
240
 
 
241
    if(DEBUG && null != source)
 
242
      System.out.println("Starting "+
 
243
                         (unique ? "UNIQUE" : "shared")+
 
244
                         " source: "+source.getSystemId()
 
245
                         );
 
246
 
 
247
    XMLStringFactory xstringFactory = m_xsf;
 
248
    int dtmPos = getFirstFreeDTMID();
 
249
    int documentID = dtmPos << IDENT_DTM_NODE_BITS;
 
250
 
 
251
    if ((null != source) && source instanceof DOMSource)
 
252
    {
 
253
      DOM2DTM dtm = new DOM2DTM(this, (DOMSource) source, documentID,
 
254
                                whiteSpaceFilter, xstringFactory, doIndexing);
 
255
 
 
256
      addDTM(dtm, dtmPos, 0);
 
257
 
 
258
      //      if (DUMPTREE)
 
259
      //      {
 
260
      //        dtm.dumpDTM();
 
261
      //      }
 
262
 
 
263
      return dtm;
 
264
    }
 
265
    else
 
266
    {
 
267
      boolean isSAXSource = (null != source)
 
268
        ? (source instanceof SAXSource) : true;
 
269
      boolean isStreamSource = (null != source)
 
270
        ? (source instanceof StreamSource) : false;
 
271
 
 
272
      if (isSAXSource || isStreamSource) {
 
273
        XMLReader reader = null;
 
274
        SAX2DTM dtm;
 
275
 
 
276
        try {
 
277
          InputSource xmlSource;
 
278
 
 
279
          if (null == source) {
 
280
            xmlSource = null;
 
281
          } else {
 
282
            reader = getXMLReader(source);
 
283
            xmlSource = SAXSource.sourceToInputSource(source);
 
284
 
 
285
            String urlOfSource = xmlSource.getSystemId();
 
286
 
 
287
            if (null != urlOfSource) {
 
288
              try {
 
289
                urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource);
 
290
              } catch (Exception e) {
 
291
                // %REVIEW% Is there a better way to send a warning?
 
292
                System.err.println("Can not absolutize URL: " + urlOfSource);
 
293
              }
 
294
 
 
295
              xmlSource.setSystemId(urlOfSource);
 
296
            }
 
297
          }
 
298
 
 
299
          if (source==null && unique && !incremental && !doIndexing) {
 
300
            // Special case to support RTF construction into shared DTM.
 
301
            // It should actually still work for other uses,
 
302
            // but may be slightly deoptimized relative to the base
 
303
            // to allow it to deal with carrying multiple documents.
 
304
            //
 
305
            // %REVIEW% This is a sloppy way to request this mode;
 
306
            // we need to consider architectural improvements.
 
307
            dtm = new SAX2RTFDTM(this, source, documentID, whiteSpaceFilter,
 
308
                                 xstringFactory, doIndexing);
 
309
          }
 
310
          /**************************************************************
 
311
          // EXPERIMENTAL 3/22/02
 
312
          else if(JKESS_XNI_EXPERIMENT && m_incremental) {              
 
313
            dtm = new XNI2DTM(this, source, documentID, whiteSpaceFilter,
 
314
                              xstringFactory, doIndexing);
 
315
          }
 
316
          **************************************************************/
 
317
          // Create the basic SAX2DTM.
 
318
          else {
 
319
            dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
 
320
                              xstringFactory, doIndexing);
 
321
          }
 
322
 
 
323
          // Go ahead and add the DTM to the lookup table.  This needs to be
 
324
          // done before any parsing occurs. Note offset 0, since we've just
 
325
          // created a new DTM.
 
326
          addDTM(dtm, dtmPos, 0);
 
327
 
 
328
 
 
329
          boolean haveXercesParser =
 
330
                     (null != reader)
 
331
                     && (reader.getClass()
 
332
                               .getName()
 
333
                               .equals("org.apache.xerces.parsers.SAXParser") );
 
334
        
 
335
          if (haveXercesParser) {
 
336
            incremental = true;  // No matter what.  %REVIEW%
 
337
          }
 
338
        
 
339
          // If the reader is null, but they still requested an incremental
 
340
          // build, then we still want to set up the IncrementalSAXSource stuff.
 
341
          if (m_incremental && incremental
 
342
               /* || ((null == reader) && incremental) */) {
 
343
            IncrementalSAXSource coParser=null;
 
344
 
 
345
            if (haveXercesParser) {
 
346
              // IncrementalSAXSource_Xerces to avoid threading.
 
347
              try {
 
348
                coParser =(IncrementalSAXSource)
 
349
                  Class.forName("org.apache.xml.dtm.ref.IncrementalSAXSource_Xerces").newInstance();  
 
350
              }  catch( Exception ex ) {
 
351
                ex.printStackTrace();
 
352
                coParser=null;
 
353
              }
 
354
            }
 
355
 
 
356
            if (coParser==null ) {
 
357
              // Create a IncrementalSAXSource to run on the secondary thread.
 
358
              if (null == reader) {
 
359
                coParser = new IncrementalSAXSource_Filter();
 
360
              } else {
 
361
                IncrementalSAXSource_Filter filter =
 
362
                         new IncrementalSAXSource_Filter();
 
363
                filter.setXMLReader(reader);
 
364
                coParser=filter;
 
365
              }
 
366
            }
 
367
 
 
368
                        
 
369
            /**************************************************************
 
370
            // EXPERIMENTAL 3/22/02
 
371
            if (JKESS_XNI_EXPERIMENT && m_incremental &&
 
372
                  dtm instanceof XNI2DTM && 
 
373
                  coParser instanceof IncrementalSAXSource_Xerces) {
 
374
                org.apache.xerces.xni.parser.XMLPullParserConfiguration xpc=
 
375
                      ((IncrementalSAXSource_Xerces)coParser)
 
376
                                           .getXNIParserConfiguration();
 
377
              if (xpc!=null) {
 
378
                // Bypass SAX; listen to the XNI stream
 
379
                ((XNI2DTM)dtm).setIncrementalXNISource(xpc);
 
380
              } else {
 
381
                  // Listen to the SAX stream (will fail, diagnostically...)
 
382
                dtm.setIncrementalSAXSource(coParser);
 
383
              }
 
384
            } else
 
385
            ***************************************************************/
 
386
          
 
387
            // Have the DTM set itself up as IncrementalSAXSource's listener.
 
388
            dtm.setIncrementalSAXSource(coParser);
 
389
 
 
390
            if (null == xmlSource) {
 
391
 
 
392
              // Then the user will construct it themselves.
 
393
              return dtm;
 
394
            }
 
395
 
 
396
            if (null == reader.getErrorHandler()) {
 
397
              reader.setErrorHandler(dtm);
 
398
            }
 
399
            reader.setDTDHandler(dtm);
 
400
 
 
401
            try {
 
402
              // Launch parsing coroutine.  Launches a second thread,
 
403
              // if we're using IncrementalSAXSource.filter().
 
404
 
 
405
              coParser.startParse(xmlSource);
 
406
            } catch (RuntimeException re) {
 
407
 
 
408
              dtm.clearCoRoutine();
 
409
 
 
410
              throw re;
 
411
            } catch (Exception e) {
 
412
 
 
413
              dtm.clearCoRoutine();
 
414
 
 
415
              throw new org.apache.xml.utils.WrappedRuntimeException(e);
 
416
            }
 
417
          } else {
 
418
            if (null == reader) {
 
419
 
 
420
              // Then the user will construct it themselves.
 
421
              return dtm;
 
422
            }
 
423
 
 
424
            // not incremental
 
425
            reader.setContentHandler(dtm);
 
426
            reader.setDTDHandler(dtm);
 
427
            if (null == reader.getErrorHandler()) {
 
428
              reader.setErrorHandler(dtm);
 
429
            }
 
430
 
 
431
            try {
 
432
              reader.setProperty(
 
433
                               "http://xml.org/sax/properties/lexical-handler",
 
434
                               dtm);
 
435
            } catch (SAXNotRecognizedException e){}
 
436
              catch (SAXNotSupportedException e){}
 
437
 
 
438
            try {
 
439
              reader.parse(xmlSource);
 
440
            } catch (RuntimeException re) {
 
441
              dtm.clearCoRoutine();
 
442
 
 
443
              throw re;
 
444
            } catch (Exception e) {
 
445
              dtm.clearCoRoutine();
 
446
 
 
447
              throw new org.apache.xml.utils.WrappedRuntimeException(e);
 
448
            }
 
449
          }
 
450
 
 
451
          if (DUMPTREE) {
 
452
            System.out.println("Dumping SAX2DOM");
 
453
            dtm.dumpDTM(System.err);
 
454
          }
 
455
 
 
456
          return dtm;
 
457
        } finally {
 
458
          // Reset the ContentHandler, DTDHandler, ErrorHandler to the DefaultHandler
 
459
          // after creating the DTM.
 
460
          if (reader != null && !(m_incremental && incremental)) {
 
461
            reader.setContentHandler(m_defaultHandler);
 
462
            reader.setDTDHandler(m_defaultHandler);
 
463
            reader.setErrorHandler(m_defaultHandler);
 
464
            
 
465
            // Reset the LexicalHandler to null after creating the DTM.
 
466
            try {
 
467
              reader.setProperty("http://xml.org/sax/properties/lexical-handler", null);
 
468
            }
 
469
            catch (Exception e) {}
 
470
          }
 
471
          releaseXMLReader(reader);
 
472
        }
 
473
      } else {
 
474
 
 
475
        // It should have been handled by a derived class or the caller
 
476
        // made a mistake.
 
477
        throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NOT_SUPPORTED, new Object[]{source})); //"Not supported: " + source);
 
478
      }
 
479
    }
 
480
  }
 
481
 
 
482
  /**
 
483
   * Given a W3C DOM node, try and return a DTM handle.
 
484
   * Note: calling this may be non-optimal, and there is no guarantee that
 
485
   * the node will be found in any particular DTM.
 
486
   *
 
487
   * @param node Non-null reference to a DOM node.
 
488
   *
 
489
   * @return a valid DTM handle.
 
490
   */
 
491
  synchronized public int getDTMHandleFromNode(org.w3c.dom.Node node)
 
492
  {
 
493
    if(null == node)
 
494
      throw new IllegalArgumentException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NODE_NON_NULL, null)); //"node must be non-null for getDTMHandleFromNode!");
 
495
 
 
496
    if (node instanceof org.apache.xml.dtm.ref.DTMNodeProxy)
 
497
      return ((org.apache.xml.dtm.ref.DTMNodeProxy) node).getDTMNodeNumber();
 
498
                
 
499
    else
 
500
    {
 
501
      // Find the DOM2DTMs wrapped around this Document (if any)
 
502
      // and check whether they contain the Node in question.
 
503
      //
 
504
      // NOTE that since a DOM2DTM may represent a subtree rather
 
505
      // than a full document, we have to be prepared to check more
 
506
      // than one -- and there is no guarantee that we will find
 
507
      // one that contains ancestors or siblings of the node we're
 
508
      // seeking.
 
509
      //
 
510
      // %REVIEW% We could search for the one which contains this
 
511
      // node at the deepest level, and thus covers the widest
 
512
      // subtree, but that's going to entail additional work
 
513
      // checking more DTMs... and getHandleOfNode is not a
 
514
      // cheap operation in most implementations.
 
515
                        //
 
516
                        // TODO: %REVIEW% If overflow addressing, we may recheck a DTM
 
517
                        // already examined. Ouch. But with the increased number of DTMs,
 
518
                        // scanning back to check this is painful. 
 
519
                        // POSSIBLE SOLUTIONS: 
 
520
                        //   Generate a list of _unique_ DTM objects?
 
521
                        //   Have each DTM cache last DOM node search?
 
522
                        int max = m_dtms.length;
 
523
      for(int i = 0; i < max; i++)
 
524
        {
 
525
          DTM thisDTM=m_dtms[i];
 
526
          if((null != thisDTM) && thisDTM instanceof DOM2DTM)
 
527
          {
 
528
            int handle=((DOM2DTM)thisDTM).getHandleOfNode(node);
 
529
            if(handle!=DTM.NULL) return handle;
 
530
          }
 
531
         }
 
532
 
 
533
                        // Not found; generate a new DTM.
 
534
                        //
 
535
                        // %REVIEW% Is this really desirable, or should we return null
 
536
                        // and make folks explicitly instantiate from a DOMSource? The
 
537
                        // latter is more work but gives the caller the opportunity to
 
538
                        // explicitly add the DTM to a DTMManager... and thus to know when
 
539
                        // it can be discarded again, which is something we need to pay much
 
540
                        // more attention to. (Especially since only DTMs which are assigned
 
541
                        // to a manager can use the overflow addressing scheme.)
 
542
                        //
 
543
                        // %BUG% If the source node was a DOM2DTM$defaultNamespaceDeclarationNode
 
544
                        // and the DTM wasn't registered with this DTMManager, we will create
 
545
                        // a new DTM and _still_ not be able to find the node (since it will
 
546
                        // be resynthesized). Another reason to push hard on making all DTMs
 
547
                        // be managed DTMs.
 
548
 
 
549
                        // Since the real root of our tree may be a DocumentFragment, we need to
 
550
      // use getParent to find the root, instead of getOwnerDocument.  Otherwise
 
551
      // DOM2DTM#getHandleOfNode will be very unhappy.
 
552
      Node root = node;
 
553
      Node p = (root.getNodeType() == Node.ATTRIBUTE_NODE) ? ((org.w3c.dom.Attr)root).getOwnerElement() : root.getParentNode();
 
554
      for (; p != null; p = p.getParentNode())
 
555
      {
 
556
        root = p;
 
557
      }
 
558
 
 
559
      DOM2DTM dtm = (DOM2DTM) getDTM(new javax.xml.transform.dom.DOMSource(root),
 
560
                                                                                                                                                 false, null, true, true);
 
561
 
 
562
      int handle;
 
563
      
 
564
      if(node instanceof org.apache.xml.dtm.ref.dom2dtm.DOM2DTMdefaultNamespaceDeclarationNode)
 
565
      {
 
566
                                // Can't return the same node since it's unique to a specific DTM, 
 
567
                                // but can return the equivalent node -- find the corresponding 
 
568
                                // Document Element, then ask it for the xml: namespace decl.
 
569
                                handle=dtm.getHandleOfNode(((org.w3c.dom.Attr)node).getOwnerElement());
 
570
                                handle=dtm.getAttributeNode(handle,node.getNamespaceURI(),node.getLocalName());
 
571
      }
 
572
      else
 
573
                                handle = ((DOM2DTM)dtm).getHandleOfNode(node);
 
574
 
 
575
      if(DTM.NULL == handle)
 
576
        throw new RuntimeException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COULD_NOT_RESOLVE_NODE, null)); //"Could not resolve the node to a handle!");
 
577
 
 
578
      return handle;
 
579
    }
 
580
  }
 
581
 
 
582
  /**
 
583
   * This method returns the SAX2 parser to use with the InputSource
 
584
   * obtained from this URI.
 
585
   * It may return null if any SAX2-conformant XML parser can be used,
 
586
   * or if getInputSource() will also return null. The parser must
 
587
   * be free for use (i.e., not currently in use for another parse().
 
588
   * After use of the parser is completed, the releaseXMLReader(XMLReader)
 
589
   * must be called.
 
590
   *
 
591
   * @param inputSource The value returned from the URIResolver.
 
592
   * @return  a SAX2 XMLReader to use to resolve the inputSource argument.
 
593
   *
 
594
   * @return non-null XMLReader reference ready to parse.
 
595
   */
 
596
  synchronized public XMLReader getXMLReader(Source inputSource)
 
597
  {
 
598
 
 
599
    try
 
600
    {
 
601
      XMLReader reader = (inputSource instanceof SAXSource)
 
602
                         ? ((SAXSource) inputSource).getXMLReader() : null;
 
603
 
 
604
      // If user did not supply a reader, ask for one from the reader manager
 
605
      if (null == reader) {
 
606
        if (m_readerManager == null) {
 
607
            m_readerManager = XMLReaderManager.getInstance();
 
608
        }
 
609
 
 
610
        reader = m_readerManager.getXMLReader();
 
611
      }
 
612
 
 
613
      return reader;
 
614
 
 
615
    } catch (SAXException se) {
 
616
      throw new DTMException(se.getMessage(), se);
 
617
    }
 
618
  }
 
619
 
 
620
  /**
 
621
   * Indicates that the XMLReader object is no longer in use for the transform.
 
622
   *
 
623
   * Note that the getXMLReader method may return an XMLReader that was
 
624
   * specified on the SAXSource object by the application code.  Such a
 
625
   * reader should still be passed to releaseXMLReader, but the reader manager
 
626
   * will only re-use XMLReaders that it created.
 
627
   *
 
628
   * @param reader The XMLReader to be released.
 
629
   */
 
630
  synchronized public void releaseXMLReader(XMLReader reader) {
 
631
    if (m_readerManager != null) {
 
632
      m_readerManager.releaseXMLReader(reader);
 
633
    }
 
634
  }
 
635
 
 
636
  /**
 
637
   * Return the DTM object containing a representation of this node.
 
638
   *
 
639
   * @param nodeHandle DTM Handle indicating which node to retrieve
 
640
   *
 
641
   * @return a reference to the DTM object containing this node.
 
642
   */
 
643
  synchronized public DTM getDTM(int nodeHandle)
 
644
  {
 
645
    try
 
646
    {
 
647
      // Performance critical function.
 
648
      return m_dtms[nodeHandle >>> IDENT_DTM_NODE_BITS];
 
649
    }
 
650
    catch(java.lang.ArrayIndexOutOfBoundsException e)
 
651
    {
 
652
      if(nodeHandle==DTM.NULL)
 
653
                                return null;            // Accept as a special case.
 
654
      else
 
655
                                throw e;                // Programming error; want to know about it.
 
656
    }    
 
657
  }
 
658
 
 
659
  /**
 
660
   * Given a DTM, find the ID number in the DTM tables which addresses
 
661
   * the start of the document. If overflow addressing is in use, other
 
662
   * DTM IDs may also be assigned to this DTM.
 
663
   *
 
664
   * @param dtm The DTM which (hopefully) contains this node.
 
665
   *
 
666
   * @return The DTM ID (as the high bits of a NodeHandle, not as our
 
667
   * internal index), or -1 if the DTM doesn't belong to this manager.
 
668
   */
 
669
  synchronized public int getDTMIdentity(DTM dtm)
 
670
  {
 
671
        // Shortcut using DTMDefaultBase's extension hooks
 
672
        // %REVIEW% Should the lookup be part of the basic DTM API?
 
673
        if(dtm instanceof DTMDefaultBase)
 
674
        {
 
675
                DTMDefaultBase dtmdb=(DTMDefaultBase)dtm;
 
676
                if(dtmdb.getManager()==this)
 
677
                        return dtmdb.getDTMIDs().elementAt(0);
 
678
                else
 
679
                        return -1;
 
680
        }
 
681
                                
 
682
    int n = m_dtms.length;
 
683
 
 
684
    for (int i = 0; i < n; i++)
 
685
    {
 
686
      DTM tdtm = m_dtms[i];
 
687
 
 
688
      if (tdtm == dtm && m_dtm_offsets[i]==0)
 
689
        return i << IDENT_DTM_NODE_BITS;
 
690
    }
 
691
 
 
692
    return -1;
 
693
  }
 
694
 
 
695
  /**
 
696
   * Release the DTMManager's reference(s) to a DTM, making it unmanaged.
 
697
   * This is typically done as part of returning the DTM to the heap after
 
698
   * we're done with it.
 
699
   *
 
700
   * @param dtm the DTM to be released.
 
701
   * 
 
702
   * @param shouldHardDelete If false, this call is a suggestion rather than an
 
703
   * order, and we may not actually release the DTM. This is intended to 
 
704
   * support intelligent caching of documents... which is not implemented
 
705
   * in this version of the DTM manager.
 
706
   *
 
707
   * @return true if the DTM was released, false if shouldHardDelete was set
 
708
   * and we decided not to.
 
709
   */
 
710
  synchronized public boolean release(DTM dtm, boolean shouldHardDelete)
 
711
  {
 
712
    if(DEBUG)
 
713
    {
 
714
      System.out.println("Releasing "+
 
715
                         (shouldHardDelete ? "HARD" : "soft")+
 
716
                         " dtm="+
 
717
                         // Following shouldn't need a nodeHandle, but does...
 
718
                         // and doesn't seem to report the intended value
 
719
                         dtm.getDocumentBaseURI()
 
720
                         );
 
721
    }
 
722
 
 
723
    if (dtm instanceof SAX2DTM)
 
724
    {
 
725
      ((SAX2DTM) dtm).clearCoRoutine();
 
726
    }
 
727
 
 
728
                // Multiple DTM IDs may be assigned to a single DTM. 
 
729
                // The Right Answer is to ask which (if it supports
 
730
                // extension, the DTM will need a list anyway). The 
 
731
                // Wrong Answer, applied if the DTM can't help us,
 
732
                // is to linearly search them all; this may be very
 
733
                // painful.
 
734
                //
 
735
                // %REVIEW% Should the lookup move up into the basic DTM API?
 
736
                if(dtm instanceof DTMDefaultBase)
 
737
                {
 
738
                        org.apache.xml.utils.SuballocatedIntVector ids=((DTMDefaultBase)dtm).getDTMIDs();
 
739
                        for(int i=ids.size()-1;i>=0;--i)
 
740
                                m_dtms[ids.elementAt(i)>>>DTMManager.IDENT_DTM_NODE_BITS]=null;
 
741
                }
 
742
                else
 
743
                {
 
744
                        int i = getDTMIdentity(dtm);
 
745
                    if (i >= 0)
 
746
                        {
 
747
                                m_dtms[i >>> DTMManager.IDENT_DTM_NODE_BITS] = null;
 
748
                        }
 
749
                }
 
750
 
 
751
    dtm.documentRelease();
 
752
    return true;
 
753
  }
 
754
 
 
755
  /**
 
756
   * Method createDocumentFragment
 
757
   *
 
758
   *
 
759
   * NEEDSDOC (createDocumentFragment) @return
 
760
   */
 
761
  synchronized public DTM createDocumentFragment()
 
762
  {
 
763
 
 
764
    try
 
765
    {
 
766
      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 
767
 
 
768
      dbf.setNamespaceAware(true);
 
769
 
 
770
      DocumentBuilder db = dbf.newDocumentBuilder();
 
771
      Document doc = db.newDocument();
 
772
      Node df = doc.createDocumentFragment();
 
773
 
 
774
      return getDTM(new DOMSource(df), true, null, false, false);
 
775
    }
 
776
    catch (Exception e)
 
777
    {
 
778
      throw new DTMException(e);
 
779
    }
 
780
  }
 
781
 
 
782
  /**
 
783
   * NEEDSDOC Method createDTMIterator
 
784
   *
 
785
   *
 
786
   * NEEDSDOC @param whatToShow
 
787
   * NEEDSDOC @param filter
 
788
   * NEEDSDOC @param entityReferenceExpansion
 
789
   *
 
790
   * NEEDSDOC (createDTMIterator) @return
 
791
   */
 
792
  synchronized public DTMIterator createDTMIterator(int whatToShow, DTMFilter filter,
 
793
                                       boolean entityReferenceExpansion)
 
794
  {
 
795
 
 
796
    /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */
 
797
    return null;
 
798
  }
 
799
 
 
800
  /**
 
801
   * NEEDSDOC Method createDTMIterator
 
802
   *
 
803
   *
 
804
   * NEEDSDOC @param xpathString
 
805
   * NEEDSDOC @param presolver
 
806
   *
 
807
   * NEEDSDOC (createDTMIterator) @return
 
808
   */
 
809
  synchronized public DTMIterator createDTMIterator(String xpathString,
 
810
                                       PrefixResolver presolver)
 
811
  {
 
812
 
 
813
    /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */
 
814
    return null;
 
815
  }
 
816
 
 
817
  /**
 
818
   * NEEDSDOC Method createDTMIterator
 
819
   *
 
820
   *
 
821
   * NEEDSDOC @param node
 
822
   *
 
823
   * NEEDSDOC (createDTMIterator) @return
 
824
   */
 
825
  synchronized public DTMIterator createDTMIterator(int node)
 
826
  {
 
827
 
 
828
    /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */
 
829
    return null;
 
830
  }
 
831
 
 
832
  /**
 
833
   * NEEDSDOC Method createDTMIterator
 
834
   *
 
835
   *
 
836
   * NEEDSDOC @param xpathCompiler
 
837
   * NEEDSDOC @param pos
 
838
   *
 
839
   * NEEDSDOC (createDTMIterator) @return
 
840
   */
 
841
  synchronized public DTMIterator createDTMIterator(Object xpathCompiler, int pos)
 
842
  {
 
843
 
 
844
    /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */
 
845
    return null;
 
846
  }
 
847
 
 
848
  /**
 
849
   * return the expanded name table.
 
850
   *
 
851
   * NEEDSDOC @param dtm
 
852
   *
 
853
   * NEEDSDOC ($objectName$) @return
 
854
   */
 
855
  public ExpandedNameTable getExpandedNameTable(DTM dtm)
 
856
  {
 
857
    return m_expandedNameTable;
 
858
  }
 
859
}