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 }