1 22 23 28 29 package org.xquark.mapper.storage; 30 31 import java.sql.PreparedStatement ; 32 import java.sql.SQLException ; 33 import java.util.Collections ; 34 import java.util.Iterator ; 35 import java.util.List ; 36 37 import org.xml.sax.Locator ; 38 import org.xquark.mapper.RepositoryException; 39 import org.xquark.mapper.dbms.*; 40 import org.xquark.mapper.mapping.ColumnMapping; 41 import org.xquark.mapper.metadata.*; 42 import org.xquark.mapper.util.RecyclingStack; 43 import org.xquark.mapper.util.RepositoryProperties; 44 import org.xquark.schema.SchemaConstants; 45 import org.xquark.schema.validation.ElementPSVInfoset; 46 import org.xquark.schema.validation.PSVInfoset; 47 import org.xquark.schema.validation.SchemaValidationContext; 48 import org.xquark.xml.xdbc.XMLDBCException; 49 import org.xquark.xpath.NodeKind; 50 51 54 class ModelBuilder extends AbstractModelBuilder 55 { 56 private static final String RCSRevision = "$Revision: 1.1 $"; 57 private static final String RCSName = "$Name: $"; 58 59 private static final short NO_STRUCT = StoragePathMetadata.DISCARDED|StoragePathMetadata.DATA_ONLY; 60 private static final short POTENTIAL_DATA = StoragePathMetadata.POTENTIAL_STRUCT|StoragePathMetadata.DATA_AND_STRUCT|StoragePathMetadata.DATA_ONLY; 61 62 protected PreparedStatement idStmt; 63 64 private long lastOID = -1; 65 private long nodeCount = 0; 66 private long docDataSize = 0; 67 68 private long DID = -1; 69 private long UDID = -1; 70 71 private int extraDataMaxSize = -1; 72 private String docID = null; 73 private short rootPosition = 0; 74 private short rowNum = 0; 75 private ExtraNode wExtraNode = new ExtraNode(); 76 private UOIDManager manager; 77 78 StructSaver nodeRow; 80 ExtraDataSaver extraNodeRow; 81 82 List textTableMappingList = null; 84 List textColumnMappingList = null; 85 86 public ModelBuilder(_RepositoryCollection collection, SchemaValidationContext schemaContext) 87 throws XMLDBCException 88 { 89 super(collection.getRepositoryConnection().getConnection(), schemaContext); 90 try 91 { 92 initBatcher(batcher, collection.getMetadata()); 93 } 94 catch (SQLException e) 95 { 96 throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while creating statement for documents IDs.", e); 97 } 98 AbstractConnection conn = collection.getRepositoryConnection().getConnection(); 99 CollectionMetadata meta = collection.getMetadata(); 100 manager = meta.getUOIDManager(); 101 storageBuffer = new StorageBuffer 102 ( 103 meta, 104 meta.getCollectionName(), 105 conn, 106 batcher, 107 this, 108 !conn.distinguishNullAndEmptyStrings() 109 ); 110 ColumnMapping textColumnMapping = meta.createDefaultMappingView(null); 111 textColumnMappingList = Collections.singletonList(textColumnMapping); 112 textTableMappingList = Collections.singletonList(textColumnMapping.getTableMapping()); 113 extraDataMaxSize = collection.getInfo().getMaxExtraDataLength(); 114 } 115 116 private void initBatcher(JDBCBatcher batcher, CollectionMetadata collection) throws SQLException 117 { 118 TableInfo table = collection.getTableInfo(TableSpec.TYPE_DOCS); 120 idStmt = connection.getConnection().prepareStatement(table.getInsertStatement()); 121 batcher.addStatement(idStmt, table.getName(), RepositoryProperties.getIntProperty(CONF_DOCID_BATCHSIZE)); 122 123 table = collection.getTableInfo(TableSpec.TYPE_STRUCT); 125 nodeRow = new StructSaver(table, collection.getUOIDManager()); 126 batcher.addStatement(nodeRow.getStatement(connection), table.getName(), 127 RepositoryProperties.getIntProperty(CONF_TREE_BATCHSIZE)); 128 129 table = collection.getTableInfo(TableSpec.TYPE_EXTRA); 131 extraNodeRow = new ExtraDataSaver(table); 132 batcher.addStatement(extraNodeRow.getStatement(connection), table.getName(), 133 RepositoryProperties.getIntProperty(CONF_TREE_BATCHSIZE)); 134 } 135 136 public String allocateDocOID(String docID) throws RepositoryException 137 { 138 DID = manager.getNewDocOID(); 139 UDID = manager.buildUDID(DID); 140 if (docID == null) 141 docID = Long.toString(DID); 142 this.docID = docID; 143 nodeRow.set(DID); 144 extraNodeRow.set(DID); 145 return this.docID; 146 } 147 148 151 public void extraNode(byte type, StoragePathMetadata path, String data, Locator locator) 152 throws XMLDBCException, SQLException 153 { 154 if ((data != null) && (data.length() > extraDataMaxSize)) 155 { 156 String msg; 157 switch (type) 158 { 159 case NodeKind.COMMENT: 160 msg = "Comment discarded"; 161 break; 162 case NodeKind.PI: 163 msg = "Processing instruction discarded"; 164 break; 165 default: 166 msg = "Extra data discarded"; 167 } 168 if (getXMLErrorHandler() != null) 169 getXMLErrorHandler().warning(new RepositoryException(RepositoryException.EXTRA_DATA_LOSS, msg)); 170 } 171 else 172 { 173 if (path.getPathID() == ROOT_PATH_ID) 174 wExtraNode.set(manager.buildUOID(DID, 0), ++rowNum, ROOT_PATH_ID, type, ++rootPosition, 0, data); 175 else 176 wExtraNode.set(getAnchor(), ++rowNum, path.getPathID(), type, 177 type == NodeKind.NAMESPACE ? 0 : getCurrentModelNode().incModelPosition(), 178 getCurrentModelNode().getCharOffset(), data); 179 batcher.addBatch(extraNodeRow.setParameters(wExtraNode), locator.getLineNumber(), locator.getColumnNumber()); 180 } 181 nodeCount++; 183 if (data != null) 184 docDataSize += data.length(); 185 } 186 187 protected AbstractModelNode getLogicalStructureNode(byte type, StoragePathMetadata path, String data, Locator locator) 188 throws SQLException , XMLDBCException 189 { 190 List nodeTableMappings = null, nodeColumnMappings = null; 191 short modelPosition = 0; 192 short rank = 0; 193 194 ModelNode parent = getCurrentModelNode(); 196 switch (type) 197 { 198 case NodeKind.TEXT: 199 nodeTableMappings = textTableMappingList; 200 modelPosition = parent.incModelPosition(); break; 202 203 case NodeKind.ELEMENT: 204 if (lastOID != -1) 205 getCurrentModelNode().flushExtraNode(); nodeTableMappings = path.getTableMappings(); 208 nodeColumnMappings = path.getColumnMappings(); 209 if (lastOID == -1) rootPosition++; 211 else 212 { 213 rank = parent.incChildCount(); 214 modelPosition = parent.incModelPosition(); } 216 break; 217 218 case NodeKind.ATTRIBUTE: 219 nodeTableMappings = path.getTableMappings(); 220 nodeColumnMappings = path.getColumnMappings(); 221 parent.incAttCount(); 222 break; 223 224 default : 225 } 226 227 ModelNode node = (ModelNode)stack.push(); 229 node.set(path, type, data, rank, modelPosition, locator); 230 231 if (path.isPersistent() || (type == NodeKind.TEXT)) { 233 235 if ((parent != null) && (parent.getPath().getStorageMode() == StoragePathMetadata.POTENTIAL_STRUCT)) 236 parent.schedulePathSignToggle(); 237 238 if (type == NodeKind.TEXT) 239 node.schedulePathSignToggle(); 240 241 node.setOID(++lastOID); 242 243 if (nodeTableMappings != null) 247 node.setTupleNode(storageBuffer.bufferizeNode(nodeTableMappings, locator)); 248 249 } 250 else if (!path.isPositionEnforced()) 251 node.addPositionExtraNode(); 252 253 if (nodeColumnMappings != null) 255 { 256 Iterator it = nodeColumnMappings.iterator(); 260 ColumnMapping column = null; 261 int refIndex; 262 while (it.hasNext()) 263 { 264 column = (ColumnMapping)it.next(); 265 refIndex = column.getTableRefIndex(); 266 if (refIndex != -1) 267 storageBuffer.getTupleFactory(column.getTableIndex()).addMasterTuple(storageBuffer.getTupleFactory(refIndex).getTuple()); 268 } 269 } 270 271 nodeCount++; 273 274 return node; 275 } 276 277 protected AbstractModelNode finalizeNode(Locator locator) 278 throws XMLDBCException, SQLException 279 { 280 ModelNode node = getCurrentModelNode(); 281 282 node.togglePathSignInData(); 284 285 node.last = lastOID; 287 288 List nodeColumnMappings = null; 290 StorageBuffer.BufferNode tupleNode = node.getTupleNode(); 291 PathMetadata path = (PathMetadata)node.getPath(); 292 293 switch (node.type) 294 { 295 case NodeKind.TEXT: 296 nodeColumnMappings = textColumnMappingList; 297 break; 298 299 case NodeKind.ELEMENT: 300 nodeColumnMappings = node.getPath().getColumnMappings(); 302 303 if ((nodeColumnMappings == null) && node.isLeaf()) 304 { 305 if ((path.getStorageMode() & POTENTIAL_DATA) != 0) 307 { 308 if (path.getReadColumnMapping() != null) 309 { 310 nodeColumnMappings = Collections.singletonList(path.getReadColumnMapping()); 312 if (tupleNode == null) 313 tupleNode = storageBuffer.bufferizeDefaultNode(path.getReadTableMapping(), locator); 314 else 315 tupleNode.addDefaultTuple(path.getReadTableMapping(), locator); 316 break; 317 } 318 else if (path.isMixed()) { 320 nodeColumnMappings = textColumnMappingList; 322 if (tupleNode == null) 323 tupleNode = storageBuffer.bufferizeDefaultNode(path.getTextTableMapping(), locator); 324 else 325 tupleNode.addDefaultTuple(path.getTextTableMapping(), locator); 326 break; 327 } 328 } 329 } 330 break; 331 332 case NodeKind.ATTRIBUTE: 333 nodeColumnMappings = node.getPath().getColumnMappings(); 334 if (nodeColumnMappings == null) 335 { 336 nodeColumnMappings = Collections.singletonList(path.getReadColumnMapping());; 337 tupleNode = storageBuffer.bufferizeDefaultNode(path.getReadTableMapping(), locator); 338 } 339 break; 340 default : 341 } 342 343 if (nodeColumnMappings != null) 345 { 346 Iterator it = nodeColumnMappings.iterator(); 347 ColumnMapping column = null; 348 349 while (it.hasNext()) 350 { 351 column = (ColumnMapping)it.next(); 352 storageBuffer.getTupleFactory(column.getTableIndex()).getTuple().addColumnMappingData(column, this); 353 } 354 } 355 356 if (tupleNode != null) 358 tupleNode.complete(); 359 360 node.flush(); 362 363 if (node.type == NodeKind.ELEMENT) 365 { 366 370 storageBuffer.flush(); 373 } 374 if (node.isLeaf()) 375 node.flushExtraNode(); 377 if (node.getData() != null) 379 docDataSize += node.getData().length(); 380 381 return (ModelNode)stack.pop(); 382 } 383 384 385 public void endModel() throws XMLDBCException, SQLException 386 { 387 super.endModel(); 388 389 idStmt.setString(1, docID); 390 idStmt.setLong(2, UDID); 391 idStmt.setTimestamp(3, new java.sql.Timestamp (System.currentTimeMillis())); 392 idStmt.setLong(4, nodeCount); 393 idStmt.setInt(5, (int)(docDataSize/nodeCount)); 394 batcher.addBatch(idStmt, 0, 0); 395 } 396 397 public void reset() 398 throws RepositoryException, SQLException 399 { 400 super.reset(); 401 lastOID = -1; 402 nodeCount = 0; 403 docDataSize = 0; 404 rootPosition = 0; 405 rowNum = 0; 406 DID = -1; 407 UDID = -1; 408 docID = null; 409 wExtraNode.clear(); 410 } 411 412 public void close() throws RepositoryException, SQLException 413 { 414 super.close(); 415 idStmt.close(); 416 idStmt = null; 417 nodeRow.close(); 418 extraNodeRow.close(); 419 } 420 421 public ModelNode getCurrentModelNode() 422 { 423 return (ModelNode)stack.top(); 424 } 425 426 public long getBucketOID() { return DID;} 430 public short getPathOID() 431 { 432 ModelBuilder.ModelNode node = getCurrentModelNode(); 433 if (node.negativePath()) 434 return (short)-node.path; 435 else 436 return node.path; 437 } 438 public String getDocumentID() 439 { return docID;} 440 public long getDocumentOID() 441 { return UDID;} 442 public long getOID() 443 {return getCurrentModelNode().oid;} 444 public long getUOID() 445 { return manager.buildUOID(DID, getCurrentModelNode().oid);} 446 public RecyclingStack.StackObject newStackObject() 447 { 448 return new ModelNode(); 449 } 450 451 455 private long getAnchor() 456 { 457 ModelNode wNode; 458 for (int i = stack.size() - 1; i >= 0 ; i--) 459 { 460 wNode = (ModelNode)stack.get(i); 461 if (wNode.oid >= 0) 462 return manager.buildUOID(DID, wNode.oid); 463 } 464 return -1; 465 } 466 467 public class ModelNode extends AbstractModelNode 471 implements RecyclingStack.StackObjectFactory 472 { 473 private static final String RCSRevision = "$Revision: 1.1 $"; 474 private static final String RCSName = "$Name: $"; 475 private int charOffset =0; 476 private RecyclingStack extraNodes = null; protected short attCount = 0; private short extraDataCount = 0; private short modelPosition = 0; 480 private boolean negativePath = false; 481 private boolean scheduleToggle = false; 482 int line = -1; 483 int column = -1; 484 485 ModelNode() 486 {} 487 488 void set(StoragePathMetadata path, byte type, String data, short rank, short modelPosition, Locator locator) 489 { 490 set(path, type, data, rank); 491 setModelPosition(modelPosition); 492 setLocation(locator); 493 } 494 495 public void clear() 496 { 497 super.clear(); 498 if (extraNodes != null) 499 extraNodes.clear(); 500 charOffset = 0; 501 attCount = 0; 502 extraDataCount = 0; 503 modelPosition = 0; 504 negativePath = false; 505 scheduleToggle = false; 506 line = -1; 507 column = -1; 508 } 509 510 public void setLocation(Locator locator) 511 { 512 if (locator != null) 513 { 514 line = locator.getLineNumber(); 515 column = locator.getColumnNumber(); 516 } 517 } 518 519 void setModelPosition(short pos) 520 { 521 modelPosition = pos; 522 } 523 524 boolean negativePath() 525 { 526 return negativePath; 527 } 528 529 void schedulePathSignToggle() 530 { 531 negativePath = true; 532 if (tupleNode != null) scheduleToggle = true; 534 } 535 536 void togglePathSignInData() 537 { 538 if (scheduleToggle && (tupleNode != null)) 539 tupleNode.changePathSign(); 540 } 541 542 void addPositionExtraNode() 543 { 544 if (extraNodes == null) 545 extraNodes = new RecyclingStack(this); 546 ExtraNode extra = (ExtraNode)extraNodes.push(); 547 extra.set(getAnchor(), ++rowNum, pathMetadata.getPathID(), type, modelPosition); 548 } 549 void flushExtraNode() throws SQLException , RepositoryException 550 { 551 if (extraNodes != null) 552 { 553 ExtraNode extra; 554 while((extra = (ExtraNode)extraNodes.pop()) != null) 555 { 556 batcher.addBatch(extraNodeRow.setParameters(extra), line, column); 557 } 558 } 559 } 560 void flush() throws SQLException , RepositoryException 561 { 562 if ((getNodeType() != NodeKind.TEXT) && ((pathMetadata.getStorageMode() & NO_STRUCT) == 0) 563 && !((pathMetadata.getStorageMode() == StoragePathMetadata.POTENTIAL_STRUCT) && isEmptyRange())) 564 batcher.addBatch(nodeRow.setParameters(this), line, column); 565 } 566 567 short incAttCount() 568 { 569 return ++attCount; 570 } 571 572 boolean isModelLeaf() 573 { 574 return ((childCount + attCount) == 0); 575 } 576 577 boolean isEmptyRange() 578 { 579 return (oid == last); 580 } 581 582 void setOID(long oid) 583 { 584 this.oid = oid; 585 } 586 587 public boolean setXSIinfo(String attName, String value) 588 throws RepositoryException 589 { 590 boolean nil = super.setXSIinfo(attName, value); 591 if (nil && pathMetadata.isNilImplicit()) return nil; 593 594 ExtraNode xsiNode; 595 if ((extraNodes == null) || (extraNodes.size() == 0)) 596 addPositionExtraNode(); 597 xsiNode = (ExtraNode)extraNodes.get(0); 598 if (xsiNode.type >= RepositoryConstants.XSI_NIL) { 600 xsiNode = (ExtraNode)extraNodes.push(); 601 xsiNode.set(lastOID, pathMetadata.getPathID(), type, modelPosition); 602 } 603 ElementPSVInfoset infoSet = validationContext.getCurrentInfoset(); 605 PSVInfoset attInfoSet = infoSet.getAttributePSVInfoset(SchemaConstants.XSI_URI, attName); 606 if (nil) 608 { 609 xsiNode.type = RepositoryConstants.XSI_NIL; 610 xsiNode.data = attInfoSet.getNormalizedValue().toString(); 611 } 612 else if (attName.equals(SchemaConstants.XSI_TYPE_ATTR)) 613 { 614 if ((pathMetadata.getReferenceColumnMapping() != null) 615 || ( 616 (pathMetadata.getTableMappings() != null) 617 && (pathMetadata.getTableMappings().size() > 0) 618 )) 619 throw new RepositoryException(RepositoryException.NOT_ALLOWED, 620 "Dynamic XML schema type binding (xsi:type) is not supported for mapped elements or attributes."); 621 xsiNode.type = RepositoryConstants.XSI_TYPE; 622 xsiNode.data = attInfoSet.getActualValue().toString(); 623 } 624 else if (attName.equals(SchemaConstants.XSI_SCHEMA_LOCATION_ATTR)) 625 { 626 xsiNode.type = RepositoryConstants.XSI_SCHEMA_LOCATION; 627 xsiNode.data = attInfoSet.getNormalizedValue().toString(); 628 } 629 else if (attName.equals(SchemaConstants.XSI_NO_NAMESPACE_SCHEMA_LOCATION_ATTR)) 630 { 631 xsiNode.type = RepositoryConstants.XSI_NO_NAMESPACE_SCHEMA_LOCATION; 632 xsiNode.data = attInfoSet.getNormalizedValue().toString(); 633 } 634 635 return nil; 637 } 638 639 public void incCharOffset(int length) 640 { 641 charOffset += length; 642 } 643 644 public short incModelPosition() 645 { 646 return ++extraDataCount; 647 } 648 649 int getCharOffset() 650 { 651 return charOffset; 652 } 653 654 public RecyclingStack.StackObject newStackObject() 655 { 656 return new ExtraNode(); 657 } 658 } 659 660 } 661 | Popular Tags |