1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id: DTMManager.java 468653 2006-10-28 07:07:05Z minchau $
20  */
21 package org.apache.xml.dtm;
22 
23 import org.apache.xml.res.XMLErrorResources;
24 import org.apache.xml.res.XMLMessages;
25 import org.apache.xml.utils.PrefixResolver;
26 import org.apache.xml.utils.XMLStringFactory;
27 
28 /**
29  * A DTMManager instance can be used to create DTM and
30  * DTMIterator objects, and manage the DTM objects in the system.
31  *
32  * <p>The system property that determines which Factory implementation
33  * to create is named "org.apache.xml.utils.DTMFactory". This
34  * property names a concrete subclass of the DTMFactory abstract
35  *  class. If the property is not defined, a platform default is be used.</p>
36  *
37  * <p>An instance of this class <emph>must</emph> be safe to use across
38  * thread instances.  It is expected that a client will create a single instance
39  * of a DTMManager to use across multiple threads.  This will allow sharing
40  * of DTMs across multiple processes.</p>
41  *
42  * <p>Note: this class is incomplete right now.  It will be pretty much
43  * modeled after javax.xml.transform.TransformerFactory in terms of its
44  * factory support.</p>
45  *
46  * <p>State: In progress!!</p>
47  */
48 public abstract class DTMManager
49 {
50 
51   /** The default property name to load the manager. */
52   private static final String defaultPropName =
53     "org.apache.xml.dtm.DTMManager";
54 
55   /** The default class name to use as the manager. */
56   private static String defaultClassName =
57     "org.apache.xml.dtm.ref.DTMManagerDefault";
58 
59   /**
60    * Factory for creating XMLString objects.
61    *  %TBD% Make this set by the caller.
62    */
63   protected XMLStringFactory m_xsf = null;
64 
65   /**
66    * Default constructor is protected on purpose.
67    */
DTMManager()68   protected DTMManager(){}
69 
70   /**
71    * Get the XMLStringFactory used for the DTMs.
72    *
73    *
74    * @return a valid XMLStringFactory object, or null if it hasn't been set yet.
75    */
getXMLStringFactory()76   public XMLStringFactory getXMLStringFactory()
77   {
78     return m_xsf;
79   }
80 
81   /**
82    * Set the XMLStringFactory used for the DTMs.
83    *
84    *
85    * @param xsf a valid XMLStringFactory object, should not be null.
86    */
setXMLStringFactory(XMLStringFactory xsf)87   public void setXMLStringFactory(XMLStringFactory xsf)
88   {
89     m_xsf = xsf;
90   }
91 
92   /**
93    * Obtain a new instance of a <code>DTMManager</code>.
94    * This static method creates a new factory instance
95    * This method uses the following ordered lookup procedure to determine
96    * the <code>DTMManager</code> implementation class to
97    * load:
98    * <ul>
99    * <li>
100    * Use the <code>org.apache.xml.dtm.DTMManager</code> system
101    * property.
102    * </li>
103    * <li>
104    * Use the JAVA_HOME(the parent directory where jdk is
105    * installed)/lib/xalan.properties for a property file that contains the
106    * name of the implementation class keyed on the same value as the
107    * system property defined above.
108    * </li>
109    * <li>
110    * Use the Services API (as detailed in the JAR specification), if
111    * available, to determine the classname. The Services API will look
112    * for a classname in the file
113    * <code>META-INF/services/org.apache.xml.dtm.DTMManager</code>
114    * in jars available to the runtime.
115    * </li>
116    * <li>
117    * Use the default <code>DTMManager</code> classname, which is
118    * <code>org.apache.xml.dtm.ref.DTMManagerDefault</code>.
119    * </li>
120    * </ul>
121    *
122    * Once an application has obtained a reference to a <code>
123    * DTMManager</code> it can use the factory to configure
124    * and obtain parser instances.
125    *
126    * @return new DTMManager instance, never null.
127    *
128    * @throws DTMConfigurationException
129    * if the implementation is not available or cannot be instantiated.
130    */
newInstance(XMLStringFactory xsf)131   public static DTMManager newInstance(XMLStringFactory xsf)
132            throws DTMConfigurationException
133   {
134     DTMManager factoryImpl = null;
135     try
136     {
137       factoryImpl = (DTMManager) ObjectFactory
138         .createObject(defaultPropName, defaultClassName);
139     }
140     catch (ObjectFactory.ConfigurationError e)
141     {
142       throw new DTMConfigurationException(XMLMessages.createXMLMessage(
143         XMLErrorResources.ER_NO_DEFAULT_IMPL, null), e.getException());
144         //"No default implementation found");
145     }
146 
147     if (factoryImpl == null)
148     {
149       throw new DTMConfigurationException(XMLMessages.createXMLMessage(
150         XMLErrorResources.ER_NO_DEFAULT_IMPL, null));
151         //"No default implementation found");
152     }
153 
154     factoryImpl.setXMLStringFactory(xsf);
155 
156     return factoryImpl;
157   }
158 
159   /**
160    * Get an instance of a DTM, loaded with the content from the
161    * specified source.  If the unique flag is true, a new instance will
162    * always be returned.  Otherwise it is up to the DTMManager to return a
163    * new instance or an instance that it already created and may be being used
164    * by someone else.
165    *
166    * (More parameters may eventually need to be added for error handling
167    * and entity resolution, and to better control selection of implementations.)
168    *
169    * @param source the specification of the source object, which may be null,
170    *               in which case it is assumed that node construction will take
171    *               by some other means.
172    * @param unique true if the returned DTM must be unique, probably because it
173    * is going to be mutated.
174    * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
175    *                         be null.
176    * @param incremental true if the DTM should be built incrementally, if
177    *                    possible.
178    * @param doIndexing true if the caller considers it worth it to use
179    *                   indexing schemes.
180    *
181    * @return a non-null DTM reference.
182    */
getDTM(javax.xml.transform.Source source, boolean unique, DTMWSFilter whiteSpaceFilter, boolean incremental, boolean doIndexing)183   public abstract DTM getDTM(javax.xml.transform.Source source,
184                              boolean unique, DTMWSFilter whiteSpaceFilter,
185                              boolean incremental, boolean doIndexing);
186 
187   /**
188    * Get the instance of DTM that "owns" a node handle.
189    *
190    * @param nodeHandle the nodeHandle.
191    *
192    * @return a non-null DTM reference.
193    */
getDTM(int nodeHandle)194   public abstract DTM getDTM(int nodeHandle);
195 
196   /**
197    * Given a W3C DOM node, try and return a DTM handle.
198    * Note: calling this may be non-optimal.
199    *
200    * @param node Non-null reference to a DOM node.
201    *
202    * @return a valid DTM handle.
203    */
getDTMHandleFromNode(org.w3c.dom.Node node)204   public abstract int getDTMHandleFromNode(org.w3c.dom.Node node);
205 
206   /**
207    * Creates a DTM representing an empty <code>DocumentFragment</code> object.
208    * @return a non-null DTM reference.
209    */
createDocumentFragment()210   public abstract DTM createDocumentFragment();
211 
212   /**
213    * Release a DTM either to a lru pool, or completely remove reference.
214    * DTMs without system IDs are always hard deleted.
215    * State: experimental.
216    *
217    * @param dtm The DTM to be released.
218    * @param shouldHardDelete True if the DTM should be removed no matter what.
219    * @return true if the DTM was removed, false if it was put back in a lru pool.
220    */
release(DTM dtm, boolean shouldHardDelete)221   public abstract boolean release(DTM dtm, boolean shouldHardDelete);
222 
223   /**
224    * Create a new <code>DTMIterator</code> based on an XPath
225    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
226    * a <a href="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
227    *
228    * @param xpathCompiler ??? Somehow we need to pass in a subpart of the
229    * expression.  I hate to do this with strings, since the larger expression
230    * has already been parsed.
231    *
232    * @param pos The position in the expression.
233    * @return The newly created <code>DTMIterator</code>.
234    */
createDTMIterator(Object xpathCompiler, int pos)235   public abstract DTMIterator createDTMIterator(Object xpathCompiler,
236           int pos);
237 
238   /**
239    * Create a new <code>DTMIterator</code> based on an XPath
240    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
241    * a <a href="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
242    *
243    * @param xpathString Must be a valid string expressing a
244    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
245    * a <a href="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
246    *
247    * @param presolver An object that can resolve prefixes to namespace URLs.
248    *
249    * @return The newly created <code>DTMIterator</code>.
250    */
createDTMIterator(String xpathString, PrefixResolver presolver)251   public abstract DTMIterator createDTMIterator(String xpathString,
252           PrefixResolver presolver);
253 
254   /**
255    * Create a new <code>DTMIterator</code> based only on a whatToShow
256    * and a DTMFilter.  The traversal semantics are defined as the
257    * descendant access.
258    * <p>
259    * Note that DTMIterators may not be an exact match to DOM
260    * NodeIterators. They are initialized and used in much the same way
261    * as a NodeIterator, but their response to document mutation is not
262    * currently defined.
263    *
264    * @param whatToShow This flag specifies which node types may appear in
265    *   the logical view of the tree presented by the iterator. See the
266    *   description of <code>NodeFilter</code> for the set of possible
267    *   <code>SHOW_</code> values.These flags can be combined using
268    *   <code>OR</code>.
269    * @param filter The <code>NodeFilter</code> to be used with this
270    *   <code>DTMFilter</code>, or <code>null</code> to indicate no filter.
271    * @param entityReferenceExpansion The value of this flag determines
272    *   whether entity reference nodes are expanded.
273    *
274    * @return The newly created <code>DTMIterator</code>.
275    */
createDTMIterator(int whatToShow, DTMFilter filter, boolean entityReferenceExpansion)276   public abstract DTMIterator createDTMIterator(int whatToShow,
277           DTMFilter filter, boolean entityReferenceExpansion);
278 
279   /**
280    * Create a new <code>DTMIterator</code> that holds exactly one node.
281    *
282    * @param node The node handle that the DTMIterator will iterate to.
283    *
284    * @return The newly created <code>DTMIterator</code>.
285    */
createDTMIterator(int node)286   public abstract DTMIterator createDTMIterator(int node);
287 
288   /* Flag indicating whether an incremental transform is desired */
289   public boolean m_incremental = false;
290 
291   /*
292    * Flag set by FEATURE_SOURCE_LOCATION.
293    * This feature specifies whether the transformation phase should
294    * keep track of line and column numbers for the input source
295    * document.
296    */
297   public boolean m_source_location = false;
298 
299   /**
300    * Get a flag indicating whether an incremental transform is desired
301    * @return incremental boolean.
302    *
303    */
getIncremental()304   public boolean getIncremental()
305   {
306     return m_incremental;
307   }
308 
309   /**
310    * Set a flag indicating whether an incremental transform is desired
311    * This flag should have the same value as the FEATURE_INCREMENTAL feature
312    * which is set by the TransformerFactory.setAttribut() method before a
313    * DTMManager is created
314    * @param incremental boolean to use to set m_incremental.
315    *
316    */
setIncremental(boolean incremental)317   public void setIncremental(boolean incremental)
318   {
319     m_incremental = incremental;
320   }
321 
322   /**
323    * Get a flag indicating whether the transformation phase should
324    * keep track of line and column numbers for the input source
325    * document.
326    * @return source location boolean
327    *
328    */
getSource_location()329   public boolean getSource_location()
330   {
331     return m_source_location;
332   }
333 
334   /**
335    * Set a flag indicating whether the transformation phase should
336    * keep track of line and column numbers for the input source
337    * document.
338    * This flag should have the same value as the FEATURE_SOURCE_LOCATION feature
339    * which is set by the TransformerFactory.setAttribut() method before a
340    * DTMManager is created
341    * @param sourceLocation boolean to use to set m_source_location
342    */
setSource_location(boolean sourceLocation)343   public void setSource_location(boolean sourceLocation){
344     m_source_location = sourceLocation;
345   }
346 
347 
348   // -------------------- private methods --------------------
349 
350    /**
351    * Temp debug code - this will be removed after we test everything
352    */
353   private static boolean debug;
354 
355   static
356   {
357     try
358     {
359       debug = System.getProperty("dtm.debug") != null;
360     }
361     catch (SecurityException ex){}
362   }
363 
364   /** This value, set at compile time, controls how many bits of the
365    * DTM node identifier numbers are used to identify a node within a
366    * document, and thus sets the maximum number of nodes per
367    * document. The remaining bits are used to identify the DTM
368    * document which contains this node.
369    *
370    * If you change IDENT_DTM_NODE_BITS, be sure to rebuild _ALL_ the
371    * files which use it... including the IDKey testcases.
372    *
373    * (FuncGenerateKey currently uses the node identifier directly and
374    * thus is affected when this changes. The IDKEY results will still be
375    * _correct_ (presuming no other breakage), but simple equality
376    * comparison against the previous "golden" files will probably
377    * complain.)
378    * */
379   public static final int IDENT_DTM_NODE_BITS = 16;
380 
381 
382   /** When this bitmask is ANDed with a DTM node handle number, the result
383    * is the low bits of the node's index number within that DTM. To obtain
384    * the high bits, add the DTM ID portion's offset as assigned in the DTM
385    * Manager.
386    */
387   public static final int IDENT_NODE_DEFAULT = (1<<IDENT_DTM_NODE_BITS)-1;
388 
389 
390   /** When this bitmask is ANDed with a DTM node handle number, the result
391    * is the DTM's document identity number.
392    */
393   public static final int IDENT_DTM_DEFAULT = ~IDENT_NODE_DEFAULT;
394 
395   /** This is the maximum number of DTMs available.  The highest DTM is
396     * one less than this.
397    */
398   public static final int IDENT_MAX_DTMS = (IDENT_DTM_DEFAULT >>> IDENT_DTM_NODE_BITS) + 1;
399 
400 
401   /**
402    * %TBD% Doc
403    *
404    * NEEDSDOC @param dtm
405    *
406    * NEEDSDOC ($objectName$) @return
407    */
getDTMIdentity(DTM dtm)408   public abstract int getDTMIdentity(DTM dtm);
409 
410   /**
411    * %TBD% Doc
412    *
413    * NEEDSDOC ($objectName$) @return
414    */
getDTMIdentityMask()415   public int getDTMIdentityMask()
416   {
417     return IDENT_DTM_DEFAULT;
418   }
419 
420   /**
421    * %TBD% Doc
422    *
423    * NEEDSDOC ($objectName$) @return
424    */
getNodeIdentityMask()425   public int getNodeIdentityMask()
426   {
427     return IDENT_NODE_DEFAULT;
428   }
429 
430 }
431