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 }