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 }