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