001package de.deepamehta.core.impl; 002 003import de.deepamehta.core.model.AssociationModel; 004import de.deepamehta.core.model.DeepaMehtaObjectModel; 005import de.deepamehta.core.model.IndexMode; 006import de.deepamehta.core.model.RelatedAssociationModel; 007import de.deepamehta.core.model.RelatedTopicModel; 008import de.deepamehta.core.model.SimpleValue; 009import de.deepamehta.core.model.TopicModel; 010import de.deepamehta.core.service.ModelFactory; 011import de.deepamehta.core.storage.spi.DeepaMehtaTransaction; 012import de.deepamehta.core.storage.spi.DeepaMehtaStorage; 013 014import static java.util.Arrays.asList; 015import java.util.ArrayList; 016import java.util.Iterator; 017import java.util.List; 018import java.util.logging.Logger; 019 020 021 022// ### TODO: should methods return model *impl* objects? -> Yes! 023class StorageDecorator { 024 025 // ---------------------------------------------------------------------------------------------- Instance Variables 026 027 private DeepaMehtaStorage storage; 028 029 private final Logger logger = Logger.getLogger(getClass().getName()); 030 031 // ---------------------------------------------------------------------------------------------------- Constructors 032 033 StorageDecorator(DeepaMehtaStorage storage) { 034 this.storage = storage; 035 } 036 037 // ----------------------------------------------------------------------------------------- Package Private Methods 038 039 040 041 // === Topics === 042 043 /** 044 * @return The fetched topic. 045 * Note: its child topics are not fetched. 046 */ 047 final TopicModelImpl fetchTopic(long topicId) { 048 return (TopicModelImpl) storage.fetchTopic(topicId); 049 } 050 051 /** 052 * Looks up a single topic by exact value. 053 * <p> 054 * IMPORTANT: Looking up a topic this way requires the corresponding type to be indexed with indexing mode 055 * <code>dm4.core.key</code>. 056 * 057 * @return The fetched topic, or <code>null</code> if no such topic exists. 058 * Note: its child topics are not fetched. 059 * 060 * @throws RuntimeException if more than one topic is found. 061 */ 062 final TopicModelImpl fetchTopic(String key, SimpleValue value) { 063 return (TopicModelImpl) storage.fetchTopic(key, value.value()); 064 } 065 066 final List<TopicModelImpl> fetchTopics(String key, SimpleValue value) { 067 return (List<TopicModelImpl>) storage.fetchTopics(key, value.value()); 068 } 069 070 // --- 071 072 /** 073 * @return The fetched topics. 074 * Note: their child topics are not fetched. 075 */ 076 final List<TopicModelImpl> queryTopics(String key, SimpleValue value) { 077 return (List<TopicModelImpl>) storage.queryTopics(key, value.value()); 078 } 079 080 // --- 081 082 final Iterator<TopicModelImpl> fetchAllTopics() { 083 return (Iterator<TopicModelImpl>) storage.fetchAllTopics(); 084 } 085 086 // --- 087 088 /** 089 * Creates a topic. 090 * <p> 091 * Actually only the topic URI and type URI are stored and indexed. 092 * The topic value is not stored. 093 * 094 * @return FIXDOC ### the created topic. Note: 095 * - the topic URI is initialzed and persisted. 096 * - the topic value is initialzed but not persisted. 097 * - the type URI is initialzed but not persisted. 098 */ 099 final void storeTopic(TopicModel model) { 100 storage.storeTopic(model); 101 } 102 103 /** 104 * Stores and indexes the topic's URI. 105 */ 106 final void storeTopicUri(long topicId, String uri) { 107 storage.storeTopicUri(topicId, uri); 108 } 109 110 final void storeTopicTypeUri(long topicId, String topicTypeUri) { 111 storage.storeTopicTypeUri(topicId, topicTypeUri); 112 } 113 114 // --- 115 116 /** 117 * Convenience method (no indexing). 118 */ 119 final void storeTopicValue(long topicId, SimpleValue value) { 120 storeTopicValue(topicId, value, asList(IndexMode.OFF), null, null); 121 } 122 123 /** 124 * Stores and indexes the topic's value. ### TODO: separate storing/indexing? 125 */ 126 final void storeTopicValue(long topicId, SimpleValue value, List<IndexMode> indexModes, String indexKey, 127 SimpleValue indexValue) { 128 storage.storeTopicValue(topicId, value, indexModes, indexKey, indexValue); 129 } 130 131 final void indexTopicValue(long topicId, IndexMode indexMode, String indexKey, SimpleValue indexValue) { 132 storage.indexTopicValue(topicId, indexMode, indexKey, indexValue); 133 } 134 135 // --- 136 137 /** 138 * Deletes the topic. 139 * <p> 140 * Prerequisite: the topic has no relations. 141 */ 142 final void _deleteTopic(long topicId) { 143 storage.deleteTopic(topicId); 144 } 145 146 147 148 // === Associations === 149 150 final AssociationModelImpl fetchAssociation(long assocId) { 151 return (AssociationModelImpl) storage.fetchAssociation(assocId); 152 } 153 154 /** 155 * Looks up a single association by exact value. 156 * If no such association exists <code>null</code> is returned. 157 * If more than one association is found a runtime exception is thrown. 158 * <p> 159 * IMPORTANT: Looking up an association this way requires the corresponding type to be indexed with indexing mode 160 * <code>dm4.core.key</code>. 161 * 162 * @return The fetched association. 163 * Note: its child topics are not fetched. 164 */ 165 final AssociationModelImpl fetchAssociation(String key, SimpleValue value) { 166 return (AssociationModelImpl) storage.fetchAssociation(key, value.value()); 167 } 168 169 final List<AssociationModelImpl> fetchAssociations(String key, SimpleValue value) { 170 return (List<AssociationModelImpl>) storage.fetchAssociations(key, value.value()); 171 } 172 173 // --- 174 175 /** 176 * Convenience method (checks singularity). 177 * 178 * Returns the association between two topics, qualified by association type and both role types. 179 * If no such association exists <code>null</code> is returned. 180 * If more than one association exist, a runtime exception is thrown. 181 * 182 * @param assocTypeUri Association type filter. Pass <code>null</code> to switch filter off. 183 * ### FIXME: for methods with a singular return value all filters should be mandatory 184 */ 185 final AssociationModelImpl fetchAssociation(String assocTypeUri, long topicId1, long topicId2, 186 String roleTypeUri1, String roleTypeUri2) { 187 List<AssociationModelImpl> assocs = fetchAssociations(assocTypeUri, topicId1, topicId2, roleTypeUri1, 188 roleTypeUri2); 189 switch (assocs.size()) { 190 case 0: 191 return null; 192 case 1: 193 return assocs.get(0); 194 default: 195 throw new RuntimeException("Ambiguity: there are " + assocs.size() + " \"" + assocTypeUri + 196 "\" associations (topicId1=" + topicId1 + ", topicId2=" + topicId2 + ", " + 197 "roleTypeUri1=\"" + roleTypeUri1 + "\", roleTypeUri2=\"" + roleTypeUri2 + "\")"); 198 } 199 } 200 201 /** 202 * Returns the associations between two topics. If no such association exists an empty set is returned. 203 * 204 * @param assocTypeUri Association type filter. Pass <code>null</code> to switch filter off. 205 */ 206 final List<AssociationModelImpl> fetchAssociations(String assocTypeUri, long topicId1, long topicId2, 207 String roleTypeUri1, String roleTypeUri2) { 208 return (List<AssociationModelImpl>) storage.fetchAssociations(assocTypeUri, topicId1, topicId2, roleTypeUri1, 209 roleTypeUri2); 210 } 211 212 // --- 213 214 /** 215 * Convenience method (checks singularity). 216 */ 217 final AssociationModelImpl fetchAssociationBetweenTopicAndAssociation(String assocTypeUri, long topicId, 218 long assocId, String topicRoleTypeUri, String assocRoleTypeUri) { 219 List<AssociationModelImpl> assocs = fetchAssociationsBetweenTopicAndAssociation(assocTypeUri, topicId, assocId, 220 topicRoleTypeUri, assocRoleTypeUri); 221 switch (assocs.size()) { 222 case 0: 223 return null; 224 case 1: 225 return assocs.get(0); 226 default: 227 throw new RuntimeException("Ambiguity: there are " + assocs.size() + " \"" + assocTypeUri + 228 "\" associations (topicId=" + topicId + ", assocId=" + assocId + ", " + 229 "topicRoleTypeUri=\"" + topicRoleTypeUri + "\", assocRoleTypeUri=\"" + assocRoleTypeUri + "\")"); 230 } 231 } 232 233 final List<AssociationModelImpl> fetchAssociationsBetweenTopicAndAssociation(String assocTypeUri, long topicId, 234 long assocId, String topicRoleTypeUri, String assocRoleTypeUri) { 235 return (List<AssociationModelImpl>) storage.fetchAssociationsBetweenTopicAndAssociation(assocTypeUri, topicId, 236 assocId, topicRoleTypeUri, assocRoleTypeUri); 237 } 238 239 // --- 240 241 final Iterator<AssociationModelImpl> fetchAllAssociations() { 242 return (Iterator<AssociationModelImpl>) storage.fetchAllAssociations(); 243 } 244 245 final long[] fetchPlayerIds(long assocId) { 246 return storage.fetchPlayerIds(assocId); 247 } 248 249 // --- 250 251 /** 252 * Stores and indexes the association's URI. 253 */ 254 final void storeAssociationUri(long assocId, String uri) { 255 storage.storeAssociationUri(assocId, uri); 256 } 257 258 final void storeAssociationTypeUri(long assocId, String assocTypeUri) { 259 storage.storeAssociationTypeUri(assocId, assocTypeUri); 260 } 261 262 final void storeRoleTypeUri(long assocId, long playerId, String roleTypeUri) { 263 storage.storeRoleTypeUri(assocId, playerId, roleTypeUri); 264 } 265 266 // --- 267 268 /** 269 * Convenience method (no indexing). 270 */ 271 final void storeAssociationValue(long assocId, SimpleValue value) { 272 storeAssociationValue(assocId, value, asList(IndexMode.OFF), null, null); 273 } 274 275 /** 276 * Stores and indexes the association's value. ### TODO: separate storing/indexing? 277 */ 278 final void storeAssociationValue(long assocId, SimpleValue value, List<IndexMode> indexModes, String indexKey, 279 SimpleValue indexValue) { 280 storage.storeAssociationValue(assocId, value, indexModes, indexKey, indexValue); 281 } 282 283 final void indexAssociationValue(long assocId, IndexMode indexMode, String indexKey, SimpleValue indexValue) { 284 storage.indexAssociationValue(assocId, indexMode, indexKey, indexValue); 285 } 286 287 // --- 288 289 final void storeAssociation(AssociationModel model) { 290 storage.storeAssociation(model); 291 } 292 293 final void _deleteAssociation(long assocId) { 294 storage.deleteAssociation(assocId); 295 } 296 297 298 299 // === Generic Object === 300 301 final DeepaMehtaObjectModelImpl fetchObject(long id) { 302 return (DeepaMehtaObjectModelImpl) storage.fetchObject(id); 303 } 304 305 306 307 // === Traversal === 308 309 /** 310 * @return The fetched associations. 311 * Note: their child topics are not fetched. 312 */ 313 final List<AssociationModelImpl> fetchTopicAssociations(long topicId) { 314 return (List<AssociationModelImpl>) storage.fetchTopicAssociations(topicId); 315 } 316 317 final List<AssociationModelImpl> fetchAssociationAssociations(long assocId) { 318 return (List<AssociationModelImpl>) storage.fetchAssociationAssociations(assocId); 319 } 320 321 // --- 322 323 /** 324 * Convenience method (checks singularity). 325 * 326 * @param assocTypeUri may be null 327 * @param myRoleTypeUri may be null 328 * @param othersRoleTypeUri may be null 329 * @param othersTopicTypeUri may be null 330 * 331 * @return The fetched topic. 332 * Note: its child topics are not fetched. 333 */ 334 final RelatedTopicModelImpl fetchTopicRelatedTopic(long topicId, String assocTypeUri, String myRoleTypeUri, 335 String othersRoleTypeUri, String othersTopicTypeUri) { 336 List<RelatedTopicModelImpl> topics = fetchTopicRelatedTopics(topicId, assocTypeUri, myRoleTypeUri, 337 othersRoleTypeUri, othersTopicTypeUri); 338 switch (topics.size()) { 339 case 0: 340 return null; 341 case 1: 342 return topics.iterator().next(); 343 default: 344 throw new RuntimeException("Ambiguity: there are " + topics.size() + " related topics (topicId=" + 345 topicId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 346 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersTopicTypeUri=\"" + othersTopicTypeUri + "\")"); 347 } 348 } 349 350 /** 351 * @param assocTypeUri may be null 352 * @param myRoleTypeUri may be null 353 * @param othersRoleTypeUri may be null 354 * @param othersTopicTypeUri may be null 355 * 356 * @return The fetched topics. 357 * Note: their child topics are not fetched. 358 */ 359 final List<RelatedTopicModelImpl> fetchTopicRelatedTopics(long topicId, String assocTypeUri, String myRoleTypeUri, 360 String othersRoleTypeUri, String othersTopicTypeUri) { 361 return (List<RelatedTopicModelImpl>) storage.fetchTopicRelatedTopics(topicId, assocTypeUri, myRoleTypeUri, 362 othersRoleTypeUri, othersTopicTypeUri); 363 } 364 365 /** 366 * Convenience method (receives *list* of association types). 367 * 368 * @param assocTypeUris may *not* be null 369 * @param myRoleTypeUri may be null 370 * @param othersRoleTypeUri may be null 371 * @param othersTopicTypeUri may be null 372 * 373 * @return The fetched topics. 374 * Note: their child topics are not fetched. 375 */ 376 final List<RelatedTopicModelImpl> fetchTopicRelatedTopics(long topicId, List<String> assocTypeUris, 377 String myRoleTypeUri, String othersRoleTypeUri, String othersTopicTypeUri) { 378 List<RelatedTopicModelImpl> result = new ArrayList(); 379 for (String assocTypeUri : assocTypeUris) { 380 result.addAll(fetchTopicRelatedTopics(topicId, assocTypeUri, myRoleTypeUri, othersRoleTypeUri, 381 othersTopicTypeUri)); 382 } 383 return result; 384 } 385 386 // --- 387 388 /** 389 * Convenience method (checks singularity). 390 * 391 * @return The fetched association. 392 * Note: its child topics are not fetched. 393 */ 394 final RelatedAssociationModelImpl fetchTopicRelatedAssociation(long topicId, String assocTypeUri, 395 String myRoleTypeUri, String othersRoleTypeUri, String othersAssocTypeUri) { 396 List<RelatedAssociationModelImpl> assocs = fetchTopicRelatedAssociations(topicId, assocTypeUri, myRoleTypeUri, 397 othersRoleTypeUri, othersAssocTypeUri); 398 switch (assocs.size()) { 399 case 0: 400 return null; 401 case 1: 402 return assocs.iterator().next(); 403 default: 404 throw new RuntimeException("Ambiguity: there are " + assocs.size() + " related associations (topicId=" + 405 topicId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 406 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersAssocTypeUri=\"" + othersAssocTypeUri + "\")"); 407 } 408 } 409 410 /** 411 * @param assocTypeUri may be null 412 * @param myRoleTypeUri may be null 413 * @param othersRoleTypeUri may be null 414 * @param othersAssocTypeUri may be null 415 * 416 * @return The fetched associations. 417 * Note: their child topics are not fetched. 418 */ 419 final List<RelatedAssociationModelImpl> fetchTopicRelatedAssociations(long topicId, String assocTypeUri, 420 String myRoleTypeUri, String othersRoleTypeUri, String othersAssocTypeUri) { 421 return (List<RelatedAssociationModelImpl>) storage.fetchTopicRelatedAssociations(topicId, assocTypeUri, 422 myRoleTypeUri, othersRoleTypeUri, othersAssocTypeUri); 423 } 424 425 // --- 426 427 /** 428 * Convenience method (checks singularity). 429 * 430 * @return The fetched topic. 431 * Note: its child topics are not fetched. 432 */ 433 final RelatedTopicModelImpl fetchAssociationRelatedTopic(long assocId, String assocTypeUri, String myRoleTypeUri, 434 String othersRoleTypeUri, String othersTopicTypeUri) { 435 List<RelatedTopicModelImpl> topics = fetchAssociationRelatedTopics(assocId, assocTypeUri, myRoleTypeUri, 436 othersRoleTypeUri, othersTopicTypeUri); 437 switch (topics.size()) { 438 case 0: 439 return null; 440 case 1: 441 return topics.iterator().next(); 442 default: 443 throw new RuntimeException("Ambiguity: there are " + topics.size() + " related topics (assocId=" + 444 assocId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 445 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersTopicTypeUri=\"" + othersTopicTypeUri + "\")"); 446 } 447 } 448 449 /** 450 * @return The fetched topics. 451 * Note: their child topics are not fetched. 452 */ 453 final List<RelatedTopicModelImpl> fetchAssociationRelatedTopics(long assocId, String assocTypeUri, 454 String myRoleTypeUri, String othersRoleTypeUri, String othersTopicTypeUri) { 455 return (List<RelatedTopicModelImpl>) storage.fetchAssociationRelatedTopics(assocId, assocTypeUri, myRoleTypeUri, 456 othersRoleTypeUri, othersTopicTypeUri); 457 } 458 459 /** 460 * Convenience method (receives *list* of association types). 461 * 462 * @param assocTypeUris may be null 463 * @param myRoleTypeUri may be null 464 * @param othersRoleTypeUri may be null 465 * @param othersTopicTypeUri may be null 466 * 467 * @return The fetched topics. 468 * Note: their child topics are not fetched. 469 */ 470 final List<RelatedTopicModelImpl> fetchAssociationRelatedTopics(long assocId, List<String> assocTypeUris, 471 String myRoleTypeUri, String othersRoleTypeUri, String othersTopicTypeUri) { 472 List<RelatedTopicModelImpl> result = new ArrayList(); 473 for (String assocTypeUri : assocTypeUris) { 474 result.addAll(fetchAssociationRelatedTopics(assocId, assocTypeUri, myRoleTypeUri, othersRoleTypeUri, 475 othersTopicTypeUri)); 476 } 477 return result; 478 } 479 480 // --- 481 482 /** 483 * Convenience method (checks singularity). 484 * 485 * @return The fetched association. 486 * Note: its child topics are not fetched. 487 */ 488 final RelatedAssociationModelImpl fetchAssociationRelatedAssociation(long assocId, String assocTypeUri, 489 String myRoleTypeUri, String othersRoleTypeUri, String othersAssocTypeUri) { 490 List<RelatedAssociationModelImpl> assocs = fetchAssociationRelatedAssociations(assocId, assocTypeUri, 491 myRoleTypeUri, othersRoleTypeUri, othersAssocTypeUri); 492 switch (assocs.size()) { 493 case 0: 494 return null; 495 case 1: 496 return assocs.iterator().next(); 497 default: 498 throw new RuntimeException("Ambiguity: there are " + assocs.size() + " related associations (assocId=" + 499 assocId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 500 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersAssocTypeUri=\"" + othersAssocTypeUri + 501 "\"),\nresult=" + assocs); 502 } 503 } 504 505 /** 506 * @param assocTypeUri may be null 507 * @param myRoleTypeUri may be null 508 * @param othersRoleTypeUri may be null 509 * @param othersAssocTypeUri may be null 510 * 511 * @return The fetched associations. 512 * Note: their child topics are not fetched. 513 */ 514 final List<RelatedAssociationModelImpl> fetchAssociationRelatedAssociations(long assocId, String assocTypeUri, 515 String myRoleTypeUri, String othersRoleTypeUri, String othersAssocTypeUri) { 516 return (List<RelatedAssociationModelImpl>) storage.fetchAssociationRelatedAssociations(assocId, assocTypeUri, 517 myRoleTypeUri, othersRoleTypeUri, othersAssocTypeUri); 518 } 519 520 // --- 521 522 /** 523 * Convenience method (checks singularity). 524 * 525 * @param objectId id of a topic or an association 526 * @param assocTypeUri may be null 527 * @param myRoleTypeUri may be null 528 * @param othersRoleTypeUri may be null 529 * @param othersTopicTypeUri may be null 530 * 531 * @return The fetched topic. 532 * Note: its child topics are not fetched. 533 */ 534 final RelatedTopicModelImpl fetchRelatedTopic(long objectId, String assocTypeUri, String myRoleTypeUri, 535 String othersRoleTypeUri, String othersTopicTypeUri) { 536 List<RelatedTopicModelImpl> topics = fetchRelatedTopics(objectId, assocTypeUri, myRoleTypeUri, 537 othersRoleTypeUri, othersTopicTypeUri); 538 switch (topics.size()) { 539 case 0: 540 return null; 541 case 1: 542 return topics.iterator().next(); 543 default: 544 throw new RuntimeException("Ambiguity: there are " + topics.size() + " related topics (objectId=" + 545 objectId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 546 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersTopicTypeUri=\"" + othersTopicTypeUri + "\")"); 547 } 548 } 549 550 /** 551 * @param objectId id of a topic or an association 552 * @param assocTypeUri may be null 553 * @param myRoleTypeUri may be null 554 * @param othersRoleTypeUri may be null 555 * @param othersTopicTypeUri may be null 556 * 557 * @return The fetched topics. 558 * Note: their child topics are not fetched. 559 */ 560 final List<RelatedTopicModelImpl> fetchRelatedTopics(long objectId, String assocTypeUri, String myRoleTypeUri, 561 String othersRoleTypeUri, String othersTopicTypeUri) { 562 return (List<RelatedTopicModelImpl>) storage.fetchRelatedTopics(objectId, assocTypeUri, myRoleTypeUri, 563 othersRoleTypeUri, othersTopicTypeUri); 564 } 565 566 // ### TODO: decorator for fetchRelatedAssociations() 567 568 569 570 // === Properties === 571 572 final Object fetchProperty(long id, String propUri) { 573 return storage.fetchProperty(id, propUri); 574 } 575 576 final boolean hasProperty(long id, String propUri) { 577 return storage.hasProperty(id, propUri); 578 } 579 580 // --- 581 582 final List<TopicModelImpl> fetchTopicsByProperty(String propUri, Object propValue) { 583 return (List<TopicModelImpl>) storage.fetchTopicsByProperty(propUri, propValue); 584 } 585 586 final List<TopicModelImpl> fetchTopicsByPropertyRange(String propUri, Number from, Number to) { 587 return (List<TopicModelImpl>) storage.fetchTopicsByPropertyRange(propUri, from, to); 588 } 589 590 final List<AssociationModelImpl> fetchAssociationsByProperty(String propUri, Object propValue) { 591 return (List<AssociationModelImpl>) storage.fetchAssociationsByProperty(propUri, propValue); 592 } 593 594 final List<AssociationModelImpl> fetchAssociationsByPropertyRange(String propUri, Number from, Number to) { 595 return (List<AssociationModelImpl>) storage.fetchAssociationsByPropertyRange(propUri, from, to); 596 } 597 598 // --- 599 600 final void storeTopicProperty(long topicId, String propUri, Object propValue, boolean addToIndex) { 601 storage.storeTopicProperty(topicId, propUri, propValue, addToIndex); 602 } 603 604 final void storeAssociationProperty(long assocId, String propUri, Object propValue, boolean addToIndex) { 605 storage.storeAssociationProperty(assocId, propUri, propValue, addToIndex); 606 } 607 608 // --- 609 610 final void indexTopicProperty(long topicId, String propUri, Object propValue) { 611 storage.indexTopicProperty(topicId, propUri, propValue); 612 } 613 614 final void indexAssociationProperty(long assocId, String propUri, Object propValue) { 615 storage.indexAssociationProperty(assocId, propUri, propValue); 616 } 617 618 // --- 619 620 final void removeTopicProperty(long topicId, String propUri) { 621 storage.deleteTopicProperty(topicId, propUri); 622 } 623 624 final void removeAssociationProperty(long assocId, String propUri) { 625 storage.deleteAssociationProperty(assocId, propUri); 626 } 627 628 629 630 // === DB === 631 632 final DeepaMehtaTransaction beginTx() { 633 return storage.beginTx(); 634 } 635 636 /** 637 * Initializes the database. 638 * Prerequisite: there is an open transaction. 639 * 640 * @return <code>true</code> if a clean install is detected, <code>false</code> otherwise. 641 */ 642 final boolean init() { 643 boolean isCleanInstall = storage.setupRootNode(); 644 if (isCleanInstall) { 645 logger.info("Clean install detected -- Starting with a fresh DB"); 646 storeMigrationNr(0); 647 } 648 return isCleanInstall; 649 } 650 651 final void shutdown() { 652 storage.shutdown(); 653 } 654 655 // --- 656 657 final int fetchMigrationNr() { 658 return (Integer) fetchProperty(0, "core_migration_nr"); 659 } 660 661 final void storeMigrationNr(int migrationNr) { 662 storage.storeTopicProperty(0, "core_migration_nr", migrationNr, false); // addToIndex=false 663 } 664 665 // --- 666 667 final Object getDatabaseVendorObject() { 668 return storage.getDatabaseVendorObject(); 669 } 670 671 final Object getDatabaseVendorObject(long objectId) { 672 return storage.getDatabaseVendorObject(objectId); 673 } 674}