1 17 package org.apache.excalibur.xml.impl; 18 19 import java.io.IOException ; 20 21 import javax.xml.parsers.DocumentBuilder ; 22 import javax.xml.parsers.DocumentBuilderFactory ; 23 import javax.xml.parsers.ParserConfigurationException ; 24 import javax.xml.parsers.SAXParserFactory ; 25 26 import org.apache.avalon.excalibur.pool.Poolable; 27 import org.apache.avalon.framework.activity.Disposable; 28 import org.apache.avalon.framework.component.Component; 29 import org.apache.avalon.framework.logger.AbstractLogEnabled; 30 import org.apache.avalon.framework.parameters.ParameterException; 31 import org.apache.avalon.framework.parameters.Parameterizable; 32 import org.apache.avalon.framework.parameters.Parameters; 33 import org.apache.avalon.framework.service.ServiceException; 34 import org.apache.avalon.framework.service.ServiceManager; 35 import org.apache.avalon.framework.service.Serviceable; 36 import org.apache.excalibur.xml.EntityResolver; 37 import org.apache.excalibur.xml.dom.DOMParser; 38 import org.apache.excalibur.xml.sax.SAXParser; 39 import org.w3c.dom.Document ; 40 import org.xml.sax.ContentHandler ; 41 import org.xml.sax.ErrorHandler ; 42 import org.xml.sax.InputSource ; 43 import org.xml.sax.SAXException ; 44 import org.xml.sax.SAXParseException ; 45 import org.xml.sax.XMLReader ; 46 import org.xml.sax.ext.LexicalHandler ; 47 48 90 public final class JaxpParser 91 extends AbstractLogEnabled 92 implements SAXParser, DOMParser, 93 Poolable, Component, Parameterizable, Serviceable, Disposable, ErrorHandler 94 { 95 96 private SAXParserFactory m_factory; 97 98 100 private XMLReader m_reader; 101 102 103 private EntityResolver m_resolver; 104 105 106 private boolean m_nsPrefixes; 107 108 109 private boolean m_reuseParsers; 110 111 112 private boolean m_stopOnWarning; 113 114 115 private boolean m_stopOnRecoverableError; 116 117 118 private DocumentBuilderFactory m_docFactory; 119 120 122 private DocumentBuilder m_docBuilder; 123 124 125 private boolean m_dropDtdComments; 126 127 128 private ServiceManager m_manager; 129 130 135 public void service( final ServiceManager manager ) 136 throws ServiceException 137 { 138 m_manager = manager; 139 140 if( manager.hasService( EntityResolver.ROLE ) ) 141 { 142 m_resolver = (EntityResolver)manager.lookup( EntityResolver.ROLE ); 143 if( getLogger().isDebugEnabled() ) 144 { 145 getLogger().debug( "JaxpParser: Using EntityResolver: " + m_resolver ); 146 } 147 } 148 } 149 150 153 public void dispose() 154 { 155 if ( m_manager != null ) 156 { 157 m_manager.release( m_resolver ); 158 m_manager = null; 159 m_resolver = null; 160 } 161 } 162 163 public void parameterize( final Parameters params ) 164 throws ParameterException 165 { 166 boolean validate = params.getParameterAsBoolean( "validate", false ); 168 m_nsPrefixes = params.getParameterAsBoolean( "namespace-prefixes", false ); 169 m_reuseParsers = params.getParameterAsBoolean( "reuse-parsers", true ); 170 m_stopOnWarning = params.getParameterAsBoolean( "stop-on-warning", true ); 171 m_stopOnRecoverableError = params.getParameterAsBoolean( "stop-on-recoverable-error", true ); 172 m_dropDtdComments = params.getParameterAsBoolean( "drop-dtd-comments", false ); 173 174 final String saxParserFactoryName = params.getParameter( "sax-parser-factory", 176 "javax.xml.parsers.SAXParserFactory" ); 177 if( "javax.xml.parsers.SAXParserFactory".equals( saxParserFactoryName ) ) 178 { 179 m_factory = SAXParserFactory.newInstance(); 180 } 181 else 182 { 183 try 184 { 185 final Class factoryClass = loadClass( saxParserFactoryName ); 186 m_factory = (SAXParserFactory )factoryClass.newInstance(); 187 } 188 catch( Exception e ) 189 { 190 throw new ParameterException( "Cannot load SAXParserFactory class " + saxParserFactoryName, e ); 191 } 192 } 193 m_factory.setNamespaceAware( true ); 194 m_factory.setValidating( validate ); 195 196 final String documentBuilderFactoryName = params.getParameter( "document-builder-factory", 198 "javax.xml.parsers.DocumentBuilderFactory" ); 199 if( "javax.xml.parsers.DocumentBuilderFactory".equals( documentBuilderFactoryName ) ) 200 { 201 m_docFactory = DocumentBuilderFactory.newInstance(); 202 } 203 else 204 { 205 try 206 { 207 final Class factoryClass = loadClass( documentBuilderFactoryName ); 208 m_docFactory = (DocumentBuilderFactory )factoryClass.newInstance(); 209 } 210 catch( Exception e ) 211 { 212 throw new ParameterException( "Cannot load DocumentBuilderFactory class " + documentBuilderFactoryName, e ); 213 } 214 } 215 m_docFactory.setNamespaceAware( true ); 216 m_docFactory.setValidating( validate ); 217 218 if( getLogger().isDebugEnabled() ) 219 { 220 getLogger().debug( "JaxpParser: validating: " + validate + 221 ", namespace-prefixes: " + m_nsPrefixes + 222 ", reuse parser: " + m_reuseParsers + 223 ", stop on warning: " + m_stopOnWarning + 224 ", stop on recoverable-error: " + m_stopOnRecoverableError + 225 ", saxParserFactory: " + saxParserFactoryName + 226 ", documentBuilderFactory: " + documentBuilderFactoryName ); 227 } 228 } 229 230 233 private Class loadClass( String name ) throws Exception 234 { 235 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 236 if( loader == null ) 237 { 238 loader = getClass().getClassLoader(); 239 } 240 return loader.loadClass( name ); 241 } 242 243 250 public void parse( final InputSource in, 251 final ContentHandler contentHandler, 252 final LexicalHandler lexicalHandler ) 253 throws SAXException , IOException 254 { 255 setupXMLReader(); 256 257 XMLReader tmpReader = m_reader; 259 m_reader = null; 260 261 try 262 { 263 LexicalHandler theLexicalHandler = null; 264 if ( null == lexicalHandler 265 && contentHandler instanceof LexicalHandler ) 266 { 267 theLexicalHandler = (LexicalHandler )contentHandler; 268 } 269 if( null != lexicalHandler ) 270 { 271 theLexicalHandler = lexicalHandler; 272 } 273 if (theLexicalHandler != null) 274 { 275 if (m_dropDtdComments) 276 theLexicalHandler = new DtdCommentEater(theLexicalHandler); 277 tmpReader.setProperty( "http://xml.org/sax/properties/lexical-handler", 278 theLexicalHandler ); 279 } 280 } 281 catch( final SAXException e ) 282 { 283 final String message = 284 "SAX2 driver does not support property: " + 285 "'http://xml.org/sax/properties/lexical-handler'"; 286 getLogger().warn( message ); 287 } 288 289 tmpReader.setErrorHandler( this ); 290 tmpReader.setContentHandler( contentHandler ); 291 if( null != m_resolver ) 292 { 293 tmpReader.setEntityResolver( m_resolver ); 294 } 295 296 tmpReader.parse( in ); 297 298 if( m_reuseParsers ) 300 { 301 m_reader = tmpReader; 302 } 303 } 304 305 312 public void parse( InputSource in, ContentHandler consumer ) 313 throws SAXException , IOException 314 { 315 this.parse( in, consumer, 316 (consumer instanceof LexicalHandler ? (LexicalHandler )consumer : null)); 317 } 318 319 322 private void setupXMLReader() 323 throws SAXException 324 { 325 if( null == m_reader ) 326 { 327 try 329 { 330 m_reader = m_factory.newSAXParser().getXMLReader(); 331 } 332 catch( final ParserConfigurationException pce ) 333 { 334 final String message = "Cannot produce a valid parser"; 335 throw new SAXException ( message, pce ); 336 } 337 338 m_reader.setFeature( "http://xml.org/sax/features/namespaces", true ); 339 340 if( m_nsPrefixes ) 341 { 342 try 343 { 344 m_reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", 345 m_nsPrefixes ); 346 } 347 catch( final SAXException se ) 348 { 349 final String message = 350 "SAX2 XMLReader does not support setting feature: " + 351 "'http://xml.org/sax/features/namespace-prefixes'"; 352 getLogger().warn( message ); 353 } 354 } 355 } 356 } 357 358 361 public Document parseDocument( final InputSource input ) 362 throws SAXException , IOException 363 { 364 setupDocumentBuilder(); 365 366 DocumentBuilder tmpBuilder = m_docBuilder; 368 m_docBuilder = null; 369 370 if( null != m_resolver ) 371 { 372 tmpBuilder.setEntityResolver( m_resolver ); 373 } 374 375 Document result = tmpBuilder.parse( input ); 376 377 if( m_reuseParsers ) 379 { 380 m_docBuilder = tmpBuilder; 381 } 382 383 return result; 384 } 385 386 389 private void setupDocumentBuilder() 390 throws SAXException 391 { 392 if( null == m_docBuilder ) 393 { 394 try 395 { 396 m_docBuilder = m_docFactory.newDocumentBuilder(); 397 } 398 catch( final ParserConfigurationException pce ) 399 { 400 final String message = "Could not create DocumentBuilder"; 401 throw new SAXException ( message, pce ); 402 } 403 } 404 } 405 406 409 public Document createDocument() 410 throws SAXException 411 { 412 setupDocumentBuilder(); 413 return m_docBuilder.newDocument(); 414 } 415 416 419 public void error( final SAXParseException spe ) 420 throws SAXException 421 { 422 final String message = 423 "Error parsing " + spe.getSystemId() + " (line " + 424 spe.getLineNumber() + " col. " + spe.getColumnNumber() + 425 "): " + spe.getMessage(); 426 if( m_stopOnRecoverableError ) 427 { 428 throw new SAXException ( message, spe ); 429 } 430 getLogger().error( message, spe ); 431 } 432 433 436 public void fatalError( final SAXParseException spe ) 437 throws SAXException 438 { 439 final String message = 440 "Fatal error parsing " + spe.getSystemId() + " (line " + 441 spe.getLineNumber() + " col. " + spe.getColumnNumber() + 442 "): " + spe.getMessage(); 443 throw new SAXException ( message, spe ); 444 } 445 446 449 public void warning( final SAXParseException spe ) 450 throws SAXException 451 { 452 final String message = 453 "Warning parsing " + spe.getSystemId() + " (line " + 454 spe.getLineNumber() + " col. " + spe.getColumnNumber() + 455 "): " + spe.getMessage(); 456 457 if( m_stopOnWarning ) 458 { 459 throw new SAXException ( message, spe ); 460 } 461 getLogger().warn( message, spe ); 462 } 463 464 469 private static class DtdCommentEater implements LexicalHandler 470 { 471 private LexicalHandler next; 472 private boolean inDTD; 473 474 public DtdCommentEater(LexicalHandler nextHandler) 475 { 476 this.next = nextHandler; 477 } 478 479 public void startDTD (String name, String publicId, String systemId) 480 throws SAXException 481 { 482 inDTD = true; 483 next.startDTD(name, publicId, systemId); 484 } 485 486 public void endDTD () 487 throws SAXException 488 { 489 inDTD = false; 490 next.endDTD(); 491 } 492 493 public void startEntity (String name) 494 throws SAXException 495 { 496 next.startEntity(name); 497 } 498 499 public void endEntity (String name) 500 throws SAXException 501 { 502 next.endEntity(name); 503 } 504 505 public void startCDATA () 506 throws SAXException 507 { 508 next.startCDATA(); 509 } 510 511 public void endCDATA () 512 throws SAXException 513 { 514 next.endCDATA(); 515 } 516 517 public void comment (char ch[], int start, int length) 518 throws SAXException 519 { 520 if (!inDTD) 521 next.comment(ch, start, length); 522 } 523 } 524 525 } 526 | Popular Tags |