1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 1999-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * 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 /*
  21  * $Id: XSLTCDTMManager.java,v 1.2 2005/08/16 22:32:54 jeffsuttor Exp $
  22  */
  23 package com.sun.org.apache.xalan.internal.xsltc.dom;
  24 
  25 import javax.xml.stream.XMLEventReader;
  26 import javax.xml.stream.XMLStreamReader;
  27 import javax.xml.transform.Source;
  28 import javax.xml.transform.dom.DOMSource;
  29 import javax.xml.transform.sax.SAXSource;
  30 import javax.xml.transform.stream.StreamSource;
  31 import javax.xml.transform.stax.StAXSource;
  32 
  33 import com.sun.org.apache.xml.internal.dtm.DTM;
  34 import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
  35 import com.sun.org.apache.xml.internal.dtm.DTMException;
  36 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  37 import com.sun.org.apache.xml.internal.dtm.ref.DTMManagerDefault;
  38 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
  39 import com.sun.org.apache.xml.internal.res.XMLMessages;
  40 import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
  41 import com.sun.org.apache.xalan.internal.xsltc.trax.DOM2SAX;
  42 import com.sun.org.apache.xalan.internal.xsltc.trax.StAXEvent2SAX;
  43 import com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX;
  44 
  45 import org.xml.sax.InputSource;
  46 import org.xml.sax.SAXNotRecognizedException;
  47 import org.xml.sax.SAXNotSupportedException;
  48 import org.xml.sax.XMLReader;
  49 
  50 /**
  51  * The default implementation for the DTMManager.
  52  */
  53 public class XSLTCDTMManager extends DTMManagerDefault
  54 {
  55 
  56     /** Set this to true if you want a dump of the DTM after creation */
  57     private static final boolean DUMPTREE = false;
  58 
  59     /** Set this to true if you want basic diagnostics */
  60     private static final boolean DEBUG = false;
  61 
  62     /**
  63      * Constructor DTMManagerDefault
  64      *
  65      */
  66     public XSLTCDTMManager()
  67     {
  68         super();
  69     }
  70 
  71     /**
  72      * Obtain a new instance of a <code>DTMManager</code>.
  73      * This static method creates a new factory instance.
  74      * The current implementation just returns a new XSLTCDTMManager instance.
  75      */
  76     public static XSLTCDTMManager newInstance()
  77     {
  78         return new XSLTCDTMManager();
  79     }
  80 
  81     /**
  82      * Creates a new instance of the XSLTC DTM Manager service.
  83      * Creates a new instance of the default class
  84      * <code>com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager</code>.
  85      */
  86       public static XSLTCDTMManager createNewDTMManagerInstance() {
  87          return newInstance();
  88       }
  89 
  90     /**
  91      * Get an instance of a DTM, loaded with the content from the
  92      * specified source.  If the unique flag is true, a new instance will
  93      * always be returned.  Otherwise it is up to the DTMManager to return a
  94      * new instance or an instance that it already created and may be being used
  95      * by someone else.
  96      * (I think more parameters will need to be added for error handling, and
  97      * entity resolution).
  98      *
  99      * @param source the specification of the source object.
 100      * @param unique true if the returned DTM must be unique, probably because it
 101      * is going to be mutated.
 102      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
 103      *                         be null.
 104      * @param incremental true if the DTM should be built incrementally, if
 105      *                    possible.
 106      * @param doIndexing true if the caller considers it worth it to use
 107      *                   indexing schemes.
 108      *
 109      * @return a non-null DTM reference.
 110      */
 111     @Override
 112     public DTM getDTM(Source source, boolean unique,
 113                       DTMWSFilter whiteSpaceFilter, boolean incremental,
 114                       boolean doIndexing)
 115     {
 116         return getDTM(source, unique, whiteSpaceFilter, incremental,
 117                       doIndexing, false, 0, true, false);
 118     }
 119 
 120     /**
 121      * Get an instance of a DTM, loaded with the content from the
 122      * specified source.  If the unique flag is true, a new instance will
 123      * always be returned.  Otherwise it is up to the DTMManager to return a
 124      * new instance or an instance that it already created and may be being used
 125      * by someone else.
 126      * (I think more parameters will need to be added for error handling, and
 127      * entity resolution).
 128      *
 129      * @param source the specification of the source object.
 130      * @param unique true if the returned DTM must be unique, probably because it
 131      * is going to be mutated.
 132      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
 133      *                         be null.
 134      * @param incremental true if the DTM should be built incrementally, if
 135      *                    possible.
 136      * @param doIndexing true if the caller considers it worth it to use
 137      *                   indexing schemes.
 138      * @param buildIdIndex true if the id index table should be built.
 139      *
 140      * @return a non-null DTM reference.
 141      */
 142     public DTM getDTM(Source source, boolean unique,
 143                       DTMWSFilter whiteSpaceFilter, boolean incremental,
 144                       boolean doIndexing, boolean buildIdIndex)
 145     {
 146         return getDTM(source, unique, whiteSpaceFilter, incremental,
 147                       doIndexing, false, 0, buildIdIndex, false);
 148     }
 149 
 150     /**
 151      * Get an instance of a DTM, loaded with the content from the
 152      * specified source.  If the unique flag is true, a new instance will
 153      * always be returned.  Otherwise it is up to the DTMManager to return a
 154      * new instance or an instance that it already created and may be being used
 155      * by someone else.
 156      * (I think more parameters will need to be added for error handling, and
 157      * entity resolution).
 158      *
 159      * @param source the specification of the source object.
 160      * @param unique true if the returned DTM must be unique, probably because it
 161      * is going to be mutated.
 162      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
 163      *                         be null.
 164      * @param incremental true if the DTM should be built incrementally, if
 165      *                    possible.
 166      * @param doIndexing true if the caller considers it worth it to use
 167      *                   indexing schemes.
 168      * @param buildIdIndex true if the id index table should be built.
 169      * @param newNameTable true if we want to use a separate ExpandedNameTable
 170      *                     for this DTM.
 171      *
 172      * @return a non-null DTM reference.
 173      */
 174   public DTM getDTM(Source source, boolean unique,
 175                     DTMWSFilter whiteSpaceFilter, boolean incremental,
 176                     boolean doIndexing, boolean buildIdIndex,
 177                     boolean newNameTable)
 178   {
 179     return getDTM(source, unique, whiteSpaceFilter, incremental,
 180                   doIndexing, false, 0, buildIdIndex, newNameTable);
 181   }
 182 
 183   /**
 184      * Get an instance of a DTM, loaded with the content from the
 185      * specified source.  If the unique flag is true, a new instance will
 186      * always be returned.  Otherwise it is up to the DTMManager to return a
 187      * new instance or an instance that it already created and may be being used
 188      * by someone else.
 189      * (I think more parameters will need to be added for error handling, and
 190      * entity resolution).
 191      *
 192      * @param source the specification of the source object.
 193      * @param unique true if the returned DTM must be unique, probably because it
 194      * is going to be mutated.
 195      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
 196      *                         be null.
 197      * @param incremental true if the DTM should be built incrementally, if
 198      *                    possible.
 199      * @param doIndexing true if the caller considers it worth it to use
 200      *                   indexing schemes.
 201      * @param hasUserReader true if <code>source</code> is a
 202      *                      <code>SAXSource</code> object that has an
 203      *                      <code>XMLReader</code>, that was specified by the
 204      *                      user.
 205      * @param size  Specifies initial size of tables that represent the DTM
 206      * @param buildIdIndex true if the id index table should be built.
 207      *
 208      * @return a non-null DTM reference.
 209      */
 210     public DTM getDTM(Source source, boolean unique,
 211                       DTMWSFilter whiteSpaceFilter, boolean incremental,
 212                       boolean doIndexing, boolean hasUserReader, int size,
 213                       boolean buildIdIndex)
 214     {
 215       return getDTM(source, unique, whiteSpaceFilter, incremental,
 216                     doIndexing, hasUserReader, size,
 217                     buildIdIndex, false);
 218   }
 219 
 220   /**
 221      * Get an instance of a DTM, loaded with the content from the
 222      * specified source.  If the unique flag is true, a new instance will
 223      * always be returned.  Otherwise it is up to the DTMManager to return a
 224      * new instance or an instance that it already created and may be being used
 225      * by someone else.
 226      * (I think more parameters will need to be added for error handling, and
 227      * entity resolution).
 228      *
 229      * @param source the specification of the source object.
 230      * @param unique true if the returned DTM must be unique, probably because it
 231      * is going to be mutated.
 232      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
 233      *                         be null.
 234      * @param incremental true if the DTM should be built incrementally, if
 235      *                    possible.
 236      * @param doIndexing true if the caller considers it worth it to use
 237      *                   indexing schemes.
 238      * @param hasUserReader true if <code>source</code> is a
 239      *                      <code>SAXSource</code> object that has an
 240      *                      <code>XMLReader</code>, that was specified by the
 241      *                      user.
 242      * @param size  Specifies initial size of tables that represent the DTM
 243      * @param buildIdIndex true if the id index table should be built.
 244      * @param newNameTable true if we want to use a separate ExpandedNameTable
 245      *                     for this DTM.
 246      *
 247      * @return a non-null DTM reference.
 248      */
 249   public DTM getDTM(Source source, boolean unique,
 250                     DTMWSFilter whiteSpaceFilter, boolean incremental,
 251                     boolean doIndexing, boolean hasUserReader, int size,
 252                     boolean buildIdIndex, boolean newNameTable)
 253   {
 254         if(DEBUG && null != source) {
 255             System.out.println("Starting "+
 256                          (unique ? "UNIQUE" : "shared")+
 257                          " source: "+source.getSystemId());
 258         }
 259 
 260         int dtmPos = getFirstFreeDTMID();
 261         int documentID = dtmPos << IDENT_DTM_NODE_BITS;
 262 
 263         if ((null != source) && source instanceof StAXSource) {
 264             final StAXSource staxSource = (StAXSource)source;
 265             StAXEvent2SAX staxevent2sax = null;
 266             StAXStream2SAX staxStream2SAX = null;
 267             if (staxSource.getXMLEventReader() != null) {
 268                 final XMLEventReader xmlEventReader = staxSource.getXMLEventReader();
 269                 staxevent2sax = new StAXEvent2SAX(xmlEventReader);
 270             } else if (staxSource.getXMLStreamReader() != null) {
 271                 final XMLStreamReader xmlStreamReader = staxSource.getXMLStreamReader();
 272                 staxStream2SAX = new StAXStream2SAX(xmlStreamReader);
 273             }
 274 
 275             SAXImpl dtm;
 276 
 277             if (size <= 0) {
 278                 dtm = new SAXImpl(this, source, documentID,
 279                                   whiteSpaceFilter, null, doIndexing,
 280                                   DTMDefaultBase.DEFAULT_BLOCKSIZE,
 281                                   buildIdIndex, newNameTable);
 282             } else {
 283                 dtm = new SAXImpl(this, source, documentID,
 284                                   whiteSpaceFilter, null, doIndexing,
 285                                   size, buildIdIndex, newNameTable);
 286             }
 287 
 288             dtm.setDocumentURI(source.getSystemId());
 289 
 290             addDTM(dtm, dtmPos, 0);
 291 
 292             try {
 293                 if (staxevent2sax != null) {
 294                     staxevent2sax.setContentHandler(dtm);
 295                     staxevent2sax.parse();
 296                 }
 297                 else if (staxStream2SAX != null) {
 298                     staxStream2SAX.setContentHandler(dtm);
 299                     staxStream2SAX.parse();
 300                 }
 301 
 302             }
 303             catch (RuntimeException re) {
 304                 throw re;
 305             }
 306             catch (Exception e) {
 307                 throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
 308             }
 309 
 310             return dtm;
 311         }else if ((null != source) && source instanceof DOMSource) {
 312             final DOMSource domsrc = (DOMSource) source;
 313             final org.w3c.dom.Node node = domsrc.getNode();
 314             final DOM2SAX dom2sax = new DOM2SAX(node);
 315 
 316             SAXImpl dtm;
 317 
 318             if (size <= 0) {
 319                 dtm = new SAXImpl(this, source, documentID,
 320                                   whiteSpaceFilter, null, doIndexing,
 321                                   DTMDefaultBase.DEFAULT_BLOCKSIZE,
 322                                   buildIdIndex, newNameTable);
 323             } else {
 324                 dtm = new SAXImpl(this, source, documentID,
 325                                   whiteSpaceFilter, null, doIndexing,
 326                                   size, buildIdIndex, newNameTable);
 327             }
 328 
 329             dtm.setDocumentURI(source.getSystemId());
 330 
 331             addDTM(dtm, dtmPos, 0);
 332 
 333             dom2sax.setContentHandler(dtm);
 334 
 335             try {
 336                 dom2sax.parse();
 337             }
 338             catch (RuntimeException re) {
 339                 throw re;
 340             }
 341             catch (Exception e) {
 342                 throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
 343             }
 344 
 345             return dtm;
 346         }
 347         else
 348         {
 349             boolean isSAXSource = (null != source)
 350                                   ? (source instanceof SAXSource) : true;
 351             boolean isStreamSource = (null != source)
 352                                   ? (source instanceof StreamSource) : false;
 353 
 354             if (isSAXSource || isStreamSource) {
 355                 XMLReader reader;
 356                 InputSource xmlSource;
 357 
 358                 if (null == source) {
 359                     xmlSource = null;
 360                     reader = null;
 361                     hasUserReader = false;  // Make sure the user didn't lie
 362                 }
 363                 else {
 364                     reader = getXMLReader(source);
 365                     xmlSource = SAXSource.sourceToInputSource(source);
 366 
 367                     String urlOfSource = xmlSource.getSystemId();
 368 
 369                     if (null != urlOfSource) {
 370                         try {
 371                             urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource);
 372                         }
 373                         catch (Exception e) {
 374                             // %REVIEW% Is there a better way to send a warning?
 375                             System.err.println("Can not absolutize URL: " + urlOfSource);
 376                         }
 377 
 378                         xmlSource.setSystemId(urlOfSource);
 379                     }
 380                 }
 381 
 382                 // Create the basic SAX2DTM.
 383                 SAXImpl dtm;
 384                 if (size <= 0) {
 385                     dtm = new SAXImpl(this, source, documentID, whiteSpaceFilter,
 386                                       null, doIndexing,
 387                                       DTMDefaultBase.DEFAULT_BLOCKSIZE,
 388                                       buildIdIndex, newNameTable);
 389                 } else {
 390                     dtm = new SAXImpl(this, source, documentID, whiteSpaceFilter,
 391                             null, doIndexing, size, buildIdIndex, newNameTable);
 392                 }
 393 
 394                 // Go ahead and add the DTM to the lookup table.  This needs to be
 395                 // done before any parsing occurs. Note offset 0, since we've just
 396                 // created a new DTM.
 397                 addDTM(dtm, dtmPos, 0);
 398 
 399                 if (null == reader) {
 400                     // Then the user will construct it themselves.
 401                     return dtm;
 402                 }
 403 
 404                 reader.setContentHandler(dtm.getBuilder());
 405 
 406                 if (!hasUserReader || null == reader.getDTDHandler()) {
 407                     reader.setDTDHandler(dtm);
 408                 }
 409 
 410                 if(!hasUserReader || null == reader.getErrorHandler()) {
 411                     reader.setErrorHandler(dtm);
 412                 }
 413 
 414                 try {
 415                     reader.setProperty("http://xml.org/sax/properties/lexical-handler", dtm);
 416                 }
 417                 catch (SAXNotRecognizedException e){}
 418                 catch (SAXNotSupportedException e){}
 419 
 420                 try {
 421                     reader.parse(xmlSource);
 422                 }
 423                 catch (RuntimeException re) {
 424                     throw re;
 425                 }
 426                 catch (Exception e) {
 427                     throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
 428                 } finally {
 429                     if (!hasUserReader) {
 430                         releaseXMLReader(reader);
 431                     }
 432                 }
 433 
 434                 if (DUMPTREE) {
 435                     System.out.println("Dumping SAX2DOM");
 436                     dtm.dumpDTM(System.err);
 437                 }
 438 
 439                 return dtm;
 440             }
 441             else {
 442                 // It should have been handled by a derived class or the caller
 443                 // made a mistake.
 444                 throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NOT_SUPPORTED, new Object[]{source}));
 445             }
 446         }
 447     }
 448 }