001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: DTMManagerDefault.java 468653 2006-10-28 07:07:05Z minchau $
020 */
021 package org.apache.xml.dtm.ref;
022
023 import javax.xml.parsers.DocumentBuilder;
024 import javax.xml.parsers.DocumentBuilderFactory;
025 import javax.xml.transform.Source;
026 import javax.xml.transform.dom.DOMSource;
027 import javax.xml.transform.sax.SAXSource;
028 import javax.xml.transform.stream.StreamSource;
029
030 import org.apache.xml.dtm.DTM;
031 import org.apache.xml.dtm.DTMException;
032 import org.apache.xml.dtm.DTMFilter;
033 import org.apache.xml.dtm.DTMIterator;
034 import org.apache.xml.dtm.DTMManager;
035 import org.apache.xml.dtm.DTMWSFilter;
036 import org.apache.xml.dtm.ref.dom2dtm.DOM2DTM;
037 import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM;
038 import org.apache.xml.dtm.ref.sax2dtm.SAX2RTFDTM;
039 import org.apache.xml.res.XMLErrorResources;
040 import org.apache.xml.res.XMLMessages;
041 import org.apache.xml.utils.PrefixResolver;
042 import org.apache.xml.utils.SystemIDResolver;
043 import org.apache.xml.utils.XMLReaderManager;
044 import org.apache.xml.utils.XMLStringFactory;
045
046 import org.w3c.dom.Document;
047 import org.w3c.dom.Node;
048
049 import org.xml.sax.InputSource;
050 import org.xml.sax.SAXException;
051 import org.xml.sax.SAXNotRecognizedException;
052 import org.xml.sax.SAXNotSupportedException;
053 import org.xml.sax.XMLReader;
054 import org.xml.sax.helpers.DefaultHandler;
055
056 /**
057 * The default implementation for the DTMManager.
058 *
059 * %REVIEW% There is currently a reentrancy issue, since the finalizer
060 * for XRTreeFrag (which runs in the GC thread) wants to call
061 * DTMManager.release(), and may do so at the same time that the main
062 * transformation thread is accessing the manager. Our current solution is
063 * to make most of the manager's methods <code>synchronized</code>.
064 * Early tests suggest that doing so is not causing a significant
065 * performance hit in Xalan. However, it should be noted that there
066 * is a possible alternative solution: rewrite release() so it merely
067 * posts a request for release onto a threadsafe queue, and explicitly
068 * process that queue on an infrequent basis during main-thread
069 * activity (eg, when getDTM() is invoked). The downside of that solution
070 * would be a greater delay before the DTM's storage is actually released
071 * for reuse.
072 * */
073 public class DTMManagerDefault extends DTMManager
074 {
075 //static final boolean JKESS_XNI_EXPERIMENT=true;
076
077 /** Set this to true if you want a dump of the DTM after creation. */
078 private static final boolean DUMPTREE = false;
079
080 /** Set this to true if you want a basic diagnostics. */
081 private static final boolean DEBUG = false;
082
083 /**
084 * Map from DTM identifier numbers to DTM objects that this manager manages.
085 * One DTM may have several prefix numbers, if extended node indexing
086 * is in use; in that case, m_dtm_offsets[] will used to control which
087 * prefix maps to which section of the DTM.
088 *
089 * This array grows as necessary; see addDTM().
090 *
091 * This array grows as necessary; see addDTM(). Growth is uncommon... but
092 * access needs to be blindingly fast since it's used in node addressing.
093 */
094 protected DTM m_dtms[] = new DTM[256];
095
096 /** Map from DTM identifier numbers to offsets. For small DTMs with a
097 * single identifier, this will always be 0. In overflow addressing, where
098 * additional identifiers are allocated to access nodes beyond the range of
099 * 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 }