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