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