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