| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, Lotus |
| * Development Corporation., http://www.lotus.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| package org.apache.xml.dtm.ref; |
| |
| import org.apache.xml.dtm.*; |
| |
| import java.util.Vector; |
| |
| // JAXP 1.1 |
| import javax.xml.parsers.*; |
| import javax.xml.transform.dom.DOMSource; |
| import javax.xml.transform.sax.SAXSource; |
| import javax.xml.transform.stream.StreamSource; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.SourceLocator; |
| |
| // Apache XML Utilities |
| import org.apache.xml.utils.PrefixResolver; |
| import org.apache.xml.utils.SystemIDResolver; |
| import org.apache.xml.dtm.ref.dom2dtm.DOM2DTM; |
| import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM; |
| import org.apache.xml.dtm.ref.sax2dtm.SAX2RTFDTM; |
| |
| /************************************************************** |
| // EXPERIMENTAL 3/22/02 |
| import org.apache.xml.dtm.ref.xni2dtm.XNI2DTM; |
| **************************************************************/ |
| |
| // W3C DOM |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Node; |
| |
| // SAX2 |
| import org.xml.sax.InputSource; |
| import org.xml.sax.XMLReader; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.EntityResolver; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXNotRecognizedException; |
| import org.xml.sax.SAXNotSupportedException; |
| import org.xml.sax.helpers.XMLReaderFactory; |
| import org.xml.sax.ext.DeclHandler; |
| import org.xml.sax.ext.LexicalHandler; |
| |
| import org.apache.xml.utils.XMLString; |
| import org.apache.xml.utils.XMLStringFactory; |
| |
| import org.apache.xalan.res.XSLTErrorResources; |
| import org.apache.xalan.res.XSLMessages; |
| |
| /** |
| * The default implementation for the DTMManager. |
| * |
| * %REVIEW% There is currently a reentrancy issue, since the finalizer |
| * for XRTreeFrag (which runs in the GC thread) wants to call |
| * DTMManager.release(), and may do so at the same time that the main |
| * transformation thread is accessing the manager. Our current solution is |
| * to make most of the manager's methods <code>synchronized</code>. |
| * Early tests suggest that doing so is not causing a significant |
| * performance hit in Xalan. However, it should be noted that there |
| * is a possible alternative solution: rewrite release() so it merely |
| * posts a request for release onto a threadsafe queue, and explicitly |
| * process that queue on an infrequent basis during main-thread |
| * activity (eg, when getDTM() is invoked). The downside of that solution |
| * would be a greater delay before the DTM's storage is actually released |
| * for reuse. |
| * */ |
| public class DTMManagerDefault extends DTMManager |
| { |
| //static final boolean JKESS_XNI_EXPERIMENT=true; |
| |
| /** Set this to true if you want a dump of the DTM after creation. */ |
| private static final boolean DUMPTREE = false; |
| |
| /** Set this to true if you want a basic diagnostics. */ |
| private static final boolean DEBUG = false; |
| |
| /** |
| * Map from DTM identifier numbers to DTM objects that this manager manages. |
| * One DTM may have several prefix numbers, if extended node indexing |
| * is in use; in that case, m_dtm_offsets[] will used to control which |
| * prefix maps to which section of the DTM. |
| * |
| * This array grows as necessary; see addDTM(). |
| * |
| * This array grows as necessary; see addDTM(). Growth is uncommon... but |
| * access needs to be blindingly fast since it's used in node addressing. |
| */ |
| protected DTM m_dtms[] = new DTM[256]; |
| |
| /** Map from DTM identifier numbers to offsets. For small DTMs with a |
| * single identifier, this will always be 0. In overflow addressing, where |
| * additional identifiers are allocated to access nodes beyond the range of |
| * a single Node Handle, this table is used to map the handle's node field |
| * into the actual node identifier. |
| * |
| * This array grows as necessary; see addDTM(). |
| * |
| * This array grows as necessary; see addDTM(). Growth is uncommon... but |
| * access needs to be blindingly fast since it's used in node addressing. |
| * (And at the moment, that includes accessing it from DTMDefaultBase, |
| * which is why this is not Protected or Private.) |
| */ |
| int m_dtm_offsets[] = new int[256]; |
| |
| /** |
| * Add a DTM to the DTM table. This convenience call adds it as the |
| * "base DTM ID", with offset 0. The other version of addDTM should |
| * be used if you want to add "extended" DTM IDs with nonzero offsets. |
| * |
| * @param dtm Should be a valid reference to a DTM. |
| * @param id Integer DTM ID to be bound to this DTM |
| */ |
| synchronized public void addDTM(DTM dtm, int id) { addDTM(dtm,id,0); } |
| |
| |
| /** |
| * Add a DTM to the DTM table. |
| * |
| * @param dtm Should be a valid reference to a DTM. |
| * @param id Integer DTM ID to be bound to this DTM. |
| * @param offset Integer addressing offset. The internal DTM Node ID is |
| * obtained by adding this offset to the node-number field of the |
| * public DTM Handle. For the first DTM ID accessing each DTM, this is 0; |
| * for overflow addressing it will be a multiple of 1<<IDENT_DTM_NODE_BITS. |
| */ |
| synchronized public void addDTM(DTM dtm, int id, int offset) |
| { |
| if(id>=IDENT_MAX_DTMS) |
| { |
| // TODO: %REVIEW% Not really the right error message. |
| throw new DTMException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_DTMIDS_AVAIL, null)); //"No more DTM IDs are available!"); |
| } |
| |
| // We used to just allocate the array size to IDENT_MAX_DTMS. |
| // But we expect to increase that to 16 bits, and I'm not willing |
| // to allocate that much space unless needed. We could use one of our |
| // handy-dandy Fast*Vectors, but this will do for now. |
| // %REVIEW% |
| int oldlen=m_dtms.length; |
| if(oldlen<=id) |
| { |
| // Various growth strategies are possible. I think we don't want |
| // to over-allocate excessively, and I'm willing to reallocate |
| // more often to get that. See also Fast*Vector classes. |
| // |
| // %REVIEW% Should throw a more diagnostic error if we go over the max... |
| int newlen=Math.min((id+256),IDENT_MAX_DTMS); |
| |
| DTM new_m_dtms[] = new DTM[newlen]; |
| System.arraycopy(m_dtms,0,new_m_dtms,0,oldlen); |
| m_dtms=new_m_dtms; |
| int new_m_dtm_offsets[] = new int[newlen]; |
| System.arraycopy(m_dtm_offsets,0,new_m_dtm_offsets,0,oldlen); |
| m_dtm_offsets=new_m_dtm_offsets; |
| } |
| |
| m_dtms[id] = dtm; |
| m_dtm_offsets[id]=offset; |
| dtm.documentRegistration(); |
| // The DTM should have been told who its manager was when we created it. |
| // Do we need to allow for adopting DTMs _not_ created by this manager? |
| } |
| |
| /** |
| * Get the first free DTM ID available. %OPT% Linear search is inefficient! |
| */ |
| synchronized public int getFirstFreeDTMID() |
| { |
| int n = m_dtms.length; |
| for (int i = 1; i < n; i++) |
| { |
| if(null == m_dtms[i]) |
| { |
| return i; |
| } |
| } |
| return n; // count on addDTM() to throw exception if out of range |
| } |
| |
| /** |
| * The default table for exandedNameID lookups. |
| */ |
| private ExpandedNameTable m_expandedNameTable = |
| new ExpandedNameTable(); |
| |
| /** |
| * Constructor DTMManagerDefault |
| * |
| */ |
| public DTMManagerDefault(){} |
| |
| |
| /** |
| * Get an instance of a DTM, loaded with the content from the |
| * specified source. If the unique flag is true, a new instance will |
| * always be returned. Otherwise it is up to the DTMManager to return a |
| * new instance or an instance that it already created and may be being used |
| * by someone else. |
| * |
| * A bit of magic in this implementation: If the source is null, unique is true, |
| * and incremental and doIndexing are both false, we return an instance of |
| * SAX2RTFDTM, which see. |
| * |
| * (I think more parameters will need to be added for error handling, and entity |
| * resolution, and more explicit control of the RTF situation). |
| * |
| * @param source the specification of the source object. |
| * @param unique true if the returned DTM must be unique, probably because it |
| * is going to be mutated. |
| * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may |
| * be null. |
| * @param incremental true if the DTM should be built incrementally, if |
| * possible. |
| * @param doIndexing true if the caller considers it worth it to use |
| * indexing schemes. |
| * |
| * @return a non-null DTM reference. |
| */ |
| synchronized public DTM getDTM(Source source, boolean unique, |
| DTMWSFilter whiteSpaceFilter, |
| boolean incremental, boolean doIndexing) |
| { |
| |
| if(DEBUG && null != source) |
| System.out.println("Starting "+ |
| (unique ? "UNIQUE" : "shared")+ |
| " source: "+source.getSystemId() |
| ); |
| |
| XMLStringFactory xstringFactory = m_xsf; |
| int dtmPos = getFirstFreeDTMID(); |
| int documentID = dtmPos << IDENT_DTM_NODE_BITS; |
| |
| if ((null != source) && source instanceof DOMSource) |
| { |
| DOM2DTM dtm = new DOM2DTM(this, (DOMSource) source, documentID, |
| whiteSpaceFilter, xstringFactory, doIndexing); |
| |
| addDTM(dtm, dtmPos, 0); |
| |
| // if (DUMPTREE) |
| // { |
| // dtm.dumpDTM(); |
| // } |
| |
| return dtm; |
| } |
| else |
| { |
| boolean isSAXSource = (null != source) |
| ? (source instanceof SAXSource) : true; |
| boolean isStreamSource = (null != source) |
| ? (source instanceof StreamSource) : false; |
| |
| if (isSAXSource || isStreamSource) |
| { |
| XMLReader reader; |
| InputSource xmlSource; |
| |
| if (null == source) |
| { |
| xmlSource = null; |
| reader = null; |
| } |
| else |
| { |
| reader = getXMLReader(source); |
| xmlSource = SAXSource.sourceToInputSource(source); |
| |
| String urlOfSource = xmlSource.getSystemId(); |
| |
| if (null != urlOfSource) |
| { |
| try |
| { |
| urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource); |
| } |
| catch (Exception e) |
| { |
| |
| // %REVIEW% Is there a better way to send a warning? |
| System.err.println("Can not absolutize URL: " + urlOfSource); |
| } |
| |
| xmlSource.setSystemId(urlOfSource); |
| } |
| } |
| |
| SAX2DTM dtm; |
| if(source==null && unique && !incremental && !doIndexing) |
| { |
| // Special case to support RTF construction into shared DTM. |
| // It should actually still work for other uses, |
| // but may be slightly deoptimized relative to the base |
| // to allow it to deal with carrying multiple documents. |
| // |
| // %REVIEW% This is a sloppy way to request this mode; |
| // we need to consider architectural improvements. |
| dtm = new SAX2RTFDTM(this, source, documentID, whiteSpaceFilter, |
| xstringFactory, doIndexing); |
| } |
| /************************************************************** |
| // EXPERIMENTAL 3/22/02 |
| else if(JKESS_XNI_EXPERIMENT && m_incremental) |
| { |
| dtm = new XNI2DTM(this, source, documentID, whiteSpaceFilter, |
| xstringFactory, doIndexing); |
| } |
| **************************************************************/ |
| else // Create the basic SAX2DTM. |
| { |
| dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter, |
| xstringFactory, doIndexing); |
| } |
| |
| // Go ahead and add the DTM to the lookup table. This needs to be |
| // done before any parsing occurs. Note offset 0, since we've just |
| // created a new DTM. |
| addDTM(dtm, dtmPos, 0); |
| |
| |
| boolean haveXercesParser = |
| (null != reader) |
| && (reader.getClass().getName().equals("org.apache.xerces.parsers.SAXParser") ); |
| |
| if (haveXercesParser) |
| incremental = true; // No matter what. %REVIEW% |
| |
| // If the reader is null, but they still requested an incremental build, |
| // then we still want to set up the IncrementalSAXSource stuff. |
| if (this.m_incremental && incremental /* || ((null == reader) && incremental) */) |
| { |
| IncrementalSAXSource coParser=null; |
| |
| if (haveXercesParser) |
| { |
| // IncrementalSAXSource_Xerces to avoid threading. |
| try { |
| // Removing Xerces compile time dependency |
| // coParser=org.apache.xml.dtm.ref.IncrementalSAXSource_Xerces.createIncrementalSAXSource(); |
| coParser =(IncrementalSAXSource)Class.forName("org.apache.xml.dtm.ref.IncrementalSAXSource_Xerces").newInstance(); |
| } catch( Exception ex ) { |
| ex.printStackTrace(); |
| coParser=null; |
| } |
| } |
| |
| if( coParser==null ) { |
| // Create a IncrementalSAXSource that will run on the secondary thread. |
| if (null == reader) |
| coParser = new IncrementalSAXSource_Filter(); |
| else |
| { |
| IncrementalSAXSource_Filter filter=new IncrementalSAXSource_Filter(); |
| filter.setXMLReader(reader); |
| coParser=filter; |
| } |
| |
| } |
| |
| |
| /************************************************************** |
| // EXPERIMENTAL 3/22/02 |
| if(JKESS_XNI_EXPERIMENT && m_incremental & |
| dtm instanceof XNI2DTM && |
| coParser instanceof IncrementalSAXSource_Xerces) |
| { |
| org.apache.xerces.xni.parser.XMLPullParserConfiguration xpc= |
| ((IncrementalSAXSource_Xerces)coParser).getXNIParserConfiguration(); |
| if(xpc!=null) |
| // Bypass SAX; listen to the XNI stream |
| ((XNI2DTM)dtm).setIncrementalXNISource(xpc); |
| else |
| // Listen to the SAX stream (will fail, diagnostically...) |
| dtm.setIncrementalSAXSource(coParser); |
| } else |
| ***************************************************************/ |
| |
| // Have the DTM set itself up as the IncrementalSAXSource's listener. |
| dtm.setIncrementalSAXSource(coParser); |
| |
| if (null == xmlSource) |
| { |
| |
| // Then the user will construct it themselves. |
| return dtm; |
| } |
| |
| if(null == reader.getErrorHandler()) |
| reader.setErrorHandler(dtm); |
| reader.setDTDHandler(dtm); |
| |
| try |
| { |
| |
| // Launch parsing coroutine. Launches a second thread, |
| // if we're using IncrementalSAXSource.filter(). |
| coParser.startParse(xmlSource); |
| } |
| catch (RuntimeException re) |
| { |
| |
| dtm.clearCoRoutine(); |
| |
| throw re; |
| } |
| catch (Exception e) |
| { |
| |
| dtm.clearCoRoutine(); |
| |
| throw new org.apache.xml.utils.WrappedRuntimeException(e); |
| } |
| } |
| else |
| { |
| if (null == reader) |
| { |
| |
| // Then the user will construct it themselves. |
| return dtm; |
| } |
| |
| // not incremental |
| reader.setContentHandler(dtm); |
| reader.setDTDHandler(dtm); |
| if(null == reader.getErrorHandler()) |
| reader.setErrorHandler(dtm); |
| |
| try |
| { |
| reader.setProperty( |
| "http://xml.org/sax/properties/lexical-handler", dtm); |
| } |
| catch (SAXNotRecognizedException e){} |
| catch (SAXNotSupportedException e){} |
| |
| try |
| { |
| reader.parse(xmlSource); |
| } |
| catch (RuntimeException re) |
| { |
| |
| dtm.clearCoRoutine(); |
| |
| throw re; |
| } |
| catch (Exception e) |
| { |
| |
| dtm.clearCoRoutine(); |
| |
| throw new org.apache.xml.utils.WrappedRuntimeException(e); |
| } |
| } |
| |
| if (DUMPTREE) |
| { |
| System.out.println("Dumping SAX2DOM"); |
| dtm.dumpDTM(System.err); |
| } |
| |
| return dtm; |
| } |
| else |
| { |
| |
| // It should have been handled by a derived class or the caller |
| // made a mistake. |
| throw new DTMException(XSLMessages.createMessage(XSLTErrorResources.ER_NOT_SUPPORTED, new Object[]{source})); //"Not supported: " + source); |
| } |
| } |
| } |
| |
| /** |
| * Given a W3C DOM node, try and return a DTM handle. |
| * Note: calling this may be non-optimal, and there is no guarantee that |
| * the node will be found in any particular DTM. |
| * |
| * @param node Non-null reference to a DOM node. |
| * |
| * @return a valid DTM handle. |
| */ |
| synchronized public int getDTMHandleFromNode(org.w3c.dom.Node node) |
| { |
| if(null == node) |
| throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NODE_NON_NULL, null)); //"node must be non-null for getDTMHandleFromNode!"); |
| |
| if (node instanceof org.apache.xml.dtm.ref.DTMNodeProxy) |
| return ((org.apache.xml.dtm.ref.DTMNodeProxy) node).getDTMNodeNumber(); |
| |
| else |
| { |
| // Find the DOM2DTMs wrapped around this Document (if any) |
| // and check whether they contain the Node in question. |
| // |
| // NOTE that since a DOM2DTM may represent a subtree rather |
| // than a full document, we have to be prepared to check more |
| // than one -- and there is no guarantee that we will find |
| // one that contains ancestors or siblings of the node we're |
| // seeking. |
| // |
| // %REVIEW% We could search for the one which contains this |
| // node at the deepest level, and thus covers the widest |
| // subtree, but that's going to entail additional work |
| // checking more DTMs... and getHandleOfNode is not a |
| // cheap operation in most implementations. |
| // |
| // TODO: %REVIEW% If overflow addressing, we may recheck a DTM |
| // already examined. Ouch. But with the increased number of DTMs, |
| // scanning back to check this is painful. |
| // POSSIBLE SOLUTIONS: |
| // Generate a list of _unique_ DTM objects? |
| // Have each DTM cache last DOM node search? |
| int max = m_dtms.length; |
| for(int i = 0; i < max; i++) |
| { |
| DTM thisDTM=m_dtms[i]; |
| if((null != thisDTM) && thisDTM instanceof DOM2DTM) |
| { |
| int handle=((DOM2DTM)thisDTM).getHandleOfNode(node); |
| if(handle!=DTM.NULL) return handle; |
| } |
| } |
| |
| // Not found; generate a new DTM. |
| // |
| // %REVIEW% Is this really desirable, or should we return null |
| // and make folks explicitly instantiate from a DOMSource? The |
| // latter is more work but gives the caller the opportunity to |
| // explicitly add the DTM to a DTMManager... and thus to know when |
| // it can be discarded again, which is something we need to pay much |
| // more attention to. (Especially since only DTMs which are assigned |
| // to a manager can use the overflow addressing scheme.) |
| // |
| // %BUG% If the source node was a DOM2DTM$defaultNamespaceDeclarationNode |
| // and the DTM wasn't registered with this DTMManager, we will create |
| // a new DTM and _still_ not be able to find the node (since it will |
| // be resynthesized). Another reason to push hard on making all DTMs |
| // be managed DTMs. |
| |
| // Since the real root of our tree may be a DocumentFragment, we need to |
| // use getParent to find the root, instead of getOwnerDocument. Otherwise |
| // DOM2DTM#getHandleOfNode will be very unhappy. |
| Node root = node; |
| Node p = (root.getNodeType() == Node.ATTRIBUTE_NODE) ? ((org.w3c.dom.Attr)root).getOwnerElement() : root.getParentNode(); |
| for (; p != null; p = p.getParentNode()) |
| { |
| root = p; |
| } |
| |
| DOM2DTM dtm = (DOM2DTM) getDTM(new javax.xml.transform.dom.DOMSource(root), |
| false, null, true, true); |
| |
| int handle; |
| |
| if(node instanceof org.apache.xml.dtm.ref.dom2dtm.DOM2DTMdefaultNamespaceDeclarationNode) |
| { |
| // Can't return the same node since it's unique to a specific DTM, |
| // but can return the equivalent node -- find the corresponding |
| // Document Element, then ask it for the xml: namespace decl. |
| handle=dtm.getHandleOfNode(((org.w3c.dom.Attr)node).getOwnerElement()); |
| handle=dtm.getAttributeNode(handle,node.getNamespaceURI(),node.getLocalName()); |
| } |
| else |
| handle = ((DOM2DTM)dtm).getHandleOfNode(node); |
| |
| if(DTM.NULL == handle) |
| throw new RuntimeException(XSLMessages.createMessage(XSLTErrorResources.ER_COULD_NOT_RESOLVE_NODE, null)); //"Could not resolve the node to a handle!"); |
| |
| return handle; |
| } |
| } |
| |
| /** |
| * This method returns the SAX2 parser to use with the InputSource |
| * obtained from this URI. |
| * It may return null if any SAX2-conformant XML parser can be used, |
| * or if getInputSource() will also return null. The parser must |
| * be free for use (i.e. |
| * not currently in use for another parse(). |
| * |
| * @param inputSource The value returned from the URIResolver. |
| * @returns a SAX2 XMLReader to use to resolve the inputSource argument. |
| * |
| * @return non-null XMLReader reference ready to parse. |
| */ |
| synchronized public XMLReader getXMLReader(Source inputSource) |
| { |
| |
| try |
| { |
| XMLReader reader = (inputSource instanceof SAXSource) |
| ? ((SAXSource) inputSource).getXMLReader() : null; |
| |
| boolean isUserReader = (reader != null); |
| |
| if (null == reader) |
| { |
| try |
| { |
| javax.xml.parsers.SAXParserFactory factory = |
| javax.xml.parsers.SAXParserFactory.newInstance(); |
| |
| factory.setNamespaceAware(true); |
| |
| javax.xml.parsers.SAXParser jaxpParser = factory.newSAXParser(); |
| |
| reader = jaxpParser.getXMLReader(); |
| } |
| catch (javax.xml.parsers.ParserConfigurationException ex) |
| { |
| throw new org.xml.sax.SAXException(ex); |
| } |
| catch (javax.xml.parsers.FactoryConfigurationError ex1) |
| { |
| throw new org.xml.sax.SAXException(ex1.toString()); |
| } |
| catch (NoSuchMethodError ex2){} |
| catch (AbstractMethodError ame){} |
| |
| if (null == reader) |
| reader = XMLReaderFactory.createXMLReader(); |
| } |
| |
| try |
| { |
| reader.setFeature("http://xml.org/sax/features/namespace-prefixes", |
| true); |
| } |
| catch (org.xml.sax.SAXException se) |
| { |
| |
| // What can we do? |
| // TODO: User diagnostics. |
| } |
| |
| // Commented out as per discussion with Thomas2.Maesing@bgs-ag.de |
| // about bug 2124. |
| // if(!isUserReader) |
| // { |
| // try |
| // { |
| // reader.setFeature("http://apache.org/xml/features/validation/dynamic", |
| // true); |
| // } |
| // catch (org.xml.sax.SAXException se) |
| // { |
| // |
| // // What can we do? |
| // // TODO: User diagnostics. |
| // } |
| // } |
| |
| return reader; |
| } |
| catch (org.xml.sax.SAXException se) |
| { |
| throw new DTMException(se.getMessage(), se); |
| } |
| } |
| |
| /** |
| * Return the DTM object containing a representation of this node. |
| * |
| * @param nodeHandle DTM Handle indicating which node to retrieve |
| * |
| * @return a reference to the DTM object containing this node. |
| */ |
| synchronized public DTM getDTM(int nodeHandle) |
| { |
| try |
| { |
| // Performance critical function. |
| return m_dtms[nodeHandle >>> IDENT_DTM_NODE_BITS]; |
| } |
| catch(java.lang.ArrayIndexOutOfBoundsException e) |
| { |
| if(nodeHandle==DTM.NULL) |
| return null; // Accept as a special case. |
| else |
| throw e; // Programming error; want to know about it. |
| } |
| } |
| |
| /** |
| * Given a DTM, find the ID number in the DTM tables which addresses |
| * the start of the document. If overflow addressing is in use, other |
| * DTM IDs may also be assigned to this DTM. |
| * |
| * @param dtm The DTM which (hopefully) contains this node. |
| * |
| * @return The DTM ID (as the high bits of a NodeHandle, not as our |
| * internal index), or -1 if the DTM doesn't belong to this manager. |
| */ |
| synchronized public int getDTMIdentity(DTM dtm) |
| { |
| // Shortcut using DTMDefaultBase's extension hooks |
| // %REVIEW% Should the lookup be part of the basic DTM API? |
| if(dtm instanceof DTMDefaultBase) |
| { |
| DTMDefaultBase dtmdb=(DTMDefaultBase)dtm; |
| if(dtmdb.getManager()==this) |
| return dtmdb.getDTMIDs().elementAt(0); |
| else |
| return -1; |
| } |
| |
| int n = m_dtms.length; |
| |
| for (int i = 0; i < n; i++) |
| { |
| DTM tdtm = m_dtms[i]; |
| |
| if (tdtm == dtm && m_dtm_offsets[i]==0) |
| return i << IDENT_DTM_NODE_BITS; |
| } |
| |
| return -1; |
| } |
| |
| /** |
| * Release the DTMManager's reference(s) to a DTM, making it unmanaged. |
| * This is typically done as part of returning the DTM to the heap after |
| * we're done with it. |
| * |
| * @param dtm the DTM to be released. |
| * |
| * @param shouldHardDelete If false, this call is a suggestion rather than an |
| * order, and we may not actually release the DTM. This is intended to |
| * support intelligent caching of documents... which is not implemented |
| * in this version of the DTM manager. |
| * |
| * @return true if the DTM was released, false if shouldHardDelete was set |
| * and we decided not to. |
| */ |
| synchronized public boolean release(DTM dtm, boolean shouldHardDelete) |
| { |
| if(DEBUG) |
| { |
| System.out.println("Releasing "+ |
| (shouldHardDelete ? "HARD" : "soft")+ |
| " dtm="+ |
| // Following shouldn't need a nodeHandle, but does... |
| // and doesn't seem to report the intended value |
| dtm.getDocumentBaseURI() |
| ); |
| } |
| |
| if (dtm instanceof SAX2DTM) |
| { |
| ((SAX2DTM) dtm).clearCoRoutine(); |
| } |
| |
| // Multiple DTM IDs may be assigned to a single DTM. |
| // The Right Answer is to ask which (if it supports |
| // extension, the DTM will need a list anyway). The |
| // Wrong Answer, applied if the DTM can't help us, |
| // is to linearly search them all; this may be very |
| // painful. |
| // |
| // %REVIEW% Should the lookup move up into the basic DTM API? |
| if(dtm instanceof DTMDefaultBase) |
| { |
| org.apache.xml.utils.SuballocatedIntVector ids=((DTMDefaultBase)dtm).getDTMIDs(); |
| for(int i=ids.size()-1;i>=0;--i) |
| m_dtms[ids.elementAt(i)>>>DTMManager.IDENT_DTM_NODE_BITS]=null; |
| } |
| else |
| { |
| int i = getDTMIdentity(dtm); |
| if (i >= 0) |
| { |
| m_dtms[i >>> DTMManager.IDENT_DTM_NODE_BITS] = null; |
| } |
| } |
| |
| dtm.documentRelease(); |
| return true; |
| } |
| |
| /** |
| * Method createDocumentFragment |
| * |
| * |
| * NEEDSDOC (createDocumentFragment) @return |
| */ |
| synchronized public DTM createDocumentFragment() |
| { |
| |
| try |
| { |
| DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); |
| |
| dbf.setNamespaceAware(true); |
| |
| DocumentBuilder db = dbf.newDocumentBuilder(); |
| Document doc = db.newDocument(); |
| Node df = doc.createDocumentFragment(); |
| |
| return getDTM(new DOMSource(df), true, null, false, false); |
| } |
| catch (Exception e) |
| { |
| throw new DTMException(e); |
| } |
| } |
| |
| /** |
| * NEEDSDOC Method createDTMIterator |
| * |
| * |
| * NEEDSDOC @param whatToShow |
| * NEEDSDOC @param filter |
| * NEEDSDOC @param entityReferenceExpansion |
| * |
| * NEEDSDOC (createDTMIterator) @return |
| */ |
| synchronized public DTMIterator createDTMIterator(int whatToShow, DTMFilter filter, |
| boolean entityReferenceExpansion) |
| { |
| |
| /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */ |
| return null; |
| } |
| |
| /** |
| * NEEDSDOC Method createDTMIterator |
| * |
| * |
| * NEEDSDOC @param xpathString |
| * NEEDSDOC @param presolver |
| * |
| * NEEDSDOC (createDTMIterator) @return |
| */ |
| synchronized public DTMIterator createDTMIterator(String xpathString, |
| PrefixResolver presolver) |
| { |
| |
| /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */ |
| return null; |
| } |
| |
| /** |
| * NEEDSDOC Method createDTMIterator |
| * |
| * |
| * NEEDSDOC @param node |
| * |
| * NEEDSDOC (createDTMIterator) @return |
| */ |
| synchronized public DTMIterator createDTMIterator(int node) |
| { |
| |
| /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */ |
| return null; |
| } |
| |
| /** |
| * NEEDSDOC Method createDTMIterator |
| * |
| * |
| * NEEDSDOC @param xpathCompiler |
| * NEEDSDOC @param pos |
| * |
| * NEEDSDOC (createDTMIterator) @return |
| */ |
| synchronized public DTMIterator createDTMIterator(Object xpathCompiler, int pos) |
| { |
| |
| /** @todo: implement this org.apache.xml.dtm.DTMManager abstract method */ |
| return null; |
| } |
| |
| /** |
| * return the expanded name table. |
| * |
| * NEEDSDOC @param dtm |
| * |
| * NEEDSDOC ($objectName$) @return |
| */ |
| public ExpandedNameTable getExpandedNameTable(DTM dtm) |
| { |
| return m_expandedNameTable; |
| } |
| } |