001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: XSLTCDTMManager.java 468651 2006-10-28 07:04:25Z minchau $ 020 */ 021 package org.apache.xalan.xsltc.dom; 022 023 import javax.xml.transform.Source; 024 import javax.xml.transform.dom.DOMSource; 025 import javax.xml.transform.sax.SAXSource; 026 import javax.xml.transform.stream.StreamSource; 027 028 import org.apache.xml.dtm.DTM; 029 import org.apache.xml.dtm.ref.DTMDefaultBase; 030 import org.apache.xml.dtm.DTMException; 031 import org.apache.xml.dtm.DTMWSFilter; 032 import org.apache.xml.dtm.ref.DTMManagerDefault; 033 import org.apache.xml.res.XMLErrorResources; 034 import org.apache.xml.res.XMLMessages; 035 import org.apache.xml.utils.SystemIDResolver; 036 import org.apache.xalan.xsltc.trax.DOM2SAX; 037 038 import org.xml.sax.InputSource; 039 import org.xml.sax.SAXNotRecognizedException; 040 import org.xml.sax.SAXNotSupportedException; 041 import org.xml.sax.XMLReader; 042 043 /** 044 * The default implementation for the DTMManager. 045 */ 046 public class XSLTCDTMManager extends DTMManagerDefault 047 { 048 049 /** The default class name to use as the manager. */ 050 private static final String DEFAULT_CLASS_NAME = 051 "org.apache.xalan.xsltc.dom.XSLTCDTMManager"; 052 053 private static final String DEFAULT_PROP_NAME = 054 "org.apache.xalan.xsltc.dom.XSLTCDTMManager"; 055 056 /** Set this to true if you want a dump of the DTM after creation */ 057 private static final boolean DUMPTREE = false; 058 059 /** Set this to true if you want basic diagnostics */ 060 private static final boolean DEBUG = false; 061 062 /** 063 * Constructor DTMManagerDefault 064 * 065 */ 066 public XSLTCDTMManager() 067 { 068 super(); 069 } 070 071 /** 072 * Obtain a new instance of a <code>DTMManager</code>. 073 * This static method creates a new factory instance. 074 * The current implementation just returns a new XSLTCDTMManager instance. 075 */ 076 public static XSLTCDTMManager newInstance() 077 { 078 return new XSLTCDTMManager(); 079 } 080 081 /** 082 * Look up the class that provides the XSLTC DTM Manager service. 083 * The following lookup procedure is used to find the service provider. 084 * <ol> 085 * <li>The value of the 086 * <code>org.apache.xalan.xsltc.dom.XSLTCDTMManager</code> property, is 087 * checked.</li> 088 * <li>The <code>xalan.propeties</code> file is checked for a property 089 * of the same name.</li> 090 * <li>The 091 * <code>META-INF/services/org.apache.xalan.xsltc.dom.XSLTCDTMManager</code> 092 * file is checked. 093 * </ol> 094 * The default is <code>org.apache.xalan.xsltc.dom.XSLTCDTMManager</code>. 095 */ 096 public static Class getDTMManagerClass() { 097 Class mgrClass = ObjectFactory.lookUpFactoryClass(DEFAULT_PROP_NAME, 098 null, 099 DEFAULT_CLASS_NAME); 100 // If no class found, default to this one. (This should never happen - 101 // the ObjectFactory has already been told that the current class is 102 // the default). 103 return (mgrClass != null) ? mgrClass : XSLTCDTMManager.class; 104 } 105 106 /** 107 * Get an instance of a DTM, loaded with the content from the 108 * specified source. If the unique flag is true, a new instance will 109 * always be returned. Otherwise it is up to the DTMManager to return a 110 * new instance or an instance that it already created and may be being used 111 * by someone else. 112 * (I think more parameters will need to be added for error handling, and 113 * entity resolution). 114 * 115 * @param source the specification of the source object. 116 * @param unique true if the returned DTM must be unique, probably because it 117 * is going to be mutated. 118 * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may 119 * be null. 120 * @param incremental true if the DTM should be built incrementally, if 121 * possible. 122 * @param doIndexing true if the caller considers it worth it to use 123 * indexing schemes. 124 * 125 * @return a non-null DTM reference. 126 */ 127 public DTM getDTM(Source source, boolean unique, 128 DTMWSFilter whiteSpaceFilter, boolean incremental, 129 boolean doIndexing) 130 { 131 return getDTM(source, unique, whiteSpaceFilter, incremental, 132 doIndexing, false, 0, true, false); 133 } 134 135 /** 136 * Get an instance of a DTM, loaded with the content from the 137 * specified source. If the unique flag is true, a new instance will 138 * always be returned. Otherwise it is up to the DTMManager to return a 139 * new instance or an instance that it already created and may be being used 140 * by someone else. 141 * (I think more parameters will need to be added for error handling, and 142 * entity resolution). 143 * 144 * @param source the specification of the source object. 145 * @param unique true if the returned DTM must be unique, probably because it 146 * is going to be mutated. 147 * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may 148 * be null. 149 * @param incremental true if the DTM should be built incrementally, if 150 * possible. 151 * @param doIndexing true if the caller considers it worth it to use 152 * indexing schemes. 153 * @param buildIdIndex true if the id index table should be built. 154 * 155 * @return a non-null DTM reference. 156 */ 157 public DTM getDTM(Source source, boolean unique, 158 DTMWSFilter whiteSpaceFilter, boolean incremental, 159 boolean doIndexing, boolean buildIdIndex) 160 { 161 return getDTM(source, unique, whiteSpaceFilter, incremental, 162 doIndexing, false, 0, buildIdIndex, false); 163 } 164 165 /** 166 * Get an instance of a DTM, loaded with the content from the 167 * specified source. If the unique flag is true, a new instance will 168 * always be returned. Otherwise it is up to the DTMManager to return a 169 * new instance or an instance that it already created and may be being used 170 * by someone else. 171 * (I think more parameters will need to be added for error handling, and 172 * entity resolution). 173 * 174 * @param source the specification of the source object. 175 * @param unique true if the returned DTM must be unique, probably because it 176 * is going to be mutated. 177 * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may 178 * be null. 179 * @param incremental true if the DTM should be built incrementally, if 180 * possible. 181 * @param doIndexing true if the caller considers it worth it to use 182 * indexing schemes. 183 * @param buildIdIndex true if the id index table should be built. 184 * @param newNameTable true if we want to use a separate ExpandedNameTable 185 * for this DTM. 186 * 187 * @return a non-null DTM reference. 188 */ 189 public DTM getDTM(Source source, boolean unique, 190 DTMWSFilter whiteSpaceFilter, boolean incremental, 191 boolean doIndexing, boolean buildIdIndex, 192 boolean newNameTable) 193 { 194 return getDTM(source, unique, whiteSpaceFilter, incremental, 195 doIndexing, false, 0, buildIdIndex, newNameTable); 196 } 197 198 /** 199 * Get an instance of a DTM, loaded with the content from the 200 * specified source. If the unique flag is true, a new instance will 201 * always be returned. Otherwise it is up to the DTMManager to return a 202 * new instance or an instance that it already created and may be being used 203 * by someone else. 204 * (I think more parameters will need to be added for error handling, and 205 * entity resolution). 206 * 207 * @param source the specification of the source object. 208 * @param unique true if the returned DTM must be unique, probably because it 209 * is going to be mutated. 210 * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may 211 * be null. 212 * @param incremental true if the DTM should be built incrementally, if 213 * possible. 214 * @param doIndexing true if the caller considers it worth it to use 215 * indexing schemes. 216 * @param hasUserReader true if <code>source</code> is a 217 * <code>SAXSource</code> object that has an 218 * <code>XMLReader</code>, that was specified by the 219 * user. 220 * @param size Specifies initial size of tables that represent the DTM 221 * @param buildIdIndex true if the id index table should be built. 222 * 223 * @return a non-null DTM reference. 224 */ 225 public DTM getDTM(Source source, boolean unique, 226 DTMWSFilter whiteSpaceFilter, boolean incremental, 227 boolean doIndexing, boolean hasUserReader, int size, 228 boolean buildIdIndex) 229 { 230 return getDTM(source, unique, whiteSpaceFilter, incremental, 231 doIndexing, hasUserReader, size, 232 buildIdIndex, false); 233 } 234 235 /** 236 * Get an instance of a DTM, loaded with the content from the 237 * specified source. If the unique flag is true, a new instance will 238 * always be returned. Otherwise it is up to the DTMManager to return a 239 * new instance or an instance that it already created and may be being used 240 * by someone else. 241 * (I think more parameters will need to be added for error handling, and 242 * entity resolution). 243 * 244 * @param source the specification of the source object. 245 * @param unique true if the returned DTM must be unique, probably because it 246 * is going to be mutated. 247 * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may 248 * be null. 249 * @param incremental true if the DTM should be built incrementally, if 250 * possible. 251 * @param doIndexing true if the caller considers it worth it to use 252 * indexing schemes. 253 * @param hasUserReader true if <code>source</code> is a 254 * <code>SAXSource</code> object that has an 255 * <code>XMLReader</code>, that was specified by the 256 * user. 257 * @param size Specifies initial size of tables that represent the DTM 258 * @param buildIdIndex true if the id index table should be built. 259 * @param newNameTable true if we want to use a separate ExpandedNameTable 260 * for this DTM. 261 * 262 * @return a non-null DTM reference. 263 */ 264 public DTM getDTM(Source source, boolean unique, 265 DTMWSFilter whiteSpaceFilter, boolean incremental, 266 boolean doIndexing, boolean hasUserReader, int size, 267 boolean buildIdIndex, boolean newNameTable) 268 { 269 if(DEBUG && null != source) { 270 System.out.println("Starting "+ 271 (unique ? "UNIQUE" : "shared")+ 272 " source: "+source.getSystemId()); 273 } 274 275 int dtmPos = getFirstFreeDTMID(); 276 int documentID = dtmPos << IDENT_DTM_NODE_BITS; 277 278 if ((null != source) && source instanceof DOMSource) 279 { 280 final DOMSource domsrc = (DOMSource) source; 281 final org.w3c.dom.Node node = domsrc.getNode(); 282 final DOM2SAX dom2sax = new DOM2SAX(node); 283 284 SAXImpl dtm; 285 286 if (size <= 0) { 287 dtm = new SAXImpl(this, source, documentID, 288 whiteSpaceFilter, null, doIndexing, 289 DTMDefaultBase.DEFAULT_BLOCKSIZE, 290 buildIdIndex, newNameTable); 291 } else { 292 dtm = new SAXImpl(this, source, documentID, 293 whiteSpaceFilter, null, doIndexing, 294 size, buildIdIndex, newNameTable); 295 } 296 297 dtm.setDocumentURI(source.getSystemId()); 298 299 addDTM(dtm, dtmPos, 0); 300 301 dom2sax.setContentHandler(dtm); 302 303 try { 304 dom2sax.parse(); 305 } 306 catch (RuntimeException re) { 307 throw re; 308 } 309 catch (Exception e) { 310 throw new org.apache.xml.utils.WrappedRuntimeException(e); 311 } 312 313 return dtm; 314 } 315 else 316 { 317 boolean isSAXSource = (null != source) 318 ? (source instanceof SAXSource) : true; 319 boolean isStreamSource = (null != source) 320 ? (source instanceof StreamSource) : false; 321 322 if (isSAXSource || isStreamSource) { 323 XMLReader reader; 324 InputSource xmlSource; 325 326 if (null == source) { 327 xmlSource = null; 328 reader = null; 329 hasUserReader = false; // Make sure the user didn't lie 330 } 331 else { 332 reader = getXMLReader(source); 333 xmlSource = SAXSource.sourceToInputSource(source); 334 335 String urlOfSource = xmlSource.getSystemId(); 336 337 if (null != urlOfSource) { 338 try { 339 urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource); 340 } 341 catch (Exception e) { 342 // %REVIEW% Is there a better way to send a warning? 343 System.err.println("Can not absolutize URL: " + urlOfSource); 344 } 345 346 xmlSource.setSystemId(urlOfSource); 347 } 348 } 349 350 // Create the basic SAX2DTM. 351 SAXImpl dtm; 352 if (size <= 0) { 353 dtm = new SAXImpl(this, source, documentID, whiteSpaceFilter, 354 null, doIndexing, 355 DTMDefaultBase.DEFAULT_BLOCKSIZE, 356 buildIdIndex, newNameTable); 357 } else { 358 dtm = new SAXImpl(this, source, documentID, whiteSpaceFilter, 359 null, doIndexing, size, buildIdIndex, newNameTable); 360 } 361 362 // Go ahead and add the DTM to the lookup table. This needs to be 363 // done before any parsing occurs. Note offset 0, since we've just 364 // created a new DTM. 365 addDTM(dtm, dtmPos, 0); 366 367 if (null == reader) { 368 // Then the user will construct it themselves. 369 return dtm; 370 } 371 372 reader.setContentHandler(dtm.getBuilder()); 373 374 if (!hasUserReader || null == reader.getDTDHandler()) { 375 reader.setDTDHandler(dtm); 376 } 377 378 if(!hasUserReader || null == reader.getErrorHandler()) { 379 reader.setErrorHandler(dtm); 380 } 381 382 try { 383 reader.setProperty("http://xml.org/sax/properties/lexical-handler", dtm); 384 } 385 catch (SAXNotRecognizedException e){} 386 catch (SAXNotSupportedException e){} 387 388 try { 389 reader.parse(xmlSource); 390 } 391 catch (RuntimeException re) { 392 throw re; 393 } 394 catch (Exception e) { 395 throw new org.apache.xml.utils.WrappedRuntimeException(e); 396 } finally { 397 if (!hasUserReader) { 398 releaseXMLReader(reader); 399 } 400 } 401 402 if (DUMPTREE) { 403 System.out.println("Dumping SAX2DOM"); 404 dtm.dumpDTM(System.err); 405 } 406 407 return dtm; 408 } 409 else { 410 // It should have been handled by a derived class or the caller 411 // made a mistake. 412 throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NOT_SUPPORTED, new Object[]{source})); 413 } 414 } 415 } 416 }