001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: DTMManagerDefault.java,v 1.52 2004/11/22 17:53:43 mkwan Exp $
018: */
019: package org.apache.xml.dtm.ref;
020:
021: import javax.xml.parsers.DocumentBuilder;
022: import javax.xml.parsers.DocumentBuilderFactory;
023: import javax.xml.transform.Source;
024: import javax.xml.transform.dom.DOMSource;
025: import javax.xml.transform.sax.SAXSource;
026: import javax.xml.transform.stream.StreamSource;
027:
028: import org.apache.xml.dtm.DTM;
029: import org.apache.xml.dtm.DTMException;
030: import org.apache.xml.dtm.DTMFilter;
031: import org.apache.xml.dtm.DTMIterator;
032: import org.apache.xml.dtm.DTMManager;
033: import org.apache.xml.dtm.DTMWSFilter;
034: import org.apache.xml.dtm.ref.dom2dtm.DOM2DTM;
035: import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM;
036: import org.apache.xml.dtm.ref.sax2dtm.SAX2RTFDTM;
037: import org.apache.xml.res.XMLErrorResources;
038: import org.apache.xml.res.XMLMessages;
039: import org.apache.xml.utils.PrefixResolver;
040: import org.apache.xml.utils.SystemIDResolver;
041: import org.apache.xml.utils.XMLReaderManager;
042: import org.apache.xml.utils.XMLStringFactory;
043:
044: import org.w3c.dom.Document;
045: import org.w3c.dom.Node;
046:
047: import org.xml.sax.InputSource;
048: import org.xml.sax.SAXException;
049: import org.xml.sax.SAXNotRecognizedException;
050: import org.xml.sax.SAXNotSupportedException;
051: import org.xml.sax.XMLReader;
052: import org.xml.sax.helpers.DefaultHandler;
053:
054: /**
055: * The default implementation for the DTMManager.
056: *
057: * %REVIEW% There is currently a reentrancy issue, since the finalizer
058: * for XRTreeFrag (which runs in the GC thread) wants to call
059: * DTMManager.release(), and may do so at the same time that the main
060: * transformation thread is accessing the manager. Our current solution is
061: * to make most of the manager's methods <code>synchronized</code>.
062: * Early tests suggest that doing so is not causing a significant
063: * performance hit in Xalan. However, it should be noted that there
064: * is a possible alternative solution: rewrite release() so it merely
065: * posts a request for release onto a threadsafe queue, and explicitly
066: * process that queue on an infrequent basis during main-thread
067: * activity (eg, when getDTM() is invoked). The downside of that solution
068: * would be a greater delay before the DTM's storage is actually released
069: * for reuse.
070: * */
071: public class DTMManagerDefault extends DTMManager {
072: //static final boolean JKESS_XNI_EXPERIMENT=true;
073:
074: /** Set this to true if you want a dump of the DTM after creation. */
075: private static final boolean DUMPTREE = false;
076:
077: /** Set this to true if you want a basic diagnostics. */
078: private static final boolean DEBUG = false;
079:
080: /**
081: * Map from DTM identifier numbers to DTM objects that this manager manages.
082: * One DTM may have several prefix numbers, if extended node indexing
083: * is in use; in that case, m_dtm_offsets[] will used to control which
084: * prefix maps to which section of the DTM.
085: *
086: * This array grows as necessary; see addDTM().
087: *
088: * This array grows as necessary; see addDTM(). Growth is uncommon... but
089: * access needs to be blindingly fast since it's used in node addressing.
090: */
091: protected DTM m_dtms[] = new DTM[256];
092:
093: /** Map from DTM identifier numbers to offsets. For small DTMs with a
094: * single identifier, this will always be 0. In overflow addressing, where
095: * additional identifiers are allocated to access nodes beyond the range of
096: * a single Node Handle, this table is used to map the handle's node field
097: * into the actual node identifier.
098: *
099: * This array grows as necessary; see addDTM().
100: *
101: * This array grows as necessary; see addDTM(). Growth is uncommon... but
102: * access needs to be blindingly fast since it's used in node addressing.
103: * (And at the moment, that includes accessing it from DTMDefaultBase,
104: * which is why this is not Protected or Private.)
105: */
106: int m_dtm_offsets[] = new int[256];
107:
108: /**
109: * The cache for XMLReader objects to be used if the user did not
110: * supply an XMLReader for a SAXSource or supplied a StreamSource.
111: */
112: protected XMLReaderManager m_readerManager = null;
113:
114: /**
115: * The default implementation of ContentHandler, DTDHandler and ErrorHandler.
116: */
117: protected DefaultHandler m_defaultHandler = new DefaultHandler();
118:
119: /**
120: * Add a DTM to the DTM table. This convenience call adds it as the
121: * "base DTM ID", with offset 0. The other version of addDTM should
122: * be used if you want to add "extended" DTM IDs with nonzero offsets.
123: *
124: * @param dtm Should be a valid reference to a DTM.
125: * @param id Integer DTM ID to be bound to this DTM
126: */
127: synchronized public void addDTM(DTM dtm, int id) {
128: addDTM(dtm, id, 0);
129: }
130:
131: /**
132: * Add a DTM to the DTM table.
133: *
134: * @param dtm Should be a valid reference to a DTM.
135: * @param id Integer DTM ID to be bound to this DTM.
136: * @param offset Integer addressing offset. The internal DTM Node ID is
137: * obtained by adding this offset to the node-number field of the
138: * public DTM Handle. For the first DTM ID accessing each DTM, this is 0;
139: * for overflow addressing it will be a multiple of 1<<IDENT_DTM_NODE_BITS.
140: */
141: synchronized public void addDTM(DTM dtm, int id, int offset) {
142: if (id >= IDENT_MAX_DTMS) {
143: // TODO: %REVIEW% Not really the right error message.
144: throw new DTMException(XMLMessages.createXMLMessage(
145: XMLErrorResources.ER_NO_DTMIDS_AVAIL, null)); //"No more DTM IDs are available!");
146: }
147:
148: // We used to just allocate the array size to IDENT_MAX_DTMS.
149: // But we expect to increase that to 16 bits, and I'm not willing
150: // to allocate that much space unless needed. We could use one of our
151: // handy-dandy Fast*Vectors, but this will do for now.
152: // %REVIEW%
153: int oldlen = m_dtms.length;
154: if (oldlen <= id) {
155: // Various growth strategies are possible. I think we don't want
156: // to over-allocate excessively, and I'm willing to reallocate
157: // more often to get that. See also Fast*Vector classes.
158: //
159: // %REVIEW% Should throw a more diagnostic error if we go over the max...
160: int newlen = Math.min((id + 256), IDENT_MAX_DTMS);
161:
162: DTM new_m_dtms[] = new DTM[newlen];
163: System.arraycopy(m_dtms, 0, new_m_dtms, 0, oldlen);
164: m_dtms = new_m_dtms;
165: int new_m_dtm_offsets[] = new int[newlen];
166: System.arraycopy(m_dtm_offsets, 0, new_m_dtm_offsets, 0,
167: oldlen);
168: m_dtm_offsets = new_m_dtm_offsets;
169: }
170:
171: m_dtms[id] = dtm;
172: m_dtm_offsets[id] = offset;
173: dtm.documentRegistration();
174: // The DTM should have been told who its manager was when we created it.
175: // Do we need to allow for adopting DTMs _not_ created by this manager?
176: }
177:
178: /**
179: * Get the first free DTM ID available. %OPT% Linear search is inefficient!
180: */
181: synchronized public int getFirstFreeDTMID() {
182: int n = m_dtms.length;
183: for (int i = 1; i < n; i++) {
184: if (null == m_dtms[i]) {
185: return i;
186: }
187: }
188: return n; // count on addDTM() to throw exception if out of range
189: }
190:
191: /**
192: * The default table for exandedNameID lookups.
193: */
194: private ExpandedNameTable m_expandedNameTable = 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, boolean incremental,
231: boolean doIndexing) {
232:
233: if (DEBUG && null != source)
234: System.out.println("Starting "
235: + (unique ? "UNIQUE" : "shared") + " source: "
236: + source.getSystemId());
237:
238: XMLStringFactory xstringFactory = m_xsf;
239: int dtmPos = getFirstFreeDTMID();
240: int documentID = dtmPos << IDENT_DTM_NODE_BITS;
241:
242: if ((null != source) && source instanceof DOMSource) {
243: DOM2DTM dtm = new DOM2DTM(this , (DOMSource) source,
244: documentID, whiteSpaceFilter, xstringFactory,
245: doIndexing);
246:
247: addDTM(dtm, dtmPos, 0);
248:
249: // if (DUMPTREE)
250: // {
251: // dtm.dumpDTM();
252: // }
253:
254: return dtm;
255: } else {
256: boolean isSAXSource = (null != source) ? (source instanceof SAXSource)
257: : true;
258: boolean isStreamSource = (null != source) ? (source instanceof StreamSource)
259: : false;
260:
261: if (isSAXSource || isStreamSource) {
262: XMLReader reader = null;
263: SAX2DTM dtm;
264:
265: try {
266: InputSource xmlSource;
267:
268: if (null == source) {
269: xmlSource = null;
270: } else {
271: reader = getXMLReader(source);
272: xmlSource = SAXSource
273: .sourceToInputSource(source);
274:
275: String urlOfSource = xmlSource.getSystemId();
276:
277: if (null != urlOfSource) {
278: try {
279: urlOfSource = SystemIDResolver
280: .getAbsoluteURI(urlOfSource);
281: } catch (Exception e) {
282: // %REVIEW% Is there a better way to send a warning?
283: System.err
284: .println("Can not absolutize URL: "
285: + urlOfSource);
286: }
287:
288: xmlSource.setSystemId(urlOfSource);
289: }
290: }
291:
292: if (source == null && unique && !incremental
293: && !doIndexing) {
294: // Special case to support RTF construction into shared DTM.
295: // It should actually still work for other uses,
296: // but may be slightly deoptimized relative to the base
297: // to allow it to deal with carrying multiple documents.
298: //
299: // %REVIEW% This is a sloppy way to request this mode;
300: // we need to consider architectural improvements.
301: dtm = new SAX2RTFDTM(this , source, documentID,
302: whiteSpaceFilter, xstringFactory,
303: doIndexing);
304: }
305: /**************************************************************
306: // EXPERIMENTAL 3/22/02
307: else if(JKESS_XNI_EXPERIMENT && m_incremental) {
308: dtm = new XNI2DTM(this, source, documentID, whiteSpaceFilter,
309: xstringFactory, doIndexing);
310: }
311: **************************************************************/
312: // Create the basic SAX2DTM.
313: else {
314: dtm = new SAX2DTM(this , source, documentID,
315: whiteSpaceFilter, xstringFactory,
316: doIndexing);
317: }
318:
319: // Go ahead and add the DTM to the lookup table. This needs to be
320: // done before any parsing occurs. Note offset 0, since we've just
321: // created a new DTM.
322: addDTM(dtm, dtmPos, 0);
323:
324: boolean haveXercesParser = (null != reader)
325: && (reader.getClass().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) Class
342: .forName(
343: "org.apache.xml.dtm.ref.IncrementalSAXSource_Xerces")
344: .newInstance();
345: } catch (Exception ex) {
346: ex.printStackTrace();
347: coParser = null;
348: }
349: }
350:
351: if (coParser == null) {
352: // Create a IncrementalSAXSource to run on the secondary thread.
353: if (null == reader) {
354: coParser = new IncrementalSAXSource_Filter();
355: } else {
356: IncrementalSAXSource_Filter filter = new IncrementalSAXSource_Filter();
357: filter.setXMLReader(reader);
358: coParser = filter;
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(
409: e);
410: }
411: } else {
412: if (null == reader) {
413:
414: // Then the user will construct it themselves.
415: return dtm;
416: }
417:
418: // not incremental
419: reader.setContentHandler(dtm);
420: reader.setDTDHandler(dtm);
421: if (null == reader.getErrorHandler()) {
422: reader.setErrorHandler(dtm);
423: }
424:
425: try {
426: reader
427: .setProperty(
428: "http://xml.org/sax/properties/lexical-handler",
429: dtm);
430: } catch (SAXNotRecognizedException e) {
431: } catch (SAXNotSupportedException e) {
432: }
433:
434: try {
435: reader.parse(xmlSource);
436: } catch (RuntimeException re) {
437: dtm.clearCoRoutine();
438:
439: throw re;
440: } catch (Exception e) {
441: dtm.clearCoRoutine();
442:
443: throw new org.apache.xml.utils.WrappedRuntimeException(
444: e);
445: }
446: }
447:
448: if (DUMPTREE) {
449: System.out.println("Dumping SAX2DOM");
450: dtm.dumpDTM(System.err);
451: }
452:
453: return dtm;
454: } finally {
455: // Reset the ContentHandler, DTDHandler, ErrorHandler to the DefaultHandler
456: // after creating the DTM.
457: if (reader != null
458: && !(m_incremental && incremental)) {
459: reader.setContentHandler(m_defaultHandler);
460: reader.setDTDHandler(m_defaultHandler);
461: reader.setErrorHandler(m_defaultHandler);
462:
463: // Reset the LexicalHandler to null after creating the DTM.
464: try {
465: reader
466: .setProperty(
467: "http://xml.org/sax/properties/lexical-handler",
468: null);
469: } catch (Exception e) {
470: }
471: }
472: releaseXMLReader(reader);
473: }
474: } else {
475:
476: // It should have been handled by a derived class or the caller
477: // made a mistake.
478: throw new DTMException(XMLMessages.createXMLMessage(
479: XMLErrorResources.ER_NOT_SUPPORTED,
480: new Object[] { source })); //"Not supported: " + source);
481: }
482: }
483: }
484:
485: /**
486: * Given a W3C DOM node, try and return a DTM handle.
487: * Note: calling this may be non-optimal, and there is no guarantee that
488: * the node will be found in any particular DTM.
489: *
490: * @param node Non-null reference to a DOM node.
491: *
492: * @return a valid DTM handle.
493: */
494: synchronized public int getDTMHandleFromNode(org.w3c.dom.Node node) {
495: if (null == node)
496: throw new IllegalArgumentException(XMLMessages
497: .createXMLMessage(
498: XMLErrorResources.ER_NODE_NON_NULL, null)); //"node must be non-null for getDTMHandleFromNode!");
499:
500: if (node instanceof org.apache.xml.dtm.ref.DTMNodeProxy)
501: return ((org.apache.xml.dtm.ref.DTMNodeProxy) node)
502: .getDTMNodeNumber();
503:
504: else {
505: // Find the DOM2DTMs wrapped around this Document (if any)
506: // and check whether they contain the Node in question.
507: //
508: // NOTE that since a DOM2DTM may represent a subtree rather
509: // than a full document, we have to be prepared to check more
510: // than one -- and there is no guarantee that we will find
511: // one that contains ancestors or siblings of the node we're
512: // seeking.
513: //
514: // %REVIEW% We could search for the one which contains this
515: // node at the deepest level, and thus covers the widest
516: // subtree, but that's going to entail additional work
517: // checking more DTMs... and getHandleOfNode is not a
518: // cheap operation in most implementations.
519: //
520: // TODO: %REVIEW% If overflow addressing, we may recheck a DTM
521: // already examined. Ouch. But with the increased number of DTMs,
522: // scanning back to check this is painful.
523: // POSSIBLE SOLUTIONS:
524: // Generate a list of _unique_ DTM objects?
525: // Have each DTM cache last DOM node search?
526: int max = m_dtms.length;
527: for (int i = 0; i < max; i++) {
528: DTM this DTM = m_dtms[i];
529: if ((null != this DTM) && this DTM instanceof DOM2DTM) {
530: int handle = ((DOM2DTM) this DTM)
531: .getHandleOfNode(node);
532: if (handle != DTM.NULL)
533: return handle;
534: }
535: }
536:
537: // Not found; generate a new DTM.
538: //
539: // %REVIEW% Is this really desirable, or should we return null
540: // and make folks explicitly instantiate from a DOMSource? The
541: // latter is more work but gives the caller the opportunity to
542: // explicitly add the DTM to a DTMManager... and thus to know when
543: // it can be discarded again, which is something we need to pay much
544: // more attention to. (Especially since only DTMs which are assigned
545: // to a manager can use the overflow addressing scheme.)
546: //
547: // %BUG% If the source node was a DOM2DTM$defaultNamespaceDeclarationNode
548: // and the DTM wasn't registered with this DTMManager, we will create
549: // a new DTM and _still_ not be able to find the node (since it will
550: // be resynthesized). Another reason to push hard on making all DTMs
551: // be managed DTMs.
552:
553: // Since the real root of our tree may be a DocumentFragment, we need to
554: // use getParent to find the root, instead of getOwnerDocument. Otherwise
555: // DOM2DTM#getHandleOfNode will be very unhappy.
556: Node root = node;
557: Node p = (root.getNodeType() == Node.ATTRIBUTE_NODE) ? ((org.w3c.dom.Attr) root)
558: .getOwnerElement()
559: : root.getParentNode();
560: for (; p != null; p = p.getParentNode()) {
561: root = p;
562: }
563:
564: DOM2DTM dtm = (DOM2DTM) getDTM(
565: new javax.xml.transform.dom.DOMSource(root), false,
566: null, true, true);
567:
568: int handle;
569:
570: if (node instanceof org.apache.xml.dtm.ref.dom2dtm.DOM2DTMdefaultNamespaceDeclarationNode) {
571: // Can't return the same node since it's unique to a specific DTM,
572: // but can return the equivalent node -- find the corresponding
573: // Document Element, then ask it for the xml: namespace decl.
574: handle = dtm.getHandleOfNode(((org.w3c.dom.Attr) node)
575: .getOwnerElement());
576: handle = dtm.getAttributeNode(handle, node
577: .getNamespaceURI(), node.getLocalName());
578: } else
579: handle = ((DOM2DTM) dtm).getHandleOfNode(node);
580:
581: if (DTM.NULL == handle)
582: throw new RuntimeException(
583: XMLMessages
584: .createXMLMessage(
585: XMLErrorResources.ER_COULD_NOT_RESOLVE_NODE,
586: null)); //"Could not resolve the node to a handle!");
587:
588: return handle;
589: }
590: }
591:
592: /**
593: * This method returns the SAX2 parser to use with the InputSource
594: * obtained from this URI.
595: * It may return null if any SAX2-conformant XML parser can be used,
596: * or if getInputSource() will also return null. The parser must
597: * be free for use (i.e., not currently in use for another parse().
598: * After use of the parser is completed, the releaseXMLReader(XMLReader)
599: * must be called.
600: *
601: * @param inputSource The value returned from the URIResolver.
602: * @return a SAX2 XMLReader to use to resolve the inputSource argument.
603: *
604: * @return non-null XMLReader reference ready to parse.
605: */
606: synchronized public XMLReader getXMLReader(Source inputSource) {
607:
608: try {
609: XMLReader reader = (inputSource instanceof SAXSource) ? ((SAXSource) inputSource)
610: .getXMLReader()
611: : null;
612:
613: // If user did not supply a reader, ask for one from the reader manager
614: if (null == reader) {
615: if (m_readerManager == null) {
616: m_readerManager = XMLReaderManager.getInstance();
617: }
618:
619: reader = m_readerManager.getXMLReader();
620: }
621:
622: return reader;
623:
624: } catch (SAXException se) {
625: throw new DTMException(se.getMessage(), se);
626: }
627: }
628:
629: /**
630: * Indicates that the XMLReader object is no longer in use for the transform.
631: *
632: * Note that the getXMLReader method may return an XMLReader that was
633: * specified on the SAXSource object by the application code. Such a
634: * reader should still be passed to releaseXMLReader, but the reader manager
635: * will only re-use XMLReaders that it created.
636: *
637: * @param reader The XMLReader to be released.
638: */
639: synchronized public void releaseXMLReader(XMLReader reader) {
640: if (m_readerManager != null) {
641: m_readerManager.releaseXMLReader(reader);
642: }
643: }
644:
645: /**
646: * Return the DTM object containing a representation of this node.
647: *
648: * @param nodeHandle DTM Handle indicating which node to retrieve
649: *
650: * @return a reference to the DTM object containing this node.
651: */
652: synchronized public DTM getDTM(int nodeHandle) {
653: try {
654: // Performance critical function.
655: return m_dtms[nodeHandle >>> IDENT_DTM_NODE_BITS];
656: } catch (java.lang.ArrayIndexOutOfBoundsException e) {
657: if (nodeHandle == DTM.NULL)
658: return null; // Accept as a special case.
659: else
660: throw e; // Programming error; want to know about it.
661: }
662: }
663:
664: /**
665: * Given a DTM, find the ID number in the DTM tables which addresses
666: * the start of the document. If overflow addressing is in use, other
667: * DTM IDs may also be assigned to this DTM.
668: *
669: * @param dtm The DTM which (hopefully) contains this node.
670: *
671: * @return The DTM ID (as the high bits of a NodeHandle, not as our
672: * internal index), or -1 if the DTM doesn't belong to this manager.
673: */
674: synchronized public int getDTMIdentity(DTM dtm) {
675: // Shortcut using DTMDefaultBase's extension hooks
676: // %REVIEW% Should the lookup be part of the basic DTM API?
677: if (dtm instanceof DTMDefaultBase) {
678: DTMDefaultBase dtmdb = (DTMDefaultBase) dtm;
679: if (dtmdb.getManager() == this )
680: return dtmdb.getDTMIDs().elementAt(0);
681: else
682: return -1;
683: }
684:
685: int n = m_dtms.length;
686:
687: for (int i = 0; i < n; i++) {
688: DTM tdtm = m_dtms[i];
689:
690: if (tdtm == dtm && m_dtm_offsets[i] == 0)
691: return i << IDENT_DTM_NODE_BITS;
692: }
693:
694: return -1;
695: }
696:
697: /**
698: * Release the DTMManager's reference(s) to a DTM, making it unmanaged.
699: * This is typically done as part of returning the DTM to the heap after
700: * we're done with it.
701: *
702: * @param dtm the DTM to be released.
703: *
704: * @param shouldHardDelete If false, this call is a suggestion rather than an
705: * order, and we may not actually release the DTM. This is intended to
706: * support intelligent caching of documents... which is not implemented
707: * in this version of the DTM manager.
708: *
709: * @return true if the DTM was released, false if shouldHardDelete was set
710: * and we decided not to.
711: */
712: synchronized public boolean release(DTM dtm,
713: boolean shouldHardDelete) {
714: if (DEBUG) {
715: System.out.println("Releasing "
716: + (shouldHardDelete ? "HARD" : "soft") + " 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: if (dtm instanceof SAX2DTM) {
723: ((SAX2DTM) dtm).clearCoRoutine();
724: }
725:
726: // Multiple DTM IDs may be assigned to a single DTM.
727: // The Right Answer is to ask which (if it supports
728: // extension, the DTM will need a list anyway). The
729: // Wrong Answer, applied if the DTM can't help us,
730: // is to linearly search them all; this may be very
731: // painful.
732: //
733: // %REVIEW% Should the lookup move up into the basic DTM API?
734: if (dtm instanceof DTMDefaultBase) {
735: org.apache.xml.utils.SuballocatedIntVector ids = ((DTMDefaultBase) dtm)
736: .getDTMIDs();
737: for (int i = ids.size() - 1; i >= 0; --i)
738: m_dtms[ids.elementAt(i) >>> DTMManager.IDENT_DTM_NODE_BITS] = null;
739: } else {
740: int i = getDTMIdentity(dtm);
741: if (i >= 0) {
742: m_dtms[i >>> DTMManager.IDENT_DTM_NODE_BITS] = null;
743: }
744: }
745:
746: dtm.documentRelease();
747: return true;
748: }
749:
750: /**
751: * Method createDocumentFragment
752: *
753: *
754: * NEEDSDOC (createDocumentFragment) @return
755: */
756: synchronized public DTM createDocumentFragment() {
757:
758: try {
759: DocumentBuilderFactory dbf = DocumentBuilderFactory
760: .newInstance();
761:
762: dbf.setNamespaceAware(true);
763:
764: DocumentBuilder db = dbf.newDocumentBuilder();
765: Document doc = db.newDocument();
766: Node df = doc.createDocumentFragment();
767:
768: return getDTM(new DOMSource(df), true, null, false, false);
769: } catch (Exception e) {
770: throw new DTMException(e);
771: }
772: }
773:
774: /**
775: * NEEDSDOC Method createDTMIterator
776: *
777: *
778: * NEEDSDOC @param whatToShow
779: * NEEDSDOC @param filter
780: * NEEDSDOC @param entityReferenceExpansion
781: *
782: * NEEDSDOC (createDTMIterator) @return
783: */
784: synchronized public DTMIterator createDTMIterator(int whatToShow,
785: DTMFilter filter, boolean entityReferenceExpansion) {
786:
787: /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */
788: return null;
789: }
790:
791: /**
792: * NEEDSDOC Method createDTMIterator
793: *
794: *
795: * NEEDSDOC @param xpathString
796: * NEEDSDOC @param presolver
797: *
798: * NEEDSDOC (createDTMIterator) @return
799: */
800: synchronized public DTMIterator createDTMIterator(
801: String xpathString, PrefixResolver presolver) {
802:
803: /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */
804: return null;
805: }
806:
807: /**
808: * NEEDSDOC Method createDTMIterator
809: *
810: *
811: * NEEDSDOC @param node
812: *
813: * NEEDSDOC (createDTMIterator) @return
814: */
815: synchronized public DTMIterator createDTMIterator(int node) {
816:
817: /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */
818: return null;
819: }
820:
821: /**
822: * NEEDSDOC Method createDTMIterator
823: *
824: *
825: * NEEDSDOC @param xpathCompiler
826: * NEEDSDOC @param pos
827: *
828: * NEEDSDOC (createDTMIterator) @return
829: */
830: synchronized public DTMIterator createDTMIterator(
831: Object xpathCompiler, int pos) {
832:
833: /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */
834: return null;
835: }
836:
837: /**
838: * return the expanded name table.
839: *
840: * NEEDSDOC @param dtm
841: *
842: * NEEDSDOC ($objectName$) @return
843: */
844: public ExpandedNameTable getExpandedNameTable(DTM dtm) {
845: return m_expandedNameTable;
846: }
847: }
|