diff --git a/ruby/neo4j/driver/bookmark_manager_config.rb b/ruby/neo4j/driver/bookmark_manager_config.rb new file mode 100644 index 00000000..8d65165a --- /dev/null +++ b/ruby/neo4j/driver/bookmark_manager_config.rb @@ -0,0 +1,48 @@ +module Neo4j + module Driver + # Bookmark configuration used to configure bookmark manager supplied by {@link BookmarkManagers#defaultManager(BookmarkManagerConfig)}. + class BookmarkManagerConfig + attr_reader :initial_bookmarks, :bookmarks_consumer, :bookmarks_supplier + def initialize(builder) + @initial_bookmarks = builder.initial_bookmarks + @bookmarks_consumer = builder.bookmarks_consumer + @bookmarks_supplier = builder.bookmarks_supplier + end + + # Creates a new {@link BookmarkManagerConfigBuilder} used to construct a configuration object. + # @return a bookmark manager configuration builder. + def builder + BookmarkManagerConfigBuilder.new + end + + # Builder used to configure {@link BookmarkManagerConfig} which will be used to create a bookmark manager. + class BookmarkManagerConfigBuilder + def with_initial_bookmarks(database_to_bookmarks) + Internal::Validator.require_non_nil!(database_to_bookmarks) + @initial_bookmarks = database_to_bookmarks + end + + # Provide bookmarks consumer. + # The consumer will be called outside bookmark manager's synchronisation lock. + # @param bookmarksConsumer bookmarks consumer + # @return this builder + def with_bookmarks_consumer(bookmarks_consumer) + @bookmarks_consumer = bookmarks_consumer + end + + # Provide bookmarks supplier. + # The supplied bookmarks will be served alongside the bookmarks served by the bookmark manager. The supplied bookmarks will not be stored nor managed by the bookmark manager. + # The supplier will be called outside bookmark manager's synchronisation lock. + # @param bookmarksSupplier the bookmarks supplier + # @return this builder + def with_bookmarks_supplier(bookmarks_supplier) + @bookmarks_supplier = bookmarks_supplier + end + + def build + BookmarkManagerConfig.new(self) + end + end + end + end +end diff --git a/ruby/neo4j/driver/bookmark_managers.rb b/ruby/neo4j/driver/bookmark_managers.rb new file mode 100644 index 00000000..8b8d6110 --- /dev/null +++ b/ruby/neo4j/driver/bookmark_managers.rb @@ -0,0 +1,13 @@ +module Neo4j + module Driver + # Setups new instances of {@link BookmarkManager}. + class BookmarkManagers + # Setups a new instance of bookmark manager that can be used in {@link org.neo4j.driver.SessionConfig.Builder#withBookmarkManager(BookmarkManager)}. + # @param config the bookmark manager configuration + # @return the bookmark manager + def self.default_manager(config) + Internal::Neo4jBookmarkManager.new(config.initial_bookmarks, config.bookmarks_consumer, config.bookmarks_supplier) + end + end + end +end diff --git a/ruby/neo4j/driver/internal/neo4j_bookmark_manager.rb b/ruby/neo4j/driver/internal/neo4j_bookmark_manager.rb new file mode 100644 index 00000000..b1c5eca1 --- /dev/null +++ b/ruby/neo4j/driver/internal/neo4j_bookmark_manager.rb @@ -0,0 +1,54 @@ +module Neo4j::Driver + module Internal + # A basic {@link BookmarkManager} implementation. + class Neo4jBookmarkManager + SERIAL_VERSION_UID = 6615186840717102303 + RW_LOCK = Concurrent::ReentrantReadWriteLock.new + + def initialize(initial_bookmarks, update_listener, bookmarks_supplier) + Internal::Validator.require_non_nil!(initial_bookmarks, "initial_bookmarks must not be nil") + @database_to_bookmarks = initial_bookmarks + @update_listener = update_listener + @bookmarks_supplier = bookmarks_supplier + end + + def update_bookmarks(database, previous_bookmarks, new_bookmarks) + immutable_bookmarks = Util::LockUtil.execute_with_lock(RW_LOCK.with_write_lock, -> {@database_to_bookmarks.compute(database, + -> (_, bookmarks) { updated_bookmarks = { } + unless bookmarks.nil? + bookmarks.stream + .filter(-> (bookmark) { !previous_bookmarks.include?(bookmark) } ) + .each(&:updated_bookmarks::add)} + end + updated_bookmarks = new_bookmarks + })}) + + unless update_listener.nil? + update_listener.accept(database, immutable_bookmarks) + end + end + + def bookmarks(database) + immutable_bookmarks = Util::LockUtil.execute_with_lock(RW_LOCK.with_read_lock, -> { @database_to_bookmarks.get_or_default(database, []) }) + + unless @bookmarks_supplier.nil? + bookmarks = @bookmarks_supplier.get_bookmarks(database) + immutable_bookmarks = bookmarks + end + + immutable_bookmarks + end + + def all_bookmarks + immutable_bookmarks = Util::LockUtil.execute_with_lock(RW_LOCK.with_read_lock, -> { @database_to_bookmarks.values.stream }) + + unless @bookmarks_supplier.nil? + bookmarks = @bookmarks_supplier.get_all_bookmarks + immutable_bookmarks = bookmarks + end + + immutable_bookmarks + end + end + end +end diff --git a/ruby/neo4j/driver/internal/no_op_bookmark_manager.rb b/ruby/neo4j/driver/internal/no_op_bookmark_manager.rb new file mode 100644 index 00000000..51b6c4a3 --- /dev/null +++ b/ruby/neo4j/driver/internal/no_op_bookmark_manager.rb @@ -0,0 +1,22 @@ +module Neo4j::Driver + module Internal + # A no-op {@link BookmarkManager} implementation. + class NoOpBookmarkManager + include BookmarkManagers + + def update_bookmarks(database, previous_bookmarks, new_bookmarks) + end + + def bookmarks(database) + [] + end + + def all_bookmarks + [] + end + + def forget(database) + end + end + end +end