1 9 package org.ozoneDB.xml.util; 10 11 import java.io.IOException ; 12 import java.io.Serializable ; 13 14 import org.ozoneDB.DxLib.DxDeque; 15 import org.ozoneDB.DxLib.DxArrayDeque; 16 17 import org.w3c.dom.Node ; 18 import org.w3c.dom.NodeList ; 19 import org.w3c.dom.Document ; 20 import org.w3c.dom.Element ; 21 import org.w3c.dom.NamedNodeMap ; 22 23 import org.xml.sax.ContentHandler ; 24 import org.xml.sax.ext.LexicalHandler ; 25 import org.xml.sax.Attributes ; 26 import org.xml.sax.Locator ; 27 import org.xml.sax.SAXException ; 28 import org.xml.sax.helpers.AttributesImpl ; 29 30 31 40 public final class SAXChunkProducer implements ContentHandler , LexicalHandler , Serializable { 41 42 44 private final static boolean debug = false; 45 46 private final static int DEFAULT_CHUNK_SIZE = 100000; 47 48 private final static int DEFAULT_CHUNK_INCREASE = 4096; 49 50 51 private final static int CHUNK_STATE_INVALID = -1; 52 53 54 private final static int CHUNK_STATE_INIT = 0; 55 56 57 private final static int CHUNK_STATE_NODE = 1; 58 59 60 private final static int CHUNK_STATE_CLOSE = 3; 61 62 63 private final static int CHUNK_STATE_FINISH = 4; 64 65 66 68 74 public SAXChunkConsumer dbConsumer; 75 76 77 private final SAXChunkProducerDelegate delegate; 78 79 private final ChunkOutputStream chunkOutput; 80 81 private final CXMLContentHandler contentHandler; 82 83 private final LexicalHandler lexicalHandler; 84 85 89 private final boolean deep; 90 91 92 96 private int depth; 97 98 99 private int processLevel = 0; 100 101 105 private final DxDeque endEvents; 106 107 108 private NodeList sourceNodes; 109 private int sourceNodesIndex; 110 111 117 private Node nextNode; 118 119 120 125 private final boolean domLevel2; 126 127 134 private int chunkState = CHUNK_STATE_INVALID; 135 136 137 139 143 144 146 150 151 153 159 160 162 public SAXChunkProducer(NodeList _nodelist) throws IOException { 163 this(_nodelist, SAXChunkProducer.DEFAULT_CHUNK_SIZE, -1); 164 } 165 166 167 169 public SAXChunkProducer(NodeList _nodelist, int _depth) throws IOException { 170 this(_nodelist, SAXChunkProducer.DEFAULT_CHUNK_SIZE, _depth); 171 } 172 173 174 176 public SAXChunkProducer(NodeList _nodelist, int _maxParts, int _depth) throws IOException { 177 this.deep = _depth < 0; 178 this.depth = _depth < 0 ? 0 : _depth; 179 180 this.delegate = null; 181 182 this.sourceNodes = _nodelist; 183 this.sourceNodesIndex = 0; 184 this.nextNode = _nodelist.item(0); 185 186 this.chunkState = CHUNK_STATE_NODE; 187 this.endEvents = new DxArrayDeque(); 188 189 Document factory = (Document )((this.nextNode.getNodeType() == Node.DOCUMENT_NODE) 190 ? this.nextNode : this.nextNode.getOwnerDocument()); 191 this.domLevel2 = factory.getImplementation().hasFeature( "XML", "2.0" ); 192 193 this.chunkOutput = new ChunkOutputStream( SAXChunkProducer.DEFAULT_CHUNK_SIZE, SAXChunkProducer.DEFAULT_CHUNK_INCREASE ); 194 this.contentHandler = new CXMLContentHandler( this.chunkOutput ); 195 this.lexicalHandler = (this.contentHandler instanceof LexicalHandler ) 196 ? this.contentHandler 197 : null; 198 } 199 200 201 203 public SAXChunkProducer( SAXChunkProducerDelegate _delegate ) throws IOException { 204 this( _delegate, SAXChunkProducer.DEFAULT_CHUNK_SIZE, -1 ); 205 } 206 207 208 210 public SAXChunkProducer( SAXChunkProducerDelegate _delegate, int _depth ) throws IOException { 211 this( _delegate, SAXChunkProducer.DEFAULT_CHUNK_SIZE, _depth ); 212 } 213 214 215 217 public SAXChunkProducer( SAXChunkProducerDelegate _delegate, int _maxParts, int _depth ) throws IOException { 218 this.deep = _depth == -1; 219 this.depth = this.deep ? 0 : _depth; 220 221 this.delegate = _delegate; 222 223 this.chunkOutput = new ChunkOutputStream( SAXChunkProducer.DEFAULT_CHUNK_SIZE, 224 SAXChunkProducer.DEFAULT_CHUNK_INCREASE ); 225 this.contentHandler = new CXMLContentHandler( this.chunkOutput ); 226 this.lexicalHandler = (this.contentHandler instanceof LexicalHandler ) 227 ? this.contentHandler 228 : null; 229 230 this.domLevel2 = false; 231 this.endEvents = null; 232 } 233 234 235 239 public ChunkOutputStream chunkStream() throws SAXException { 240 return this.chunkOutput; 241 } 242 243 244 260 public final void createNextChunk() throws SAXException { 261 String uri; 262 String qName; 263 String lName; 264 265 268 while (chunkOutput.getState() != ChunkOutputStream.STATE_OVERFLOW && chunkState != CHUNK_STATE_FINISH) { 269 271 switch (chunkState) { 272 case CHUNK_STATE_NODE: 273 switch (nextNode.getNodeType()) { 274 case Node.DOCUMENT_NODE: 275 contentHandler.startDocument(); 276 depth -= deep ? 0 : 1; 277 278 endEvents.push( nextNode ); 279 280 nextNode = nextNode.getFirstChild(); 282 chunkState = ((nextNode == null) || (depth < 0)) 283 ? CHUNK_STATE_CLOSE 284 : CHUNK_STATE_NODE; 285 nextNode = (chunkState == CHUNK_STATE_CLOSE) ? (Node )endEvents.pop() : nextNode; 286 break; 287 case Node.ELEMENT_NODE: 288 Element elem = (Element )nextNode; 289 Attributes saxAttr = createSAXAttributes(elem); 290 uri = domLevel2 ? elem.getNamespaceURI() : ""; 291 qName = elem.getNodeName(); 292 lName = domLevel2 ? elem.getLocalName() : qName; 293 294 contentHandler.startElement( 295 uri == null ? "" : uri, 296 lName == null ? qName : lName, 297 qName, saxAttr ); 298 299 endEvents.push(nextNode); 300 301 depth -= deep ? 0 : 1; 302 303 nextNode = nextNode.getFirstChild(); 304 chunkState = ((nextNode == null) || (depth < 0)) ? CHUNK_STATE_CLOSE : CHUNK_STATE_NODE; 305 nextNode = (chunkState == CHUNK_STATE_CLOSE) ? (Node )endEvents.pop() : nextNode; 306 break; 307 default: 308 convertSingleEventNode( nextNode ); 309 310 nextNode = nextNode.getNextSibling(); 311 chunkState = ((nextNode != null) && (endEvents.peek() != null)) 312 ? CHUNK_STATE_NODE 313 : ((nextNode = (Node )endEvents.pop()) != null) 314 ? CHUNK_STATE_CLOSE 315 : CHUNK_STATE_FINISH; 316 317 if (this.chunkState == CHUNK_STATE_FINISH) { 318 this.sourceNodesIndex++; 319 if (this.sourceNodesIndex < this.sourceNodes.getLength()) { 320 this.nextNode = this.sourceNodes.item(this.sourceNodesIndex); 321 this.chunkState = CHUNK_STATE_NODE; 322 } 323 324 } 325 326 break; 327 } 328 break; 329 330 case CHUNK_STATE_CLOSE: { 331 switch (nextNode.getNodeType()) { 332 case Node.ELEMENT_NODE: 333 depth += deep ? 0 : 1; 334 335 Element elem = (Element )nextNode; 336 uri = domLevel2 ? elem.getNamespaceURI() : ""; 337 qName = elem.getNodeName(); 338 lName = domLevel2 ? elem.getLocalName() : qName; 339 contentHandler.endElement( 340 uri == null ? "" : uri, 341 lName == null ? qName : lName, 342 qName); 343 344 nextNode = elem.getNextSibling(); 345 break; 346 case Node.DOCUMENT_NODE: 347 depth += deep ? 0 : 1; 348 contentHandler.endDocument(); 349 nextNode = null; 350 break; 351 default: 352 throw new IllegalStateException ( "endEvents stack contains unproper value: " + nextNode ); 353 } 355 356 chunkState = ((nextNode != null) && (endEvents.peek() != null)) 357 ? CHUNK_STATE_NODE 358 : ((nextNode = (Node )endEvents.pop()) != null) 359 ? CHUNK_STATE_CLOSE 360 : CHUNK_STATE_FINISH; 361 362 if (this.chunkState == CHUNK_STATE_FINISH) { 363 this.sourceNodesIndex++; 364 if (this.sourceNodesIndex < this.sourceNodes.getLength()) { 365 this.nextNode = this.sourceNodes.item(this.sourceNodesIndex); 366 this.chunkState = CHUNK_STATE_NODE; 367 } 368 369 } 370 371 break; 372 } 373 default: 374 throw new IllegalStateException ("Unsupported value in member chunkState: " + chunkState); 375 } 376 } 377 378 if (chunkState == CHUNK_STATE_FINISH) { 379 chunkOutput.setEndFlag(); 380 } 381 } 382 383 384 389 private void convertSingleEventNode(Node _node) throws SAXException { 390 391 switch (_node.getNodeType()) { 392 case Node.TEXT_NODE: 393 char[] ch = _node.getNodeValue().toCharArray(); 394 this.contentHandler.characters( ch, 0, ch.length ); 395 break; 396 case Node.CDATA_SECTION_NODE: 397 char[] cdata = _node.getNodeValue().toCharArray(); 398 if (this.lexicalHandler != null) { 399 this.lexicalHandler.startCDATA(); 400 } 401 402 this.contentHandler.characters( cdata, 0, cdata.length ); 403 404 if (this.lexicalHandler != null) { 405 this.lexicalHandler.endCDATA(); 406 } 407 break; 408 case Node.PROCESSING_INSTRUCTION_NODE: 409 this.contentHandler.processingInstruction( _node.getNodeName(), _node.getNodeValue() ); 410 break; 411 case Node.ENTITY_REFERENCE_NODE: 412 this.contentHandler.skippedEntity( _node.getNodeName() ); 413 break; 414 case Node.COMMENT_NODE: 415 if (this.lexicalHandler != null) { 416 char[] comment = _node.getNodeValue().toCharArray(); 417 this.lexicalHandler.comment(comment, 0, comment.length); 418 } 419 break; 420 case Node.DOCUMENT_TYPE_NODE: 421 break; 423 case Node.DOCUMENT_FRAGMENT_NODE: 424 break; 426 case Node.NOTATION_NODE: 427 break; 429 case Node.ENTITY_NODE: 430 break; 432 case Node.ATTRIBUTE_NODE: 433 break; 435 default: 436 break; 438 } 439 } 440 441 442 448 private Attributes createSAXAttributes( Element elem ) { 449 NamedNodeMap domAttributes = elem.getAttributes(); 450 AttributesImpl saxAttributes = new AttributesImpl (); 451 452 int length = domAttributes.getLength(); 453 454 for (int i = 0; i < length; i++) { 455 456 Node node = domAttributes.item(i); 457 String uri = domLevel2 ? node.getNamespaceURI() : ""; 458 String qName = node.getNodeName(); 459 String lName = domLevel2 ? node.getLocalName() : qName; 460 461 saxAttributes.addAttribute( 462 (uri == null) ? "" : uri, 463 (lName == null) ? qName : lName, 464 qName, "", 465 node.getNodeValue()); 466 } 467 468 return saxAttributes; 469 } 470 471 472 474 475 478 public final void startDocument() throws SAXException { 479 if (deep || depth >= 0) { 480 if (debug) { 481 System.out.println( "SAXChunkProducer.startDocument()..." ); 482 } 483 484 this.contentHandler.startDocument(); 485 this.processLevel++; 486 checkChunk(); 487 } 488 489 depth -= deep ? 0 : 1; 490 } 491 492 493 496 public final void endDocument() throws SAXException { 497 depth += deep ? 0 : 1; 498 499 if (deep || depth >= 0) { 500 if (debug) { 501 System.out.println( "SAXChunkProducer.endDocument()..." ); 502 } 503 504 this.contentHandler.endDocument(); 505 this.processLevel--; 506 checkChunk(); 507 } 508 } 509 510 511 514 public final void startElement( String namespaceURI, String localName, String rawName, Attributes atts ) 515 throws SAXException { 516 if (deep || depth >= 0) { 517 if (debug) { 518 System.out.println( "SAXChunkProducer.startElement()..." ); 519 } 520 521 this.contentHandler.startElement( namespaceURI, localName, rawName, atts ); 522 this.processLevel++; 523 checkChunk(); 524 } 525 526 depth -= deep ? 0 : 1; 527 } 528 529 530 533 public final void endElement( String _namespaceURI, String _localName, String _rawName ) throws SAXException { 534 depth = deep ? 0 : 1; 535 536 if (deep || depth >= 0) { 537 if (debug) { 538 System.out.println( "SAXChunkProducer.endElement()..." ); 539 } 540 541 this.contentHandler.endElement( _namespaceURI, _localName, _rawName ); 542 this.processLevel--; 543 checkChunk(); 544 } 545 } 546 547 548 551 public final void characters( char[] ch, int start, int length ) throws SAXException { 552 if (deep || depth >= 0) { 553 if (debug) { 554 System.out.println( "SAXChunkProducer.characters()..." ); 555 } 556 557 char[] characters = new char[length]; 558 System.arraycopy( ch, start, characters, 0, length ); 559 560 this.contentHandler.characters( characters, 0, characters.length ); 561 checkChunk(); 562 } 563 } 564 565 566 569 public final void processingInstruction( String target, String data ) throws SAXException { 570 if (deep || depth >= 0) { 571 if (debug) { 572 System.out.println( "SAXChunkProducer.pi ..." ); 573 } 574 575 this.contentHandler.processingInstruction( target, data ); 576 checkChunk(); 577 } 578 } 579 580 581 584 public final void skippedEntity( java.lang.String name ) throws SAXException { 585 if (deep || depth >= 0) { 586 this.contentHandler.skippedEntity( name ); 587 checkChunk(); 588 } 589 } 590 591 592 595 public final void startPrefixMapping( String prefix, String uri ) throws SAXException { 596 if (deep || depth >= 0) { 597 if (debug) { 598 System.out.println( "SAXChunkProducer.startPrefixMapping ..." ); 599 } 600 601 this.contentHandler.startPrefixMapping( prefix, uri ); 602 checkChunk(); 603 } 604 } 605 606 607 610 public final void endPrefixMapping( String prefix ) throws SAXException { 611 if (deep || depth >= 0) { 612 if (debug) { 613 System.out.println( "SAXChunkProducer.endPrefixMapping()..." ); 614 } 615 616 this.contentHandler.endPrefixMapping( prefix ); 617 checkChunk(); 618 } 619 } 620 621 622 625 public final void ignorableWhitespace( char[] ch, int start, int length ) throws SAXException { 626 } 628 629 630 633 public final void setDocumentLocator( Locator locator ) { 634 } 636 637 638 642 643 public void comment( char[] ch, int start, int length ) throws SAXException { 644 if ((this.lexicalHandler != null) 645 && (deep || depth >= 0)) { 646 this.lexicalHandler.comment(ch, start, length); 647 checkChunk(); 648 } 649 } 650 651 652 public void startCDATA() throws SAXException { 653 if ((this.lexicalHandler != null) 654 && (deep || depth >= 0)) { 655 this.lexicalHandler.startCDATA(); 656 checkChunk(); 657 } 658 } 659 660 661 public void endCDATA() throws SAXException { 662 if ((this.lexicalHandler != null) 663 && (deep || depth >= 0)) { 664 this.lexicalHandler.endCDATA(); 665 checkChunk(); 666 } 667 } 668 669 670 public void startDTD(String name, String publicId, String systemId) 671 throws SAXException { 672 if ((this.lexicalHandler != null) 673 && (deep || depth >= 0)) { 674 this.lexicalHandler.startDTD(name, publicId, systemId); 675 checkChunk(); 676 } 677 } 678 679 680 public void endDTD() throws SAXException { 681 if ((this.lexicalHandler != null) 682 && (deep || depth >= 0)) { 683 this.lexicalHandler.endDTD(); 684 checkChunk(); 685 } 686 } 687 688 689 public void startEntity(String name) throws SAXException { 690 if ((this.lexicalHandler != null) 691 && (deep || depth >= 0)) { 692 this.lexicalHandler.startEntity(name); 693 checkChunk(); 694 } 695 } 696 697 698 public void endEntity(String name) throws SAXException { 699 if ((this.lexicalHandler != null) 700 && (deep || depth >= 0)) { 701 this.lexicalHandler.startEntity(name); 702 checkChunk(); 703 } 704 } 705 706 707 protected final void checkChunk() { 708 if (this.delegate == null) { 709 return; 710 } 711 712 try { 713 if ((this.chunkOutput.getState() == ChunkOutputStream.STATE_OVERFLOW) 714 || (this.processLevel == 0)) { 715 this.delegate.processChunk(this); 716 this.chunkOutput.reset(); 717 } 718 } catch (Exception e) { 719 e.printStackTrace(); 720 throw new RuntimeException (e.toString()); 721 } 722 } 723 724 } 725 | Popular Tags |