Skip to content

Setup : LiveObject plugin #1085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 22, 2025
Merged

Setup : LiveObject plugin #1085

merged 5 commits into from
May 22, 2025

Conversation

sacOO7
Copy link
Collaborator

@sacOO7 sacOO7 commented May 19, 2025

Fixed #1084

  1. Declared required liveobject java interfaces
  2. Implemented liveobject interface for LiveObjectsPlugin

Summary by CodeRabbit

  • New Features

    • Introduced Live Objects support, enabling real-time collaborative data structures such as live maps and live counters.
    • Added new channel modes and protocol message types to support object and annotation messages.
    • Provided plugin architecture for integrating and managing live objects on channels.
  • Bug Fixes

    • No user-facing bug fixes included in this release.
  • Chores

    • Updated project configuration and dependencies to support new features and modules.

Copy link

coderabbitai bot commented May 19, 2025

"""

Walkthrough

This change introduces the LiveObjects plugin architecture into the codebase. It adds new interfaces and implementations for live data objects, updates core SDK classes to integrate with the plugin, and sets up a dedicated Kotlin module for LiveObjects. Build scripts, enums, and protocol message types are extended to support new object-related operations and capabilities.

Changes

File(s) / Path(s) Change Summary
live-objects/build.gradle.kts, live-objects/gradle.properties, settings.gradle.kts Added new Gradle module for LiveObjects with build configuration and project properties.
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt, live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt Added Kotlin implementations for LiveObjects and LiveObjectsPlugin with method stubs and resource management.
lib/src/main/java/io/ably/lib/objects/LiveObjects.java, LiveMap.java, LiveCounter.java Introduced new interfaces for live maps, counters, and objects with synchronous and asynchronous methods.
lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java Added plugin interface for managing LiveObjects instances per channel.
lib/src/main/java/io/ably/lib/plugins/PluginInstance.java, PluginConnectionAdapter.java Introduced plugin lifecycle and connection adapter interfaces for protocol message handling.
lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java, Connection.java, ChannelBase.java, Channel.java Updated core classes to support optional LiveObjectsPlugin integration, plugin lifecycle, and channel access.
lib/src/main/java/io/ably/lib/realtime/Connection.java, lib/src/main/java/io/ably/lib/transport/ConnectionManager.java Updated constructors and logic to pass and utilize LiveObjectsPlugin, handle new protocol actions, and implement plugin connection adapter.
lib/src/main/java/io/ably/lib/types/ChannelMode.java, ProtocolMessage.java Extended enums to support new object and annotation message types and capabilities.
android/build.gradle.kts, java/build.gradle.kts, gradle/libs.versions.toml Added JetBrains annotations as a compile-only dependency for code quality and nullability contracts.
lib/src/test/java/io/ably/lib/test/realtime/ConnectionManagerTest.java Adjusted test to match updated ConnectionManager constructor signature.

Sequence Diagram(s)

sequenceDiagram
    participant Client as AblyRealtime
    participant Plugin as LiveObjectsPlugin
    participant Channel as Channel
    participant ConnMgr as ConnectionManager

    Client->>Plugin: tryInitializeLiveObjectsPlugin()
    Plugin-->>Client: LiveObjectsPlugin instance or null

    Client->>ConnMgr: new ConnectionManager(..., liveObjectsPlugin)
    Client->>Channel: new Channel(..., liveObjectsPlugin)
    Channel->>Plugin: getObjects()

    Note over ConnMgr,Plugin: On protocol message (object/object_sync)
    ConnMgr->>Plugin: handle(message)
Loading

Assessment against linked issues

Objective Addressed Explanation
Create separate Kotlin module for LiveObjects compatible with Java (#1084)
Ensure high cohesion and low coupling with core SDK (#1084)
Integrate plugin architecture and interfaces for LiveObjects (#1084)
Update core SDK to support optional plugin and protocol extensions (#1084)

Poem

In burrows deep, a plugin grew,
LiveObjects hopping into view.
With maps and counters, lively and bright,
Kotlin and Java now unite!
Channels and connections, all in sync,
This rabbit’s code is in the pink.
🐇✨
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 7fab87f and cd7d075.

📒 Files selected for processing (7)
  • lib/src/main/java/io/ably/lib/objects/LiveCounter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (1 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (7 hunks)
  • lib/src/main/java/io/ably/lib/realtime/ChannelBase.java (4 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • lib/src/main/java/io/ably/lib/realtime/ChannelBase.java
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java
  • lib/src/main/java/io/ably/lib/objects/LiveCounter.java
  • lib/src/main/java/io/ably/lib/objects/LiveMap.java
  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: check-realtime
  • GitHub Check: check (29)
  • GitHub Check: check (19)
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check (21)
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check (24)
  • GitHub Check: build
  • GitHub Check: check
  • GitHub Check: check-rest

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 19, 2025 12:31 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 19, 2025 12:32 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (7)
lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (1)

19-24: Consider adding lifecycle information to dispose method documentation

While the documentation clearly explains what the method does, consider adding information about when this method should be called and what happens to any resources held by the LiveObjects instance after disposal.

/**
 * Disposes of the LiveObjects instance associated with the specified channel name.
 *
+ * This method should be called when the channel is no longer needed to free up resources.
+ * After disposal, any references to the LiveObjects instance should be considered invalid.
 *
 * @param channelName the name of the channel whose LiveObjects instance is to be removed.
 */
lib/src/main/java/io/ably/lib/objects/batch/BatchContextLiveMap.java (1)

49-56: Consider clarifying the purpose of the value parameter in remove method

The remove method requires both a key and a value, which is unusual for map operations that typically only require the key. If this is for optimistic concurrency control (i.e., the value must match what's currently stored), it should be documented explicitly.

/**
 * Removes the specified key-value pair from the live map.
 *
 * @param keyName the name of the key to remove.
- * @param value the value associated with the key to remove.
+ * @param value the expected value associated with the key; removal occurs only if the current value matches.
 */
void remove(String keyName, Object value);
lib/src/main/java/io/ably/lib/objects/LiveMap.java (1)

49-56: Consider clarifying the value parameter's role in the remove method

Similar to BatchContextLiveMap, the remove method takes both key and value parameters. If this is for optimistic concurrency control, this should be explicitly documented.

/**
 * Removes the specified key and its associated value from the map.
 *
 * @param keyName the key to be removed.
- * @param value the value associated with the key to be removed.
+ * @param value the expected value associated with the key; removal occurs only if the current value matches.
 */
void remove(String keyName, Object value);
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1)

7-49: Add implementation timeline or specs for TODOs

All methods currently use TODO("Not yet implemented"). Consider adding more specific information in these TODO messages, such as implementation plans, requirements, or JIRA ticket references to make it clear what the expected behavior should be and to guide future implementation work.

-override fun getRoot(): LiveMap {
-    TODO("Not yet implemented")
+override fun getRoot(): LiveMap {
+    TODO("Implement according to live objects spec - LO-123")
lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (1)

45-50: Consider adding a public method to check if LiveObjects plugin is available

The LiveObjectsPlugin is initialized via reflection, making it optional, but there's no public way to check if it's available. Consider adding a hasLiveObjectsPlugin() method to allow clients to determine if they can use LiveObjects functionality.

+/**
+ * Checks if the LiveObjects plugin is available.
+ *
+ * @return true if the LiveObjects plugin is available, false otherwise.
+ */
+public boolean hasLiveObjectsPlugin() {
+    return liveObjectsPlugin != null;
+}
lib/src/main/java/io/ably/lib/objects/LiveObjects.java (2)

22-28: Consider return type for batch operation

The batch method doesn't return anything, which means callers have no way to know when the batch operation completes except through the callback. Consider returning a Future, CompletableFuture, or similar to allow more flexible handling of the asynchronous operation.

-void batch(Callback<BatchContext> batchContextCallback);
+CompletableFuture<BatchContext> batch(Callback<BatchContext> batchContextCallback);

53-60: Clarify default behavior for null initialValue

The createCounter method accepts a Long initialValue parameter, but it's not clear what happens if null is passed. Consider documenting the default behavior.

/**
 * Creates a new LiveCounter with an initial value.
 *
- * @param initialValue the initial value of the LiveCounter.
+ * @param initialValue the initial value of the LiveCounter. If null, the counter will start at 0.
 * @return the newly created LiveCounter instance.
 */
LiveCounter createCounter(Long initialValue);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 333dc54 and abe200c.

📒 Files selected for processing (15)
  • android/src/main/java/io/ably/lib/realtime/Channel.java (2 hunks)
  • java/src/main/java/io/ably/lib/realtime/Channel.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveCounter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContext.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContextLiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (6 hunks)
  • lib/src/main/java/io/ably/lib/realtime/ChannelBase.java (4 hunks)
  • live-objects/build.gradle.kts (1 hunks)
  • live-objects/gradle.properties (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1 hunks)
  • settings.gradle.kts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (2)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (2)
  • getInstance (7-9)
  • dispose (11-13)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1)
  • channelName (6-50)
lib/src/main/java/io/ably/lib/objects/batch/BatchContext.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (2)
  • batch (11-13)
  • getRoot (7-9)
lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (2)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1)
  • channelName (6-50)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1)
  • dispose (11-13)
lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (11)
  • batch (11-13)
  • getRoot (7-9)
  • createMap (15-17)
  • createMap (19-21)
  • createMap (23-25)
  • createCounter (27-29)
  • getRootAsync (31-33)
  • createMapAsync (35-37)
  • createMapAsync (39-41)
  • createMapAsync (43-45)
  • createCounterAsync (47-49)
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: check (24)
  • GitHub Check: check (21)
  • GitHub Check: check (29)
  • GitHub Check: check (19)
  • GitHub Check: check-realtime
  • GitHub Check: check
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check-rest
  • GitHub Check: build
🔇 Additional comments (21)
settings.gradle.kts (1)

18-18: LGTM: New module integration

The addition of the "live-objects" module to the Gradle settings is correct and follows the established naming convention in the project.

lib/src/main/java/io/ably/lib/objects/batch/BatchContext.java (1)

1-17:

❌ Incorrect review comment

Well-structured interface definition with good documentation

The BatchContext interface is clearly documented and defines a focused API for batch operations on live data objects. The interface follows good Java practices with comprehensive Javadoc.

However, I notice that while this interface's getRoot() returns a BatchContextLiveMap, the corresponding method in DefaultLiveObjects.kt returns a LiveMap. Please ensure these types are compatible in the implementation.


🏁 Script executed:

#!/bin/bash
# Verify the relationship between BatchContextLiveMap and LiveMap
echo "Checking for BatchContextLiveMap definition..."
fd --type file --extension java --exec grep -l "BatchContextLiveMap" {} \;

echo "Searching for relationship between BatchContextLiveMap and LiveMap..."
fd --type file --extension java --exec grep -l "BatchContextLiveMap.*extends.*LiveMap\|interface.*BatchContextLiveMap.*LiveMap" {} \;

Length of output: 603


I’ll pull in the definitions of BatchContextLiveMap and inspect how getRoot() is implemented in DefaultLiveObjects.kt to confirm their types align.


🏁 Script executed:

#!/bin/bash
set -e

# Show BatchContextLiveMap definition
echo "===== lib/src/main/java/io/ably/lib/objects/batch/BatchContextLiveMap.java ====="
sed -n '1,200p' lib/src/main/java/io/ably/lib/objects/batch/BatchContextLiveMap.java

# Locate DefaultLiveObjects.kt
echo
echo "Searching for DefaultLiveObjects.kt..."
KT_FILE=$(fd --type f --extension kt -x grep -l "class DefaultLiveObjects" {} | head -n1)
if [ -z "$KT_FILE" ]; then
  echo "ERROR: DefaultLiveObjects.kt not found"
  exit 1
fi
echo "Found: $KT_FILE"

# Find and show getRoot() implementation
echo
echo "Looking for getRoot() in DefaultLiveObjects.kt..."
grep -R -n "getRoot" "$KT_FILE" || true

LINE=$(grep -R -n "getRoot" "$KT_FILE" | head -n1 | cut -d: -f1)
if [ -n "$LINE" ]; then
  START=$((LINE-5))
  [ "$START" -lt 1 ] && START=1
  END=$((LINE+15))
  echo
  echo "===== Context around getRoot() (lines $START$END) ====="
  sed -n "${START},${END}p" "$KT_FILE"
else
  echo "No getRoot() method found in $KT_FILE"
fi

Length of output: 3136


I’ll search the Kotlin sources for where BatchContext is implemented and how getRoot() is defined to verify the return types align.


🏁 Script executed:

#!/bin/bash
set -e

echo "=== Looking for override fun getRoot in Kotlin sources ==="
grep -R -n "override fun getRoot" live-objects/src/main/kotlin || true

echo
echo "=== Finding classes that implement BatchContext ==="
grep -R -n ":.*BatchContext" live-objects/src/main/kotlin || true

echo
echo "=== All references to BatchContext in Kotlin ==="
grep -R -n "BatchContext" live-objects/src/main/kotlin

Length of output: 1200


Gathering the LiveMap definition to confirm it implements BatchContextLiveMap.


🏁 Script executed:

#!/bin/bash
set -e

echo "=== Locating LiveMap interface in Kotlin sources ==="
fd --type f --extension kt -x grep -l "interface LiveMap" {} || true

echo
echo "=== Locating LiveMap class in Kotlin sources ==="
fd --type f --extension kt -x grep -l "class LiveMap" {} || true

echo
for file in $(fd --type f --extension kt -x grep -l "interface LiveMap" {}); do
  echo "===== $file ====="
  sed -n '1,200p' "$file"
done

Length of output: 452


I’ll locate all LiveMap definitions across the repo (both Java and Kotlin) to confirm whether it implements or aliases BatchContextLiveMap:


🏁 Script executed:

#!/bin/bash
set -e

echo "=== Files named *LiveMap*.java or *.kt ==="
fd --type f -e java -e kt "LiveMap" .

echo
echo "=== Java: looking for LiveMap in lib/src/main/java ==="
grep -R -n "interface LiveMap" lib/src/main/java || true
grep -R -n "class LiveMap" lib/src/main/java || true

echo
echo "=== Kotlin: looking for LiveMap/interface/typealias definitions ==="
grep -R -n "interface LiveMap" . || true
grep -R -n "class LiveMap" . || true
grep -R -n "typealias LiveMap" . || true

Length of output: 929


Inspecting the actual LiveMap definition and the Kotlin implementation:


🏁 Script executed:

#!/bin/bash
set -e

echo "===== lib/src/main/java/io/ably/lib/objects/LiveMap.java ====="
sed -n '1,200p' lib/src/main/java/io/ably/lib/objects/LiveMap.java

echo
echo "===== live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt ====="
sed -n '1,200p' live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt

Length of output: 4291


Ignore incorrect type-compatibility concern

The getRoot() in BatchContext (returning BatchContextLiveMap) is part of the batch-operation API, whereas getRoot() in DefaultLiveObjects implements the LiveObjects interface and correctly returns a LiveMap. These are two separate methods in different interfaces—there’s no need for BatchContextLiveMap and LiveMap to be related.

No changes are required here.

Likely an incorrect or invalid review comment.

android/src/main/java/io/ably/lib/realtime/Channel.java (2)

6-6: LGTM: Import for LiveObjectsPlugin

The import is correctly added to support the new parameter in the constructor.


17-18: LGTM: Constructor updated for LiveObjects support

The constructor has been properly expanded to include the LiveObjectsPlugin parameter and correctly passes it to the superclass constructor.

java/src/main/java/io/ably/lib/realtime/Channel.java (2)

3-3: LGTM: Import for LiveObjectsPlugin

The import is correctly added to support the new parameter in the constructor.


8-9: LGTM: Constructor updated for LiveObjects support

The constructor has been properly expanded to include the LiveObjectsPlugin parameter and correctly passes it to the superclass constructor. This mirrors the same change made in the Android version, ensuring consistent implementation across platforms.

live-objects/gradle.properties (1)

1-4: Maven POM properties are well-defined and appropriate

The Maven POM properties for the new 'live-objects' module are clearly defined with appropriate values. The artifact ID, name, description, and packaging type follow standard Maven/Gradle conventions and accurately describe the purpose of this module.

live-objects/build.gradle.kts (3)

1-4: Good use of Gradle plugins

The build script correctly applies the java-library plugin and uses the plugin alias for Kotlin JVM, which is a good practice for centralizing version management.


10-13: Dependencies look appropriate for the module

The dependencies section correctly sets up the implementation dependency on the :java project module and test dependencies on Kotlin test libraries.


19-21: Excellent use of explicitApi for library development

Using explicitApi() is a great practice for library modules as it enforces explicit visibility modifiers and return types, making the API surface clearer for consumers.

lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (2)

3-7: Clear and concise documentation

The JavaDoc provides a good high-level description of the plugin's purpose. This helps users understand the intent of the interface.


10-16: Well-documented API method

The getInstance method is well-documented with clear parameter and return descriptions.

live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (2)

7-9: Good use of Kotlin's getOrPut function

The implementation efficiently uses Kotlin's getOrPut function, which handles the cache lookup and creation pattern in a concise way.


11-13:

❌ Incorrect review comment

Consider adding resource cleanup in dispose

The dispose method only removes the entry from the cache. If the LiveObjects instance holds any resources that need explicit cleanup (such as event listeners, timers, or network connections), consider adding cleanup logic before removing it from the cache.


🏁 Script executed:

#!/bin/bash
# Check if LiveObjects implementation has any cleanup methods or resources that need disposal
echo "Checking LiveObjects interface for cleanup methods..."
grep -r "close\|dispose\|cleanup" --include="*.java" --include="*.kt" lib/src/main/java/io/ably/lib/objects/ live-objects/src/main/kotlin/io/ably/lib/objects/

echo "Checking DefaultLiveObjects implementation for resources that might need cleanup..."
grep -r "private val\|private var" --include="DefaultLiveObjects.kt" live-objects/src/main/kotlin/io/ably/lib/objects/

Length of output: 948


I’d like to inspect the plugin itself to see what resources it holds. Let’s dump the contents of DefaultLiveObjectsPlugin.kt and look for any private fields:


🏁 Script executed:

#!/bin/bash
echo "===== Contents of DefaultLiveObjectsPlugin.kt ====="
sed -n '1,200p' live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt

echo
echo "===== Any private fields in DefaultLiveObjectsPlugin.kt ====="
grep -E "private (val|var)" -n live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt

Length of output: 890


Let’s inspect the DefaultLiveObjects implementation to see if it holds any subscriptions, listeners, or other resources needing explicit cleanup:


🏁 Script executed:

#!/bin/bash
echo "===== DefaultLiveObjects.kt ====="
sed -n '1,200p' live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt

echo
echo "===== Resource-like members in DefaultLiveObjects ====="
grep -E "private (val|var)" -n live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt

Length of output: 1849


No additional cleanup needed in dispose

The DefaultLiveObjectsPlugin.dispose(channelName) method only drops the cached DefaultLiveObjects instance, and DefaultLiveObjects itself currently holds no subscriptions, listeners, timers, or other disposable resources—just a channel name string. There’s nothing to clean up today. If you introduce resource-holding fields in DefaultLiveObjects in the future, you can extend dispose to call their cleanup methods at that time.

Likely an incorrect or invalid review comment.

lib/src/main/java/io/ably/lib/objects/LiveCounter.java (1)

1-42: Good implementation of the LiveCounter interface

The LiveCounter interface is well-designed with a clear separation between synchronous and asynchronous operations. The documentation is thorough and properly explains the purpose of each method.

lib/src/main/java/io/ably/lib/objects/batch/BatchContextLiveMap.java (1)

1-63: Well-structured batch context interface

The BatchContextLiveMap interface provides a clear and consistent API for batch operations on live maps. The methods align well with standard map operations while preserving the stateful nature of batch processing.

lib/src/main/java/io/ably/lib/realtime/ChannelBase.java (2)

96-106: Good integration of LiveObjects plugin with clear error messaging

The LiveObjects plugin integration is well-implemented with appropriate null checking and a helpful error message that guides users on how to add the missing dependency.


1301-1312: Appropriate constructor update for plugin integration

The constructor change properly integrates the LiveObjectsPlugin while maintaining backward compatibility with the existing functionality.

lib/src/main/java/io/ably/lib/objects/LiveMap.java (1)

1-82: Well-designed LiveMap interface with consistent sync/async patterns

The LiveMap interface provides a comprehensive API for real-time map operations with both synchronous and asynchronous variants. The method signatures and documentation are clear and consistent with other interfaces in the codebase.

live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1)

6-6: Class visibility is appropriately restricted

The internal modifier correctly limits the accessibility of this implementation to within the module, enforcing that consumers should work with the interface rather than the implementation.

lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (1)

238-240:

❌ Incorrect review comment

Ensure thread safety when accessing liveObjectsPlugin

While the liveObjectsPlugin field is final, it's good practice to synchronize or use atomic operations when accessing it in the release method to ensure thread safety, especially since it might be called from different threads.


🏁 Script executed:

#!/bin/bash
# Search for synchronization patterns in Channel-related operations
rg -A 2 -B 2 "synchronized.*Channel" lib/src/main/java/io/ably/lib/realtime/

Length of output: 1642


I’d like to confirm how liveObjectsPlugin is used and whether its access is already protected. Let’s pull in the surrounding context and look for any existing synchronization in AblyRealtime.java:


🏁 Script executed:

#!/bin/bash
# Show references to liveObjectsPlugin with context
rg -n "liveObjectsPlugin" -A3 -B3 lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java

# Find where dispose is called in this class
rg -n "dispose" -n lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java

# Check for any synchronized blocks in AblyRealtime
rg -n "synchronized" -n lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java

# Locate the release method to see its signature and annotations
rg -n "release" -A5 -B5 lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java

Length of output: 3552


No additional synchronization required for liveObjectsPlugin
The liveObjectsPlugin field is final and safely published once during construction. Reading a final field is thread-safe, and because you remove the channel from the concurrent map before calling dispose(), you’re guaranteed it only runs once per channel. If the plugin itself needs to guard its internal state against concurrent disposal, that logic belongs inside its own implementation, not here.

Likely an incorrect or invalid review comment.

1. Declared required liveobject java interfaces
2. Implemented liveobject interface for LiveObjectsPlugin
3. Declared batch specific public interface methods
@sacOO7 sacOO7 force-pushed the feature/liveobject-plugin-setup branch from abe200c to c435f5d Compare May 19, 2025 15:27
@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 19, 2025 15:28 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (3)
lib/src/main/java/io/ably/lib/objects/LiveObjects.java (3)

8-13: Add thread safety documentation to interface

The interface lacks information about thread safety guarantees. Consider adding explicit documentation about whether implementations should be thread-safe and any synchronization requirements for callers.

/**
 * The LiveObjects interface provides methods to interact with live data objects,
 * such as maps and counters, in a real-time environment. It supports both synchronous
 * and asynchronous operations for retrieving and creating live objects.
+ *
+ * <p>Implementations of this interface must be thread-safe as they may be accessed
+ * from multiple threads concurrently.
 */

15-20: Specify error handling behavior for synchronous methods

The synchronous methods like getRoot() don't specify how errors are communicated to callers. Consider documenting whether these methods throw exceptions and which types of exceptions callers should handle.

/**
 * Retrieves the root LiveMap object.
 *
 * @return the root LiveMap instance.
+ * @throws LiveObjectException if the root map cannot be retrieved or accessed.
 */
LiveMap getRoot();

45-52: Document nullability expectations for parameters

The interface doesn't specify whether null values are acceptable for parameters. Consider adding @NonNull annotations or explicit documentation about null handling for each parameter.

/**
 * Creates a new LiveMap based on a standard Java Map.
 *
- * @param map the Java Map to base the new LiveMap on.
+ * @param map the Java Map to base the new LiveMap on. Must not be null.
 * @return the newly created LiveMap instance.
+ * @throws IllegalArgumentException if map is null.
 */
LiveMap createMap(Map<String, Object> map);
🧹 Nitpick comments (1)
lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1)

53-60: Consider using primitive type for initialValue

The initialValue parameter is defined as Long (object wrapper) rather than long (primitive). Unless you need to represent a null initial value, consider using the primitive type for better performance.

/**
 * Creates a new LiveCounter with an initial value.
 *
- * @param initialValue the initial value of the LiveCounter.
+ * @param initialValue the initial value of the LiveCounter. If null, a default value of 0 will be used.
 * @return the newly created LiveCounter instance.
 */
-LiveCounter createCounter(Long initialValue);
+LiveCounter createCounter(Long initialValue); // Keep as Long if null values are intended to be supported
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between abe200c and c435f5d.

📒 Files selected for processing (16)
  • android/src/main/java/io/ably/lib/realtime/Channel.java (2 hunks)
  • java/src/main/java/io/ably/lib/realtime/Channel.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveCounter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContext.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContextBuilder.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContextLiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (6 hunks)
  • lib/src/main/java/io/ably/lib/realtime/ChannelBase.java (4 hunks)
  • live-objects/build.gradle.kts (1 hunks)
  • live-objects/gradle.properties (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1 hunks)
  • settings.gradle.kts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContextBuilder.java
🚧 Files skipped from review as they are similar to previous changes (14)
  • settings.gradle.kts
  • android/src/main/java/io/ably/lib/realtime/Channel.java
  • java/src/main/java/io/ably/lib/realtime/Channel.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContextLiveMap.java
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContext.java
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java
  • live-objects/build.gradle.kts
  • lib/src/main/java/io/ably/lib/objects/LiveCounter.java
  • lib/src/main/java/io/ably/lib/objects/LiveMap.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • lib/src/main/java/io/ably/lib/realtime/ChannelBase.java
  • live-objects/gradle.properties
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java
🧰 Additional context used
🧬 Code Graph Analysis (1)
lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (11)
  • batch (11-13)
  • getRoot (7-9)
  • createMap (15-17)
  • createMap (19-21)
  • createMap (23-25)
  • createCounter (27-29)
  • getRootAsync (31-33)
  • createMapAsync (35-37)
  • createMapAsync (39-41)
  • createMapAsync (43-45)
  • createCounterAsync (47-49)
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: check
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check-realtime
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check-rest
  • GitHub Check: check (29)
  • GitHub Check: check (19)
  • GitHub Check: check (24)
  • GitHub Check: check (21)
  • GitHub Check: build

@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 20, 2025 11:46 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 20, 2025 11:47 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
lib/src/test/java/io/ably/lib/test/common/Setup.java (1)

172-187: Consider improvements to the internet availability check implementation.

The checkInternetAvailability() method has a few areas that could be improved:

  1. The URL and timeout values are hard-coded. Consider making these configurable, perhaps as constants or properties.
  2. The method wraps all exceptions into a generic Exception, which loses specific error details. Consider preserving the original exception type or providing more detailed error messages.
  3. The connection is not explicitly closed after use. Although Java will eventually clean it up, it's best practice to close resources explicitly.
public static void checkInternetAvailability() throws Exception {
    HttpURLConnection connection = null;
    try {
        String testUrl = "https://internet-up.ably-realtime.com/is-the-internet-up.txt";
        connection = (HttpURLConnection) new URL(testUrl).openConnection();
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(5000); // Set timeout to 5 seconds
        connection.setReadTimeout(5000);

        int responseCode = connection.getResponseCode();
        if (responseCode != 200) {
            throw new IOException("Host is not available. Response code: " + responseCode);
        }
    } catch (Exception e) {
        throw new Exception("Internet is not available", e);
+    } finally {
+        if (connection != null) {
+            connection.disconnect();
+        }
    }
}
lib/src/main/java/io/ably/lib/plugins/objects/LiveMap.java (1)

67-83: Consider consistent return types between sync and async methods

The asynchronous methods are correctly defined with callbacks, but there's an inconsistency in the return types compared to their synchronous counterparts:

  • Synchronous methods set and remove return void
  • Asynchronous methods setAsync and removeAsync use Callback<Void>

Consider whether it would be more consistent to have:

  1. Both return void (current implementation)
  2. Synchronous methods return some result type that's passed to the async callback
  3. Or add a boolean return value for synchronous methods to indicate success/failure

Also, consider adding asynchronous equivalents for other synchronous methods like get, entries, keys, values, and size for consistency and to provide non-blocking alternatives for all operations.

lib/src/main/java/io/ably/lib/plugins/objects/LiveObjects.java (2)

63-109: Consistent async API design

The asynchronous methods are correctly defined with callbacks that match their synchronous counterparts. The pattern of providing both synchronous and asynchronous versions of each method is a good practice for a Java library, allowing flexibility for different threading models.

One minor improvement would be to consider adding an @NotNull annotation to the initialValue parameter of createCounter and createCounterAsync methods to be consistent with other parameters, although the current implementation correctly uses @NotNull in the JavaDoc for these parameters.


37-53: Consider validation for map transformations

The methods createMap(LiveMap), createMap(LiveCounter), and createMap(Map<String, Object>) transform different objects into a LiveMap.

Since these are interface methods, they don't contain implementation details, but it would be helpful to document:

  1. What happens with null values in the source map/counter?
  2. Are there any restrictions on the types of objects that can be stored as values?
  3. Is this a deep or shallow copy of the source data?

This additional documentation would help implementers understand the expected behavior.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between c435f5d and 86a035e.

📒 Files selected for processing (15)
  • gradle/libs.versions.toml (2 hunks)
  • java/build.gradle.kts (1 hunks)
  • java/src/main/java/io/ably/lib/realtime/Channel.java (1 hunks)
  • lib/src/main/java/io/ably/lib/plugins/objects/LiveCounter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/plugins/objects/LiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/plugins/objects/LiveObjects.java (1 hunks)
  • lib/src/main/java/io/ably/lib/plugins/objects/LiveObjectsPlugin.java (1 hunks)
  • lib/src/main/java/io/ably/lib/plugins/objects/batch/BatchContext.java (1 hunks)
  • lib/src/main/java/io/ably/lib/plugins/objects/batch/BatchContextBuilder.java (1 hunks)
  • lib/src/main/java/io/ably/lib/plugins/objects/batch/BatchContextLiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (6 hunks)
  • lib/src/main/java/io/ably/lib/realtime/ChannelBase.java (4 hunks)
  • lib/src/test/java/io/ably/lib/test/common/Setup.java (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • lib/src/main/java/io/ably/lib/plugins/objects/batch/BatchContextBuilder.java
  • gradle/libs.versions.toml
  • lib/src/main/java/io/ably/lib/plugins/objects/LiveCounter.java
  • lib/src/main/java/io/ably/lib/plugins/objects/batch/BatchContextLiveMap.java
🚧 Files skipped from review as they are similar to previous changes (5)
  • java/src/main/java/io/ably/lib/realtime/Channel.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java
  • lib/src/main/java/io/ably/lib/realtime/ChannelBase.java
🧰 Additional context used
🧬 Code Graph Analysis (2)
lib/src/main/java/io/ably/lib/plugins/objects/batch/BatchContext.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (2)
  • batch (14-16)
  • getRoot (10-12)
lib/src/main/java/io/ably/lib/plugins/objects/LiveObjects.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (12)
  • batch (14-16)
  • getRoot (10-12)
  • createMap (18-20)
  • createMap (22-24)
  • createMap (26-28)
  • createCounter (54-56)
  • getRootAsync (30-32)
  • batchAsync (34-36)
  • createMapAsync (38-40)
  • createMapAsync (42-44)
  • createMapAsync (46-48)
  • createCounterAsync (50-52)
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: check (29)
  • GitHub Check: check (19)
  • GitHub Check: check (24)
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check (21)
  • GitHub Check: check-realtime
  • GitHub Check: build
  • GitHub Check: check-rest
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check
🔇 Additional comments (6)
java/build.gradle.kts (1)

23-23: Added JetBrains annotations as a compile-only dependency
Using compileOnly(libs.jetbrains) is appropriate for null-safety and purity annotations without impacting the runtime classpath. Please verify that the libs.jetbrains alias is correctly defined in the version catalog and resolves to the intended org.jetbrains:annotations artifact.

lib/src/test/java/io/ably/lib/test/common/Setup.java (1)

4-5: LGTM - appropriate imports for HttpURLConnection functionality.

The added imports support the new network connectivity check feature.

lib/src/main/java/io/ably/lib/plugins/objects/batch/BatchContext.java (1)

1-19: Well-designed interface with clear documentation

The BatchContext interface is well-structured with appropriate JavaDoc comments explaining its purpose and contract. The @NotNull annotation on the return type of getRoot() ensures API consumers are aware the method won't return null.

Consider whether the interface should include methods for committing or rolling back a batch operation if these aren't handled elsewhere in the API.

lib/src/main/java/io/ably/lib/plugins/objects/LiveObjectsPlugin.java (1)

1-26: Clean interface design following best practices

The LiveObjectsPlugin interface provides a clear contract for managing LiveObjects instances associated with channel names. The method signatures are well-defined, and the JavaDoc comments provide good documentation on the purpose of each method.

The use of @NotNull annotations correctly enforces that channel names must not be null, which helps prevent null pointer exceptions at runtime.

The interface is appropriately focused on a single responsibility - managing the lifecycle of LiveObjects instances.

lib/src/main/java/io/ably/lib/plugins/objects/LiveMap.java (1)

1-66: Well-structured interface with good documentation

The LiveMap interface provides a comprehensive API for interacting with a live, real-time map structure. The synchronous methods are well-defined with appropriate return types and parameter annotations.

The @Contract(pure = true) annotation on the size() method is a good practice, indicating that the method doesn't modify the state of the object.

All methods have clear JavaDoc comments explaining their purpose and parameters.

lib/src/main/java/io/ably/lib/plugins/objects/LiveObjects.java (1)

1-62: Well-structured interface with comprehensive operations

The LiveObjects interface provides a comprehensive set of methods for interacting with live data objects. The synchronous methods are well-defined with appropriate return types and parameter annotations.

All methods have clear JavaDoc comments explaining their purpose and parameters.

The interface provides good abstraction for creating different types of live objects (maps and counters) and supports batch operations.

@sacOO7 sacOO7 force-pushed the feature/liveobject-plugin-setup branch from 86a035e to 6b291d0 Compare May 20, 2025 12:22
@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 20, 2025 12:23 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 20, 2025 12:25 Inactive
@sacOO7 sacOO7 force-pushed the feature/liveobject-plugin-setup branch from 6b291d0 to d2181b1 Compare May 20, 2025 12:40
@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 20, 2025 12:41 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 20, 2025 12:42 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (6)
lib/src/main/java/io/ably/lib/objects/LiveCounter.java (1)

1-46: Consider adding support for custom increment/decrement values

The interface is well-defined with both synchronous and asynchronous methods, but it only supports incrementing and decrementing by 1. Consider extending the interface to support incrementing/decrementing by arbitrary values, which could provide more flexibility.

public interface LiveCounter {
    void increment();
    void incrementAsync(@NotNull Callback<Void> callback);
    void decrement();
    void decrementAsync(@NotNull Callback<Void> callback);
+    void incrementBy(long delta);
+    void incrementByAsync(long delta, @NotNull Callback<Void> callback);
+    void decrementBy(long delta);
+    void decrementByAsync(long delta, @NotNull Callback<Void> callback);
    @NotNull
    @Contract(pure = true)
    Long value();
}
lib/src/main/java/io/ably/lib/objects/LiveObjects.java (5)

20-25: Consider adding error handling documentation.

The getRoot() method doesn't specify how errors are communicated to callers. While I understand from previous comments that specific exception types aren't known yet, it would be helpful to at least indicate that exceptions might be thrown in case of errors.

/**
 * Retrieves the root LiveMap object.
 *
 * @return the root LiveMap instance.
+ * @throws Exception if an error occurs while retrieving the root map.
 */
LiveMap getRoot();

58-64: Consider using primitive long instead of Long object.

The initialValue parameter is defined as Long (object) rather than long (primitive). This requires boxing/unboxing and could have performance implications for a potentially frequently used counter. Unless you specifically need to support null values (which contradicts the @NotNull annotation), consider using the primitive type.

/**
 * Creates a new LiveCounter with an initial value.
 *
- * @param initialValue the initial value of the LiveCounter.
+ * @param initialValue the initial value of the LiveCounter as a primitive long.
 * @return the newly created LiveCounter instance.
 */
-LiveCounter createCounter(@NotNull Long initialValue);
+LiveCounter createCounter(long initialValue);

105-111: Maintain consistency with primitive types if changing the synchronous method.

If you update the synchronous createCounter method to use the primitive long as suggested, make sure to update this asynchronous version as well for consistency.

/**
 * Asynchronously creates a new LiveCounter with an initial value.
 *
- * @param initialValue the initial value of the LiveCounter.
+ * @param initialValue the initial value of the LiveCounter as a primitive long.
 * @param callback the callback to handle the result or error.
 */
-void createCounterAsync(@NotNull Long initialValue, @NotNull Callback<LiveCounter> callback);
+void createCounterAsync(long initialValue, @NotNull Callback<LiveCounter> callback);

50-56: Document acceptable value types for the map.

The createMap method accepts a Map<String, Object> but doesn't specify what types of objects are allowed as values. Consider documenting the acceptable value types to help API users understand limitations.

/**
 * Creates a new LiveMap based on a standard Java Map.
 *
- * @param map the Java Map to base the new LiveMap on.
+ * @param map the Java Map to base the new LiveMap on. Values must be of supported types
+ *            (e.g., String, Number, Boolean, Map, List, or other supported Ably types).
 * @return the newly created LiveMap instance.
 */
LiveMap createMap(@NotNull Map<String, Object> map);

97-103: Maintain value type documentation consistency.

If you add documentation about acceptable value types to the synchronous createMap method, make sure to add similar documentation to this asynchronous version for consistency.

/**
 * Asynchronously creates a new LiveMap based on a standard Java Map.
 *
- * @param map the Java Map to base the new LiveMap on.
+ * @param map the Java Map to base the new LiveMap on. Values must be of supported types
+ *            (e.g., String, Number, Boolean, Map, List, or other supported Ably types).
 * @param callback the callback to handle the result or error.
 */
void createMapAsync(@NotNull Map<String, Object> map, @NotNull Callback<LiveMap> callback);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 6b291d0 and d2181b1.

📒 Files selected for processing (14)
  • android/build.gradle.kts (1 hunks)
  • gradle/libs.versions.toml (2 hunks)
  • java/build.gradle.kts (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveCounter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContext.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContextBuilder.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContextLiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (6 hunks)
  • lib/src/test/java/io/ably/lib/test/common/Setup.java (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContext.java
  • lib/src/main/java/io/ably/lib/objects/batch/BatchContextBuilder.java
🚧 Files skipped from review as they are similar to previous changes (7)
  • java/build.gradle.kts
  • android/build.gradle.kts
  • gradle/libs.versions.toml
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt
  • lib/src/test/java/io/ably/lib/test/common/Setup.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java
🧰 Additional context used
🧬 Code Graph Analysis (1)
lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (12)
  • batch (11-13)
  • getRoot (7-9)
  • createMap (15-17)
  • createMap (19-21)
  • createMap (23-25)
  • createCounter (51-53)
  • getRootAsync (27-29)
  • batchAsync (31-33)
  • createMapAsync (35-37)
  • createMapAsync (39-41)
  • createMapAsync (43-45)
  • createCounterAsync (47-49)
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: build
  • GitHub Check: check (24)
  • GitHub Check: check (21)
  • GitHub Check: check (29)
  • GitHub Check: check (19)
  • GitHub Check: check
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check-realtime
  • GitHub Check: check-rest
🔇 Additional comments (3)
lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (1)

1-26: Well-structured interface with clear documentation

The LiveObjectsPlugin interface is well-designed with thorough JavaDoc comments and proper null safety annotations. It provides a clean contract for managing LiveObjects instances associated with channels.

lib/src/main/java/io/ably/lib/objects/batch/BatchContextLiveMap.java (1)

1-76: Interface properly defined with appropriate annotations

The BatchContextLiveMap interface is well-structured with appropriate null safety, unmodifiability, and pure contract annotations. The documentation is thorough and clear.

lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1)

1-18: Good interface definition with clear documentation.

The LiveObjects interface is well-documented with clear descriptions of its purpose and thread safety requirements. The imports are appropriate for the functionality being defined.

@sacOO7 sacOO7 force-pushed the feature/liveobject-plugin-setup branch from d2181b1 to 0a108a1 Compare May 20, 2025 13:03
@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 20, 2025 13:04 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 20, 2025 13:05 Inactive
…methods

2. Added internet connectivity check to test setup
@sacOO7 sacOO7 force-pushed the feature/liveobject-plugin-setup branch from 0a108a1 to bce4ba9 Compare May 21, 2025 10:56
@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 21, 2025 10:57 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 21, 2025 10:59 Inactive
2. Added live objects specific channel modes and flags to protocol message
@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 21, 2025 11:04 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 21, 2025 11:05 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
lib/src/main/java/io/ably/lib/types/ProtocolMessage.java (1)

21-28: Consider updating class documentation.

The class documentation should be updated to mention that ProtocolMessage now also supports Live Objects functionality through the new action types and flags.

 /**
  * A message sent and received over the Realtime protocol.
  * A ProtocolMessage always relates to a single channel only, but
  * can contain multiple individual Messages or PresenceMessages.
  * ProtocolMessages are serially numbered on a connection.
+ * ProtocolMessage also supports Live Objects functionality through dedicated
+ * action types and flags.
  * See the Ably client library developer documentation for further
  * details on the members of a ProtocolMessage.
  */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between bce4ba9 and d81cb24.

📒 Files selected for processing (5)
  • lib/src/main/java/io/ably/lib/objects/LiveCounter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveMap.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java (1 hunks)
  • lib/src/main/java/io/ably/lib/types/ChannelMode.java (1 hunks)
  • lib/src/main/java/io/ably/lib/types/ProtocolMessage.java (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • lib/src/main/java/io/ably/lib/types/ChannelMode.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • lib/src/main/java/io/ably/lib/objects/LiveCounter.java
  • lib/src/main/java/io/ably/lib/objects/LiveObjects.java
  • lib/src/main/java/io/ably/lib/objects/LiveMap.java
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: build
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check-rest
  • GitHub Check: check-realtime
  • GitHub Check: check (24)
  • GitHub Check: check (19)
  • GitHub Check: check (21)
  • GitHub Check: check (29)
  • GitHub Check: check
🔇 Additional comments (4)
lib/src/main/java/io/ably/lib/types/ProtocolMessage.java (4)

48-52: Appropriate extension of Action enum for Live Objects support.

The new action types auth, activate, object, object_sync, and annotation are added to support the Live Objects plugin functionality. These follow the existing naming convention and extend the protocol message capabilities appropriately.


64-65: Clear documentation and appropriate flag addition.

The has_objects flag is properly documented with a clear comment and placed at bit position 7, maintaining the existing pattern for flag declarations.


70-76: Well-organized flags with appropriate categorization.

The new flags are logically grouped with clear comments separating different categories:

  • Channel mode flags (presence_subscribe)
  • Annotation flags (annotation_publish, annotation_subscribe)
  • Object flags (object_subscribe, object_publish)

The bit positions are appropriately spaced and follow the existing pattern.


89-91:

❓ Verification inconclusive

Consider whether ackRequired should be updated.

The ackRequired method currently only returns true for message and presence actions. Consider whether any of the new actions (object, annotation, etc.) require acknowledgments and should be included in this method.


🏁 Script executed:

#!/bin/bash
# Check if there are other places in the codebase that might indicate whether
# the new message types require acknowledgment

# Look for pattern matching in the codebase related to ack requirements
rg -i "ack.*required|require.*ack" --type java

Length of output: 4241


Verify ackRequired covers new Actions in ProtocolMessage

A search for “ackRequired” and related patterns shows it’s only ever used for Action.message and Action.presence. The Action enum also includes object and annotation (and potentially other new actions), so please confirm whether these should trigger acknowledgments. If they do, update the method accordingly:

 public static boolean ackRequired(ProtocolMessage msg) {
-    return msg.action == Action.message || msg.action == Action.presence;
+    return msg.action == Action.message
+        || msg.action == Action.presence
+        || msg.action == Action.object
+        || msg.action == Action.annotation;
 }

Location:

  • lib/src/main/java/io/ably/lib/types/ProtocolMessage.java:89-91

@sacOO7 sacOO7 requested a review from ttypic May 21, 2025 12:25
@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 21, 2025 12:25 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 21, 2025 12:26 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1)

10-12: Appropriate use of ConcurrentHashMap for thread-safety.

The implementation correctly uses ConcurrentHashMap for thread-safe caching of LiveObjects instances, addressing the previous review comment about potential concurrency issues.

🧹 Nitpick comments (4)
lib/src/test/java/io/ably/lib/test/realtime/ConnectionManagerTest.java (1)

138-142: Consider supplying a stub instead of null for the new plugin parameter

A hard-coded null is perfectly legal, but if at any point the test (or the code under test) starts to call liveObjectsPlugin.handle(..) you will get an NPE instead of a clean Mockito verification failure.
Providing a mocked plugin keeps the test future-proof and self-documenting:

LiveObjectsPlugin plugin = Mockito.mock(LiveObjectsPlugin.class);
ConnectionManager connectionManager =
        new ConnectionManager(ably, connection, channels, new EmptyPlatformAgentProvider(), plugin) {
    @Override protected boolean checkConnectivity() { return false; }
};
lib/src/main/java/io/ably/lib/realtime/Connection.java (1)

123-130: Constructor signature changed – update javadoc & usage comments

Connection(..) now expects a LiveObjectsPlugin, but the class-level and constructor comments still describe only the previous four parameters.
Consider updating the Javadoc to mention the plugin and to clarify that null is acceptable when the feature is disabled.
This prevents confusion for maintainers and for downstream code that may reflectively inspect the constructor.

lib/src/main/java/io/ably/lib/transport/ConnectionManager.java (1)

84-91: Immutable reference to plugin is good – but mention nullability

Nice addition; holding a final reference ensures thread-safety.
A brief comment (or @nullable annotation) would make it explicit that the field may be null when the plugin is absent, helping static-analysis tools.

live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1)

22-34: Consider preserving exception details when transforming errors.

When transforming the ErrorInfo to an Exception, you're currently only keeping the message, which loses other potentially useful error details (code, statusCode, etc.).

- deferred.completeExceptionally(Exception(reason.message))
+ deferred.completeExceptionally(Exception(reason.toString()).apply { 
+   initCause(reason.cause) 
+ })

This preserves more error context for debugging and error handling upstream.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between d81cb24 and 6446864.

📒 Files selected for processing (9)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (1 hunks)
  • lib/src/main/java/io/ably/lib/plugins/PluginConnectionAdapter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/plugins/PluginInstance.java (1 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (6 hunks)
  • lib/src/main/java/io/ably/lib/realtime/Connection.java (2 hunks)
  • lib/src/main/java/io/ably/lib/transport/ConnectionManager.java (6 hunks)
  • lib/src/test/java/io/ably/lib/test/realtime/ConnectionManagerTest.java (1 hunks)
  • live-objects/build.gradle.kts (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • lib/src/main/java/io/ably/lib/plugins/PluginConnectionAdapter.java
  • lib/src/main/java/io/ably/lib/plugins/PluginInstance.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • live-objects/build.gradle.kts
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java
🧰 Additional context used
🧬 Code Graph Analysis (1)
lib/src/main/java/io/ably/lib/transport/ConnectionManager.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (2)
  • handle (36-38)
  • send (22-34)
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check-rest-okhttp
  • GitHub Check: build
  • GitHub Check: check
  • GitHub Check: check-rest
  • GitHub Check: check-realtime
  • GitHub Check: check (29)
  • GitHub Check: check (24)
  • GitHub Check: check (21)
  • GitHub Check: check (19)
🔇 Additional comments (4)
lib/src/main/java/io/ably/lib/transport/ConnectionManager.java (1)

1686-1689: Overloaded send delegates correctly but always queues – validate semantics

send(msg, listener) forwards to send(msg, /*queueEvents=*/true, listener).
Is queuing always desirable for plugin-originated messages? If the plugin expects an immediate NACK when the connection is not writable, passing queueEvents=true may hide problems.

Please double-check desired behaviour; if immediate failure is preferable, delegate with queueEvents=false when listener != null, or expose both options.

No code change required if current behaviour is intentional.

live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (3)

3-8: Good use of imports and dependencies.

The imports are appropriate for the functionality implemented in this class, including thread-safety (ConcurrentHashMap) and coroutine support (CompletableDeferred).


14-16: Efficient implementation of getInstance.

The getOrPut method provides a clean, thread-safe way to retrieve cached instances or create new ones when needed. This is an idiomatic Kotlin approach.


36-38: Implement the handle method as a priority.

The handle method seems critical for processing incoming protocol messages but is currently unimplemented. Consider implementing this method before moving forward, as it appears to be a core functionality of the plugin.

Without implementation, how will the plugin respond to incoming "object" and "object_sync" protocol messages mentioned in the summary? This could block the functionality of the entire live objects feature.

2. Added bridging interfaces to send and receive protocol messages
3. Added impl. for dispose method
@sacOO7 sacOO7 force-pushed the feature/liveobject-plugin-setup branch from 6446864 to d87b365 Compare May 21, 2025 14:31
@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 21, 2025 14:32 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 21, 2025 14:33 Inactive
Copy link
Contributor

@ttypic ttypic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good! Added small comments

@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 22, 2025 12:31 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1085/javadoc May 22, 2025 12:32 Inactive
@sacOO7 sacOO7 force-pushed the feature/liveobject-plugin-setup branch from 5ae9249 to 7fab87f Compare May 22, 2025 14:44
@sacOO7 sacOO7 requested a review from ttypic May 22, 2025 14:45
@github-actions github-actions bot temporarily deployed to staging/pull/1085/features May 22, 2025 14:45 Inactive
@sacOO7 sacOO7 force-pushed the feature/liveobject-plugin-setup branch from 7fab87f to 15cd909 Compare May 22, 2025 14:50
2. Removed liveobject batching operation specific interfaces
Copy link
Contributor

@ttypic ttypic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@sacOO7 sacOO7 merged commit ac0ece7 into main May 22, 2025
12 checks passed
@sacOO7 sacOO7 deleted the feature/liveobject-plugin-setup branch May 22, 2025 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

LiveObjects SDK Plugin Setup
2 participants