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: DTMManager.java 468653 2006-10-28 07:07:05Z minchau $
020 */
021 package org.apache.xml.dtm;
022
023 import org.apache.xml.res.XMLErrorResources;
024 import org.apache.xml.res.XMLMessages;
025 import org.apache.xml.utils.PrefixResolver;
026 import org.apache.xml.utils.XMLStringFactory;
027
028 /**
029 * A DTMManager instance can be used to create DTM and
030 * DTMIterator objects, and manage the DTM objects in the system.
031 *
032 * <p>The system property that determines which Factory implementation
033 * to create is named "org.apache.xml.utils.DTMFactory". This
034 * property names a concrete subclass of the DTMFactory abstract
035 * class. If the property is not defined, a platform default is be used.</p>
036 *
037 * <p>An instance of this class <emph>must</emph> be safe to use across
038 * thread instances. It is expected that a client will create a single instance
039 * of a DTMManager to use across multiple threads. This will allow sharing
040 * of DTMs across multiple processes.</p>
041 *
042 * <p>Note: this class is incomplete right now. It will be pretty much
043 * modeled after javax.xml.transform.TransformerFactory in terms of its
044 * factory support.</p>
045 *
046 * <p>State: In progress!!</p>
047 */
048 public abstract class DTMManager
049 {
050
051 /** The default property name to load the manager. */
052 private static final String defaultPropName =
053 "org.apache.xml.dtm.DTMManager";
054
055 /** The default class name to use as the manager. */
056 private static String defaultClassName =
057 "org.apache.xml.dtm.ref.DTMManagerDefault";
058
059 /**
060 * Factory for creating XMLString objects.
061 * %TBD% Make this set by the caller.
062 */
063 protected XMLStringFactory m_xsf = null;
064
065 /**
066 * Default constructor is protected on purpose.
067 */
068 protected DTMManager(){}
069
070 /**
071 * Get the XMLStringFactory used for the DTMs.
072 *
073 *
074 * @return a valid XMLStringFactory object, or null if it hasn't been set yet.
075 */
076 public XMLStringFactory getXMLStringFactory()
077 {
078 return m_xsf;
079 }
080
081 /**
082 * Set the XMLStringFactory used for the DTMs.
083 *
084 *
085 * @param xsf a valid XMLStringFactory object, should not be null.
086 */
087 public void setXMLStringFactory(XMLStringFactory xsf)
088 {
089 m_xsf = xsf;
090 }
091
092 /**
093 * Obtain a new instance of a <code>DTMManager</code>.
094 * This static method creates a new factory instance
095 * This method uses the following ordered lookup procedure to determine
096 * the <code>DTMManager</code> implementation class to
097 * load:
098 * <ul>
099 * <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 }