1 22 23 28 29 package org.xquark.mapper.storage; 30 31 import java.sql.SQLException ; 32 import java.util.*; 33 34 import org.apache.commons.logging.Log; 35 import org.apache.commons.logging.LogFactory; 36 import org.xml.sax.ContentHandler ; 37 import org.xml.sax.ErrorHandler ; 38 import org.xml.sax.SAXException ; 39 import org.xml.sax.ext.LexicalHandler ; 40 import org.xml.sax.helpers.AttributesImpl ; 41 import org.xquark.mapper.RepositoryException; 42 import org.xquark.mapper.mapping.ColumnMapping; 43 import org.xquark.mapper.mapping.TableMapping; 44 import org.xquark.mapper.metadata.*; 45 import org.xquark.schema.*; 46 import org.xquark.schema.validation.ContentIterator; 47 import org.xquark.schema.validation.ValidationContextProvider; 48 import org.xquark.util.NamespaceContextStack; 49 import org.xquark.xml.xdbc.XMLDBCException; 50 import org.xquark.xpath.NodeKind; 51 52 59 public abstract class XMLBuilder 60 implements RepositoryConstants 61 { 62 private static final String RCSRevision = "$Revision: 1.2 $"; 63 private static final String RCSName = "$Name: $"; 64 65 private static Log log = LogFactory.getLog(XMLBuilder.class); 66 67 private final static String DEFAULT_PREFIX = "ns"; 68 private final static short UNKNOWN = 0; 69 private final static short FOUND_ELEMENT = 1; 70 private final static short NIL_ELEMENT = 2; 71 private final static short MISSING_ELEMENT = 3; 72 73 protected final static long NOT_FOUND = -3; 75 protected final static long TEXT_FOUND = -2; 76 protected final static long NO_UOID_FOUND = -1; 77 78 private final static int INDENT_ARRAY_TAB_COUNT = 10; 79 private final static char[] INDENT_CHAR_ARRAY = {0xA,'\t','\t','\t','\t', 80 '\t','\t','\t','\t','\t','\t'}; 81 82 protected PathSet pathSet; 83 84 private AttributesImpl attributes = new AttributesImpl (); 88 89 protected ContentHandler contentHandler = null; 90 protected LexicalHandler lexicalHandler = null; 91 protected ErrorHandler errorHandler = null; 92 protected boolean generateDBPrefix = false; protected PrefixProvider prefixProvider; 94 95 protected TableExplorer tuplePool; 97 98 protected _RepositoryCollection collection; 99 private int defaultMappingIndex; 100 private ColumnMapping defaultColumnMapping; private SchemaManager schemaManager; 103 104 protected XMLBuilder(_RepositoryCollection collection) 105 throws XMLDBCException 106 { 107 this.collection = collection; 108 schemaManager = collection.getRepositoryConnection().getSchemaManager(); 109 CollectionMetadata metadata = collection.getMetadata(); 110 pathSet = metadata.getPathSet(); 111 defaultMappingIndex = metadata.getDefaultMappingIndex(); 112 defaultColumnMapping = metadata.getDefaultMapping().getDefaultColumnMapping(null); 113 } 114 115 120 protected long browseBranch(long first, long last, long uoid, long anchor, 121 MetadataIterator metaContext, int level, boolean mixedContext) 122 throws XMLDBCException, SQLException , SAXException 123 { 124 PathNode meta = metaContext.getPathNode(); 125 short pid = meta.getPathID(); 126 ElementInfoSet eltInfo = null; 127 boolean nil; 128 boolean textOnly = true; 129 long branchLast = (uoid < 0 ? first : uoid); 130 131 if (log.isDebugEnabled()) 132 log.debug("Entering browseBranch [path, first, last]=" + meta + ',' + first + ',' + last); 133 134 138 nil = false; 140 eltInfo = new ElementInfoSet(); 141 prefixProvider.push(); 142 143 StructExplorer structRow = tuplePool.getStructNode(); 145 switch (meta.getStorageMode()) 146 { 147 case PathMetadata.POTENTIAL_STRUCT: 148 if (structRow.isInRange(first, last, pid) && ((uoid < 0) || (structRow.getUOID() == uoid))) 150 { 151 anchor = uoid = first = structRow.getUOID(); 152 branchLast = last = structRow.getLast(); 153 structRow.fetchNextRow(); } 155 else if (uoid >= first) anchor = first = last = branchLast = uoid; 157 else if (meta.isMixed()) 158 { 159 Tuple dataTuple = tuplePool.get(defaultMappingIndex); 160 if (dataTuple.getPathID() != pid) 161 return first; first = last = branchLast = anchor = uoid = dataTuple.getUOID(); 163 } 164 eltInfo.setStatus(FOUND_ELEMENT); 165 break; 166 case PathMetadata.STRUCT_ONLY: 167 case PathMetadata.DATA_AND_STRUCT: 168 if (!structRow.isInRange(first, last, pid)) return first; eltInfo.setStatus(FOUND_ELEMENT); 171 anchor = uoid = first = structRow.getUOID(); 172 last = branchLast = structRow.getLast(); 173 structRow.fetchNextRow(); break; 175 case PathMetadata.DATA_ONLY: 176 if (uoid < 0) 177 { 178 Tuple dataTuple = tuplePool.get(meta.getReadTableMapping().getTableMapping().getTableIndex()); 179 if (dataTuple.getPathID() != pid) 180 return first; uoid = dataTuple.getUOID(); 182 } 183 eltInfo.setStatus(FOUND_ELEMENT); 184 first = last = branchLast = anchor = uoid; 185 break; 186 case PathMetadata.DISCARDED: 187 break; 188 default: 189 throw new RepositoryException(RepositoryException.CONSISTENCY_ERROR, 190 "Metadata is corrupted for the collection " 191 + collection.getCollectionName() + "(Unknow storage flag " 192 + meta.getStorageMode() + " for pid " + meta.getPathID() + ")"); 193 } 194 195 processElement(metaContext, first, last, uoid, anchor, eltInfo); 196 197 switch (eltInfo.getStatus()) 198 { 199 case NIL_ELEMENT: 200 eltInfo.generateStartElement(meta); 201 break; 202 203 case FOUND_ELEMENT: 204 case UNKNOWN: long childUOID = NO_UOID_FOUND; 209 long lastChild = uoid; 210 PathNode child = null; 211 212 if (meta.isChildrenPositionEnforced()) { 215 ContentIterator it; 216 if (eltInfo.getXSIType() == null) 218 it = metaContext.getElementDeclaration().getType().childIterator(); 219 else 220 it = eltInfo.getXSIType().childIterator(); 221 222 if (it != null) 223 { 224 ElementDeclaration eltDecl = null; 225 long textUOID; 226 List nextValidElements = it.nextValidElements(); while ((nextValidElements != null) && (nextValidElements.size() != 0)) 228 { 229 childUOID = Long.MAX_VALUE; 230 eltDecl = null; 231 textUOID = NOT_FOUND; 232 if (meta.isMixed()) 234 textUOID = scanTextNode(first, last, pid); 235 236 switch (nextValidElements.size()) 238 { 239 case 1: 240 eltDecl = (ElementDeclaration)nextValidElements.get(0); 241 if (eltDecl != null) 242 { 243 child = metaContext.getChild(eltDecl.getNamespace(), eltDecl.getName(), NodeKind.ELEMENT); 244 childUOID = checkOccurrence(lastChild + 1, last, anchor, child, eltInfo.getChildCount() + 1); 245 } 246 break; 247 default: Iterator walker = nextValidElements.iterator(); 250 long foundUOID; 251 ElementDeclaration potentialDecl = null; 252 while (walker.hasNext()) 253 { 254 potentialDecl = (ElementDeclaration)walker.next(); 255 if (potentialDecl == null) continue; 257 child = metaContext.getChild(potentialDecl.getNamespace(), potentialDecl.getName(), NodeKind.ELEMENT); 258 if (child != null) 259 { 260 foundUOID = checkOccurrence(lastChild + 1, last, anchor, child, eltInfo.getChildCount() + 1); 261 if((foundUOID != NOT_FOUND) && ((foundUOID < childUOID) || (childUOID == NO_UOID_FOUND))) 262 { 263 if (foundUOID == NO_UOID_FOUND) { 265 if (eltDecl == null) 266 { 267 childUOID = foundUOID; 268 eltDecl = potentialDecl; 269 } 270 break; } 272 else { 274 childUOID = foundUOID; 275 eltDecl = potentialDecl; 276 } 277 } 278 } 279 } 280 break; 281 } 282 if ((textUOID != NOT_FOUND) 283 && ((textUOID < childUOID) || (childUOID == NOT_FOUND))) 284 { 285 eltInfo.generateStartElement(meta); 286 eltInfo.generateTextNode(); 287 continue; } 289 290 if (eltDecl == null) break; 292 293 eltInfo.generateStartElement(meta); 294 295 eltInfo.flushExtraData(!mixedContext, true); 297 if (!mixedContext) 298 indent(level); 299 textOnly = false; 300 metaContext.push(eltDecl.getNamespace(), eltDecl.getName()); 301 try { 302 it.startElement(eltDecl.getNamespace(), eltDecl.getName()); 303 lastChild = browseBranch(first, last, childUOID, anchor, 304 metaContext, level + 1, mixedContext || metaContext.getPathNode().isMixed()); 305 it.endElement(eltDecl.getNamespace(), eltDecl.getName()); 306 nextValidElements = it.nextValidElements(); 307 } 308 catch (SchemaException e) { 309 throw new RuntimeException ("Error while iterating through schema: " + e.getMessage()); 310 } 311 metaContext.pop(); 312 eltInfo.incChildCount(); processExtraData(anchor, pid, eltInfo); 314 } 315 } 316 } 317 else { 319 while (((childUOID = scanChild(lastChild + 1, last, anchor, metaContext, eltInfo.getChildCount() + 1)) > NOT_FOUND) 321 || !eltInfo.extraFlushed()) 322 { 323 eltInfo.generateStartElement(meta); 324 if (childUOID == NOT_FOUND) 325 eltInfo.flushExtraData(!mixedContext, true); 326 else if (childUOID == TEXT_FOUND) 327 eltInfo.generateTextNode(); 328 else 329 { 330 eltInfo.flushExtraData(!mixedContext, true); 331 if ((pid != ROOT_PATH_ID) && !mixedContext) 332 indent(level); 333 textOnly = false; 334 lastChild = browseBranch(first, last, childUOID, anchor, 335 metaContext, level + 1, mixedContext || metaContext.getPathNode().isMixed()); 336 metaContext.pop(); 337 eltInfo.incChildCount(); } 339 processExtraData(anchor, pid, eltInfo); 340 } 341 if (eltInfo.hasExtraData()) 343 { 344 eltInfo.generateStartElement(meta); 345 eltInfo.flushExtraData(!mixedContext, false); } 347 } 348 break; 349 350 default: return first; 352 } 353 354 if (eltInfo.leafElementButNotMissing()) 356 eltInfo.generateStartElement(meta); 357 358 359 if (eltInfo.elementGenerated()) 361 { 362 eltInfo.flushExtraData(!mixedContext, true); 363 if (!textOnly && !mixedContext) 364 indent(level - 1); 365 contentHandler.endElement( 366 meta.getNamespace() == null ? "" : meta.getNamespace(), 367 meta.getLocalName(), 368 ""); 369 eltInfo.generateEndPrefix(); 370 371 if (meta.getTableMappings() != null) 373 { 374 Iterator it = meta.getTableMappings().iterator(); 375 TableMapping refTableMapping = null, tm = null; 376 if (meta.getReadColumnMapping() != null) 377 refTableMapping = meta.getReadColumnMapping().getTableMapping(); 378 379 while (it.hasNext()) 380 { 381 tm = (TableMapping)it.next(); 382 if (!tm.equals(refTableMapping)) 384 tuplePool.get(tm.getTableIndex()).fetchNextRow(); 385 } 386 } 387 } 388 prefixProvider.pop(); 389 390 if (log.isDebugEnabled()) 391 log.debug("Exiting browseBranch [path]=" + meta); 392 return branchLast; 393 } 394 395 399 private long scanChild(long first, long last, long anchor, 400 MetadataIterator metaContext, int pos) 401 throws SQLException , RepositoryException 402 { 403 short structPID = -1; 404 short dataPID = -1; 405 long structUOID = Long.MAX_VALUE; 406 long dataUOID = Long.MAX_VALUE; 407 short wPID, pid = metaContext.getPathMetadata().getPathID(); 408 409 if ((tuplePool.getExtraNode().getAnchor() == anchor) 413 && (tuplePool.getExtraNode().getType() >= NodeKind.ELEMENT) 414 && (tuplePool.getExtraNode().getPosition() == pos)) { 416 metaContext.push(tuplePool.getExtraNode().getPath()); 417 return NO_UOID_FOUND; 418 } 419 else { 421 StructExplorer structNode = null; 423 424 if (tuplePool.getStructNode().isInRange(first, last)) 425 structNode = tuplePool.getStructNode(); 426 427 Tuple nextDataTuple = tuplePool.pollData( 429 metaContext.getPathMetadata().getBuildMappings(), 430 first, 431 last 432 ); 433 434 if (structNode != null) 435 { 436 wPID = structNode.getPath(); 437 if (wPID >= 0) 438 { 439 PathNode structChild = pathSet.get(wPID); 440 if (((PathNode)structChild.getParent()).getPathID() == pid) 441 { 442 structUOID = structNode.getUOID(); 443 structPID = wPID; 444 } 445 } 446 } 447 448 if (nextDataTuple != null) 449 { 450 if (metaContext.getPathMetadata().isMixed() 452 && (nextDataTuple.getMapping().getTableIndex() == defaultMappingIndex) 453 && (nextDataTuple.getPathID() == pid)) return TEXT_FOUND; 455 456 wPID = nextDataTuple.getPathID(); 457 if (wPID >= 0) 458 { 459 PathNode dataChild = pathSet.get(wPID); if (((PathNode)dataChild.getParent()).getPathID() == pid) 461 { 462 dataUOID = nextDataTuple.getUOID(); 463 dataPID = wPID; 464 } 465 } 466 } 467 } 468 long childUOID = structUOID; 470 short childPID = structPID; 471 472 if (dataUOID < childUOID) 473 { 474 childUOID = dataUOID; 475 childPID = dataPID; 476 } 477 478 if (childUOID != Long.MAX_VALUE) 480 { 481 metaContext.push(childPID); 482 return childUOID; 483 } 484 else 485 return NOT_FOUND; 486 } 487 488 492 private long checkOccurrence(long first, long last, long anchor, 493 PathNode node, int pos) 494 throws SQLException , XMLDBCException 495 { 496 long nodeUOID = NOT_FOUND; 497 498 if ((tuplePool.getExtraNode().getAnchor() == anchor) 502 && (tuplePool.getExtraNode().getPath() == node.getPathID()) 503 && (tuplePool.getExtraNode().getType() >= NodeKind.ELEMENT)) 504 { 505 if (tuplePool.getExtraNode().getPosition() == pos) 506 nodeUOID = NO_UOID_FOUND; 507 else 508 nodeUOID = NOT_FOUND; 509 } 510 else 511 nodeUOID = getElementUOID(first, last, node); 512 return nodeUOID; 513 } 514 515 519 private long scanTextNode(long first, long last, short parentPID) 520 throws SQLException 521 { 522 long textNodeUOID = NOT_FOUND; 523 524 Tuple defaultTuple = tuplePool.get(defaultMappingIndex); 526 if (defaultTuple.isInRangeAbs(first, last , parentPID)) textNodeUOID = defaultTuple.getUOID(); 528 529 return textNodeUOID; 530 } 531 535 protected long getElementUOID(long first, long last, PathNode node) 536 throws SQLException , XMLDBCException 537 { 538 long nodeUOID = NOT_FOUND; 539 Tuple dataTuple; 540 541 switch (node.getStorageMode()) 545 { 546 case PathMetadata.POTENTIAL_STRUCT: 547 if (tuplePool.getStructNode().isInRange(first, last, node.getPathID())) 549 nodeUOID = tuplePool.getStructNode().getUOID(); 550 551 dataTuple = tuplePool.get(defaultMappingIndex); 553 if ((dataTuple != null) && dataTuple.isInRangeAbs(first, last, node.getPathID()) 555 && ((nodeUOID < 0) || (dataTuple.getUOID() < nodeUOID))) 556 nodeUOID = dataTuple.getUOID(); 557 break; 558 559 case PathMetadata.DATA_ONLY: 560 dataTuple = tuplePool.get(node.getReadTableMapping().getTableMapping().getTableIndex()); 562 if (dataTuple.isInRangeAbs(first, last, node.getPathID())) 563 nodeUOID = dataTuple.getUOID(); 564 break; 565 566 case PathMetadata.DATA_AND_STRUCT: 567 if (tuplePool.getStructNode().isInRange(first, last, node.getPathID())) 569 nodeUOID = tuplePool.getStructNode().getUOID(); 570 else if (node.getReadTableMapping() != null) { 572 dataTuple = tuplePool.get(node.getReadTableMapping().getTableMapping().getTableIndex()); 574 if (dataTuple.isInRangeAbs(first, last, node.getPathID())) 575 nodeUOID = dataTuple.getUOID(); 576 } 577 break; 578 case PathMetadata.STRUCT_ONLY: 579 if (tuplePool.getStructNode().isInRange(first, last, node.getPathID())) 581 nodeUOID = tuplePool.getStructNode().getUOID(); 582 break; 583 584 case PathMetadata.DISCARDED: 585 if (node.getReadColumnMapping() == null) 587 nodeUOID = NO_UOID_FOUND; else if (isMappedValueNull(node)) 589 { 590 if (node.isNilImplicit()) 591 nodeUOID = NO_UOID_FOUND; } 593 else 594 nodeUOID = NO_UOID_FOUND; 595 break; 596 default: 597 throw new RepositoryException(RepositoryException.CONSISTENCY_ERROR, 598 "Metadata is corrupted for the collection " 599 + collection.getCollectionName() + "(Unknow storage flag " 600 + node.getStorageMode() + " for pid " + node.getPathID() + ")"); 601 } 602 return nodeUOID; 603 } 604 605 606 612 private void processElement(MetadataIterator metaContext, long first, 613 long last, long uoid, long anchor, 614 ElementInfoSet eltInfo) 615 throws XMLDBCException, SQLException , SAXException 616 { 617 PathNode wPath = metaContext.getPathNode(); 618 short eltPID = wPath.getPathID(); 619 620 if (processExtraData(anchor, eltPID, eltInfo)) 622 eltInfo.setStatus(NIL_ELEMENT); 623 624 String nsUri = wPath.getNamespace(); 626 if ((nsUri!= null) && !generateDBPrefix) 627 { 628 String pfx = prefixProvider.getPrefix(nsUri); 629 if (pfx == null) 630 { 631 pfx = prefixProvider.getGeneratedPrefix(wPath); 632 eltInfo.generateStartPrefixMapping(pfx, nsUri); 633 } 634 } 635 636 if (eltPID == ROOT_PATH_ID) 637 { 638 eltInfo.flushExtraData(true, true); 640 eltInfo.setStatus(FOUND_ELEMENT); 641 return; 642 } 643 644 Collection children = metaContext.getPathNode().getChildren(); 646 if (children != null) 647 { 648 String value; 649 Iterator it = children.iterator(); 650 651 while (it.hasNext()) 652 { 653 wPath = (PathNode)it.next(); 654 if (wPath.getType() != NodeKind.ATTRIBUTE) 655 continue; 656 657 if (wPath.getReadTableMapping() == null) { 659 value = getMappedValue(wPath, first, first, true, false, false); 660 if (value != null) 661 attributes.addAttribute(wPath.getNamespace() == null ? "" : wPath.getNamespace(), 662 wPath.getLocalName(), "", ATTRIBUTE_TYPES[7], value); 663 } 664 } 665 } 666 wPath = metaContext.getPathNode(); 669 670 if ((eltInfo.getStatus() != NIL_ELEMENT) 671 && ((wPath.getReadColumnMapping() != null) || wPath.isMixed())) 672 { 673 eltInfo.setValue(getElementCharData(wPath, uoid, eltInfo)); 675 if (eltInfo.getValue() == null) 676 { 677 if (wPath.isNilImplicit()) 678 { 679 attributes.addAttribute( 680 SchemaConstants.XSI_URI, 681 SchemaConstants.XSI_NIL_ATTR, 682 "", 683 ATTRIBUTE_TYPES[7], 684 SchemaConstants.TRUE_VALUE 685 ); 686 eltInfo.setStatus(NIL_ELEMENT); 687 } 688 else if (eltInfo.getStatus() == UNKNOWN) eltInfo.setStatus(MISSING_ELEMENT); 690 } 691 else 692 eltInfo.setStatus(FOUND_ELEMENT); 693 } 694 695 processAttributes(first, last, metaContext); 698 699 } 700 701 private boolean processExtraData(long anchor, short eltPID, 702 ElementInfoSet eltInfo) 703 throws SQLException , SAXException 704 { 705 boolean nil = false; 706 ExtraDataExplorer extraNodeBrowser = tuplePool.getExtraNode(); 707 while ((extraNodeBrowser.getRowNum() > eltInfo.getLastRowNum()) 708 && (extraNodeBrowser.getPath() == eltPID) 709 && (extraNodeBrowser.getUOID() == anchor) 710 || 711 ((eltPID == ROOT_PATH_ID) && (extraNodeBrowser.getPath() == ROOT_PATH_ID)) 712 ) 713 { 714 switch (extraNodeBrowser.getType()) 715 { 716 case NodeKind.NAMESPACE: 717 String data = extraNodeBrowser.getData(); int i = data.indexOf('}'); 719 String pfx = data.substring(i+1); 720 String uri = data.substring(1, i); 721 if (prefixProvider.declarePrefix(pfx, uri) || generateDBPrefix) eltInfo.generateStartPrefixMapping(pfx, uri); 723 break; 724 case NodeKind.PI: 725 case NodeKind.COMMENT: 726 case START_CDATA_SECTION: 727 case END_CDATA_SECTION: 728 eltInfo.addNode(extraNodeBrowser.copyNode()); 729 break; 730 case XSI_NIL: 731 attributes.addAttribute( 732 SchemaConstants.XSI_URI, 733 SchemaConstants.XSI_NIL_ATTR, 734 "", 735 ATTRIBUTE_TYPES[7], 736 extraNodeBrowser.getData() 737 ); 738 nil = extraNodeBrowser.isNil(); 739 break; 740 case XSI_NO_NAMESPACE_SCHEMA_LOCATION: 741 attributes.addAttribute( 742 SchemaConstants.XSI_URI, 743 SchemaConstants.XSI_NO_NAMESPACE_SCHEMA_LOCATION_ATTR, 744 "", 745 ATTRIBUTE_TYPES[7], 746 extraNodeBrowser.getData() 747 ); 748 break; 749 case XSI_SCHEMA_LOCATION: 750 attributes.addAttribute( 751 SchemaConstants.XSI_URI, 752 SchemaConstants.XSI_SCHEMA_LOCATION_ATTR, 753 "", 754 ATTRIBUTE_TYPES[7], 755 extraNodeBrowser.getData() 756 ); 757 break; 758 case XSI_TYPE: 759 String typeString = extraNodeBrowser.getData(); 760 String nsURI = null, localName = null; 761 int bracket1 = typeString.indexOf('{'); 762 int bracket2 = typeString.indexOf('}'); 763 nsURI = typeString.substring(bracket1 + 1, bracket2 - bracket1); 764 localName = typeString.substring(bracket2 + 1); 765 766 eltInfo.setXSIType(schemaManager.getType(nsURI, localName)); 767 attributes.addAttribute( 768 SchemaConstants.XSI_URI, 769 SchemaConstants.XSI_TYPE_ATTR, 770 "", 771 ATTRIBUTE_TYPES[7], 772 schemaManager.getQNameType().toXMLString(typeString, prefixProvider) 773 ); 774 break; 775 default: 780 } 782 eltInfo.setExtraRowNum(extraNodeBrowser.getRowNum()); 783 extraNodeBrowser.fetchNextRow(); 784 } 785 return nil; 786 } 787 788 792 793 private void processAttributes(long first, long last, MetadataIterator metaContext) 794 throws XMLDBCException, SQLException 795 { 796 Tuple electedTuple = null; 798 PathNode attNode; 799 String value; 800 Collection mappingSubset = metaContext.getPathMetadata().getBuildMappings(); 801 short eltPID = metaContext.getPathMetadata().getPathID(); 802 803 while ((electedTuple = tuplePool.pollData(mappingSubset, first + 1, last)) != null) 805 { 806 attNode = metaContext.getPathNode(electedTuple.getPathID()); 807 if ((attNode.getType() != org.xquark.xpath.NodeKind.ATTRIBUTE) 809 || (((PathNode)attNode.getParent()).getPathID() != eltPID)) 810 break; 811 812 value = getMappedValue(attNode, first, last, false, true, false); 813 if (value != null) { 815 attributes.addAttribute(attNode.getNamespace() == null ? "" : attNode.getNamespace(), 816 attNode.getLocalName(), "", ATTRIBUTE_TYPES[7], value); 817 } 818 } 819 } 820 821 private boolean isMappedValueNull(PathMetadata node) 822 throws SQLException , XMLDBCException 823 { 824 boolean ret = false; 825 ColumnMapping column = node.getReadColumnMapping(); 826 if (column != null) { 828 Tuple tuple = tuplePool.get(column.getTableIndex()); 829 if (tuple.getValue(column, node.getDeclaration(), prefixProvider) == null) 830 ret = true; 831 } 832 return ret; 833 } 834 835 838 protected String getMappedValue(PathMetadata node, long first, long last, 839 boolean checkRange, boolean lookup, boolean systematic) 840 throws SQLException , XMLDBCException 841 { 842 String ret =null; 843 ColumnMapping column = node.getReadColumnMapping(); 844 if (column != null) { 846 Tuple tuple = tuplePool.get(column.getTableIndex()); 847 if (!checkRange || tuple.isInRange(first, last)) 848 ret = tuple.getValue(column, node.getDeclaration(), prefixProvider); 849 if (lookup && (systematic || (tuple.getPathID() == node.getPathID()))) 850 tuple.fetchNextRow(); 851 } 852 return ret; 853 } 854 855 860 private String getElementCharData(PathMetadata node, long eltUOID, 861 ElementInfoSet eltInfo) 862 throws SQLException , XMLDBCException 863 { 864 String ret = null; 865 ColumnMapping column = node.getReadColumnMapping(); 866 if (column == null) 867 column = node.getTextColumnMapping(); 868 PathMetadata tableNode = node.getTableMappingPath(); 869 Tuple tuple = tuplePool.get(column.getTableIndex()); 870 if (((eltUOID < 0) || (tuple.getUOID() == eltUOID)) 871 && (tuple.getPathID() == (int)tableNode.getPathID())) 872 { 873 ret = tuple.getValue(column, node.getDeclaration(), prefixProvider); 874 if (tableNode.getPathID() == node.getPathID()) 875 tuple.fetchNextRow(); 876 } 877 return ret; 878 } 879 880 public void close() throws RepositoryException 881 { 882 if (tuplePool != null) 883 { 884 try 885 { 886 tuplePool.close(); 887 tuplePool = null; 888 pathSet = null; 889 attributes = null; 890 prefixProvider = null; 891 collection = null; 892 contentHandler = null; 893 lexicalHandler = null; 894 errorHandler = null; 895 } 896 catch (SQLException e) 897 { 898 throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while freeing ressources", e); 899 } 900 } 901 } 902 903 public void reset() throws RepositoryException, SQLException 904 { 905 attributes.clear(); 907 tuplePool.reset(); 908 prefixProvider.clear(); 909 } 910 911 914 public void unPlug() 915 { 916 contentHandler = null; 917 lexicalHandler = null; 918 errorHandler = null; 919 } 920 921 922 private void indent(int indent) throws SAXException 923 { 924 int quotient = indent/INDENT_ARRAY_TAB_COUNT; 925 926 if (quotient == 0) contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 0, indent + 1); 928 else 929 { 930 contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 0, INDENT_ARRAY_TAB_COUNT + 1); 932 for (int i = 2; i <= quotient; i++) 933 { 934 contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 1, INDENT_ARRAY_TAB_COUNT); 935 } 936 int remainder = indent%INDENT_ARRAY_TAB_COUNT; 937 if (remainder > 0) 938 contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 1, remainder); 939 } 940 } 941 942 946 protected class ElementInfoSet 947 { 948 private ArrayList nodesToInsert = new ArrayList(2); 949 private int childCount = 0; 950 private int charCount = 0; 951 private String value = null; 952 private boolean notGenerated = true; 953 private boolean extraFlushed = false; 954 private short status = UNKNOWN; 955 private short lastNum = -1; 956 private List prefixes = new ArrayList(2); 957 private org.xquark.schema.Type xsiType = null; 958 959 void addNode(ExtraNode node) 960 { 961 nodesToInsert.add(node); 962 extraFlushed = false; 963 } 964 void clear() 965 { 966 nodesToInsert.clear(); 967 charCount = 0; 968 lastNum = -1; 969 value = null; 970 status = UNKNOWN; 971 notGenerated = true; 972 xsiType = null; 973 extraFlushed = false; 974 } 975 976 void generateStartPrefixMapping(String pfx, String uri) 977 throws SAXException 978 { 979 prefixes.add(pfx); 980 contentHandler.startPrefixMapping(pfx, uri); 981 } 982 983 void generateEndPrefix() 984 throws SAXException 985 { 986 int prefixCount = prefixes.size(); 987 String pfx; 988 for (int i = 0; i < prefixCount; i++) 989 { 990 pfx = (String )prefixes.get(i); 991 contentHandler.endPrefixMapping(pfx); 992 } 993 } 994 995 void setValue(String value) 996 { 997 this.value = value; 998 } 999 1000 void setXSIType(org.xquark.schema.Type type) 1001 { 1002 xsiType = type; 1003 } 1004 1005 org.xquark.schema.Type getXSIType() 1006 { 1007 return xsiType; 1008 } 1009 1010 String getValue() 1011 { 1012 return value; 1013 } 1014 1015 boolean hasValue() 1016 { 1017 return value != null; 1018 } 1019 1020 boolean elementGenerated() 1021 { 1022 return !notGenerated; 1023 } 1024 1025 boolean extraFlushed() 1026 { 1027 return extraFlushed; 1028 } 1029 1030 boolean hasExtraData() 1031 { 1032 return nodesToInsert.size() != 0; 1033 } 1034 1035 boolean leafElementButNotMissing() 1036 { 1037 return (childCount == 0) && ( 1038 (status != MISSING_ELEMENT) 1039 || (value != null) 1040 || (attributes.getLength() != 0) 1041 ); 1042 } 1043 1044 void setStatus(short status) 1045 { 1046 this.status = status; 1047 } 1048 1049 short getStatus() 1050 { 1051 return status; 1052 } 1053 1054 void incChildCount() 1055 { 1056 childCount++; 1057 } 1058 1059 int getChildCount() 1060 { 1061 return childCount; 1062 } 1063 1064 void setExtraRowNum(short rowNum) 1065 { 1066 lastNum = rowNum; 1067 } 1068 1069 short getLastRowNum() 1070 { 1071 return lastNum; 1072 } 1073 1074 void generateStartElement(PathNode path) 1075 throws RepositoryException, SAXException 1076 { 1077 if (notGenerated && (path.getPathID() != ROOT_PATH_ID)) 1078 { 1079 contentHandler.startElement( 1081 path.getNamespace() == null ? "" : path.getNamespace(), 1082 path.getLocalName(), 1083 "", 1084 attributes); 1085 attributes.clear(); 1086 1087 if (value != null) generateCharacters(value); 1089 notGenerated = false; 1090 } 1091 } 1092 1093 1096 void generateTextNode(long first, long last, PathNode path) 1097 throws XMLDBCException, SQLException 1098 { 1099 Tuple defaultTuple = tuplePool.get(defaultMappingIndex); 1100 if (defaultTuple.isInRangeAbs(first, last , path.getPathID())) 1101 generateTextNode(); 1102 } 1103 1104 1107 void generateTextNode() 1108 throws RepositoryException, SQLException , XMLDBCException 1109 { 1110 Tuple defaultTuple = tuplePool.get(defaultMappingIndex); 1111 generateCharacters(defaultTuple.getValue(defaultColumnMapping, null, prefixProvider)); 1112 defaultTuple.fetchNextRow(); 1113 incChildCount(); } 1115 1116 1117 void generateCharacters(String textData) throws RepositoryException 1118 { 1119 1120 int lastOffset = 0; 1121 Iterator it = nodesToInsert.iterator(); 1122 ExtraNode node; 1123 char[] data = null; 1124 1125 if (textData == null) 1126 { 1127 if (nodesToInsert.size() == 0) 1128 return; 1129 data = new char[0]; 1130 } 1131 else 1132 data = textData.toCharArray(); 1133 1134 int maxGlobalOffset = charCount + data.length; 1135 while (it.hasNext()) 1136 { 1137 node = (ExtraNode)it.next(); 1138 if (node.offset > (lastOffset + charCount)) 1139 { 1140 try 1144 { 1145 contentHandler.characters(data, lastOffset, 1146 (node.offset < maxGlobalOffset ? node.offset : maxGlobalOffset) - (lastOffset + charCount)); 1147 } 1148 catch(SAXException e) 1149 { 1150 throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR, "SAX Exception thrown during characters() with the following message : "+e.getMessage()); 1151 } 1152 1153 lastOffset = node.offset - charCount; 1154 } 1155 1156 if ((node.position == childCount + 1) && (node.offset <= maxGlobalOffset)) 1157 { 1158 try 1159 { 1160 switch (node.type) 1161 { 1162 case NodeKind.PI: 1163 StringTokenizer st = new StringTokenizer(node.data); 1164 contentHandler.processingInstruction(st.nextToken(), st.nextToken("")); 1165 break; 1166 1167 case NodeKind.COMMENT : 1168 if (lexicalHandler != null) 1169 lexicalHandler.comment(node.data.toCharArray(), 0, node.data.length()); 1170 break; 1171 case START_CDATA_SECTION: 1172 if (lexicalHandler != null) 1173 lexicalHandler.startCDATA(); 1174 break; 1175 case END_CDATA_SECTION: 1176 if (lexicalHandler != null) 1177 lexicalHandler.endCDATA(); 1178 break; 1179 default : 1180 } 1181 } 1182 catch(SAXException e) 1183 { 1184 String methodName = null; 1185 switch (node.type) 1186 { 1187 case NodeKind.PI: 1188 methodName = "processingInstruction()"; 1189 break; 1190 case NodeKind.COMMENT : 1191 methodName = "comment()"; 1192 break; 1193 case START_CDATA_SECTION: 1194 methodName = "startCDATA()"; 1195 break; 1196 case END_CDATA_SECTION: 1197 methodName = "endCDATA()"; 1198 break; 1199 default : 1200 } 1201 throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR, 1202 "SAX Exception thrown during " + methodName 1203 + " with the following message : "+e.getMessage()); 1204 } 1205 it.remove(); 1206 incChildCount(); } 1208 } 1209 if (lastOffset < data.length) { 1212 try 1216 { 1217 contentHandler.characters(data, lastOffset, data.length - lastOffset); 1218 } 1219 catch(SAXException e) 1220 { 1221 throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR, "SAX Exception thrown during characters() with the following message : "+e.getMessage()); 1222 } 1223 } 1224 1225 charCount = maxGlobalOffset; 1227 } 1228 1229 1230 void flushExtraData(boolean carriageReturn, boolean checkPosition) 1231 throws RepositoryException, SAXException 1232 { 1233 extraFlushed = true; 1235 Iterator it = nodesToInsert.iterator(); 1236 ExtraNode node; 1237 while (it.hasNext()) 1238 { 1239 node = (ExtraNode)it.next(); 1240 if ( !checkPosition || (node.position == childCount + 1)) { 1242 if (carriageReturn) 1243 contentHandler.ignorableWhitespace(INDENT_CHAR_ARRAY, 0, 1); 1244 switch (node.type) 1245 { 1246 case NodeKind.PI: 1247 StringTokenizer st = new StringTokenizer(node.data); 1248 try 1249 { 1250 contentHandler.processingInstruction(st.nextToken(), st.nextToken("")); 1251 } 1252 catch(SAXException e) 1253 { 1254 throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR, "SAX Exception thrown during processingInstruction() with the following message : "+e.getMessage()); 1255 } 1256 break; 1257 1258 case NodeKind.COMMENT : 1259 if (lexicalHandler != null) 1260 { 1261 try 1262 { 1263 lexicalHandler.comment(node.data.toCharArray(), 0, node.data.length()); 1264 } 1265 catch(SAXException e) 1266 { 1267 throw new RepositoryException(RepositoryException.SAX_OUTPUT_ERROR, "SAX Exception thrown during comment() with the following message : "+e.getMessage()); 1268 } 1269 } 1270 break; 1271 default : 1272 } 1273 it.remove(); 1274 incChildCount(); } 1276 } 1277 } 1278 } 1279 1280 1283 protected class PrefixProvider implements ValidationContextProvider 1284 { 1285 private NamespaceContextStack nsContextStack; 1286 private int generatedPrefixCount = 1; 1287 1288 public PrefixProvider() 1289 { 1290 nsContextStack = new NamespaceContextStack(); 1291 } 1292 1293 public PrefixProvider(NamespaceContextStack nsContextStack) 1294 { 1295 this.nsContextStack = nsContextStack; 1296 } 1297 1298 1300 public String getPrefix(String uri) 1301 { 1302 return nsContextStack.getPrefix(uri); 1303 } 1304 1305 String getGeneratedPrefix(PathNode path) 1306 { 1307 String newPfx = null; 1308 1309 Declaration decl = path.getDeclaration(); 1311 if (decl != null) 1312 newPfx = decl.getSchema().getPrefix(); 1313 1314 if ((newPfx == null) || (newPfx.length() == 0)) 1316 { 1317 do 1318 { 1319 newPfx = "ns" + generatedPrefixCount++; 1320 } 1321 while (nsContextStack.getNamespaceURI(newPfx) != null); 1322 } 1323 1324 declarePrefix(newPfx, path.getNamespace()); 1325 return newPfx; 1326 } 1327 1328 1330 protected boolean declarePrefix(String prefix, String uri) 1331 { 1332 boolean newPfx = (getPrefix(uri) == null); 1333 if (newPfx) 1334 nsContextStack.declarePrefix(prefix, uri); 1335 return newPfx; 1336 } 1337 1338 public String getNamespaceURI(String prefix) 1339 { 1340 return nsContextStack.getNamespaceURI(prefix); 1341 } 1342 1343 public String getDocumentBase() 1344 { 1345 return null; 1346 } 1347 1348 void clear() 1349 { 1350 nsContextStack = new NamespaceContextStack(); 1351 generatedPrefixCount = 1; 1352 } 1353 1354 public java.util.Map getNotationDeclarations() 1355 { 1356 return null; 1357 } 1358 1359 void push() 1360 { 1361 nsContextStack.pushContext(); 1362 } 1363 1364 void pop() 1365 { 1366 nsContextStack.popContext(); 1367 } 1368 } 1369} 1370 | Popular Tags |