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