Home | History | Annotate | Download | only in dtm
      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  */
     21 package org.apache.xml.dtm;
     22 
     23 import org.apache.xml.res.XMLErrorResources;
     24 import org.apache.xml.res.XMLMessages;
     25 import org.apache.xml.utils.PrefixResolver;
     26 import 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  */
     48 public 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