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 */
21package org.apache.xml.dtm;
22
23import org.apache.xml.res.XMLErrorResources;
24import org.apache.xml.res.XMLMessages;
25import org.apache.xml.utils.PrefixResolver;
26import 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 */
48public 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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
408  public abstract int getDTMIdentity(DTM dtm);
409
410  /**
411   * %TBD% Doc
412   *
413   * NEEDSDOC ($objectName$) @return
414   */
415  public int getDTMIdentityMask()
416  {
417    return IDENT_DTM_DEFAULT;
418  }
419
420  /**
421   * %TBD% Doc
422   *
423   * NEEDSDOC ($objectName$) @return
424   */
425  public int getNodeIdentityMask()
426  {
427    return IDENT_NODE_DEFAULT;
428  }
429
430}
431