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