Skip to content

Conversation

@sacOO7
Copy link
Collaborator

@sacOO7 sacOO7 commented May 23, 2025

Fixed #1086

Summary by CodeRabbit

  • New Features

    • Introduced new interfaces and adapters to support advanced real-time object operations.
    • Added support for handling and processing object protocol messages, including map and counter operations.
    • Implemented new data structures for object messaging, enabling richer real-time data interactions.
    • Added ability to set channel serials for improved synchronization in real-time channels.
  • Refactor

    • Updated plugin and adapter initialization to use a more generic interface for improved flexibility.
    • Refactored message handling and sending logic for better coroutine support and error handling.
    • Removed deprecated interfaces and methods to streamline plugin lifecycle management.
  • Bug Fixes

    • Improved error reporting when channels are not found during message processing.
  • Documentation

    • Updated terminology in LiveMap method documentation for clarity, replacing "undefined" with "null".

@coderabbitai
Copy link

coderabbitai bot commented May 23, 2025

"""

Walkthrough

The changes introduce new internal data models for LiveObjects, update plugin and adapter interfaces to use a new LiveObjectsAdapter, and refactor related plugin and connection logic to support these changes. Kotlin extension utilities and message format enums are added, and protocol handling is updated to utilize the new models and adapter.

Changes

File(s) Change Summary
lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java Renamed and moved interface from PluginConnectionAdapter to LiveObjectsAdapter; added setChannelSerial method.
lib/src/main/java/io/ably/lib/objects/Adapter.java Added Adapter class implementing LiveObjectsAdapter with channel serial management and message sending.
lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java Refactored plugin initialization to use LiveObjectsAdapter.Adapter instead of PluginConnectionAdapter.
lib/src/main/java/io/ably/lib/transport/ConnectionManager.java Removed PluginConnectionAdapter implementation and related send method.
lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java Modified interface: removed PluginInstance extension; added handle and parameterless dispose methods.
lib/src/main/java/io/ably/lib/plugins/PluginInstance.java Deleted interface defining handle and dispose methods.
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt Updated constructor to require LiveObjectsAdapter; added handle method for protocol messages.
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt Refactored to use LiveObjectsAdapter; removed suspend send method; implemented handle method.
live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt Added sendAsync suspend extension for LiveObjectsAdapter and internal ProtocolMessageFormat enum; added Binary class.
live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt Added internal data classes and enums modeling object messages and operations per spec.
lib/src/main/java/io/ably/lib/objects/LiveMap.java Updated get method documentation to replace "undefined" with "null" for absent or tombstoned entries.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant DefaultLiveObjectsPlugin
    participant DefaultLiveObjects
    participant LiveObjectsAdapter
    participant AblyRealtime

    Client->>DefaultLiveObjectsPlugin: handle(msg: ProtocolMessage)
    DefaultLiveObjectsPlugin->>DefaultLiveObjects: handle(msg)
    DefaultLiveObjects->>LiveObjectsAdapter: setChannelSerial(channelName, channelSerial)
    LiveObjectsAdapter->>AblyRealtime: update channelSerial for channel
Loading

Assessment against linked issues

Objective Addressed Explanation
Declare internal models for LiveObjects as per spec (ECO-5375)

Possibly related PRs

  • Setup : LiveObject plugin #1085: Introduces the LiveObjectsPlugin interface and integrates it into AblyRealtime and related classes; related by plugin and adapter refactoring.

Poem

In the warren where objects live and play,
New models hop in, ready for the fray.
Adapters connect, with serials set right,
Plugins and helpers leap into the light.
With enums and messages, all neat and precise—
This rabbit approves: the code’s looking nice!
🐇✨
"""


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 431cfe7 and 4dfb1a0.

📒 Files selected for processing (1)
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: check
  • GitHub Check: check (21)
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check (24)
  • GitHub Check: check (29)
  • GitHub Check: check (19)
  • GitHub Check: check-rest
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check-realtime
  • GitHub Check: build
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 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 docstrings to generate docstrings for this 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/1087/features May 23, 2025 12:15 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1087/javadoc May 23, 2025 12:17 Inactive
@sacOO7 sacOO7 force-pushed the feature/declare-data-models branch from b66c81c to 29d7854 Compare May 23, 2025 12:19
@github-actions github-actions bot temporarily deployed to staging/pull/1087/features May 23, 2025 12:19 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1087/javadoc May 23, 2025 12:21 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1087/features May 27, 2025 11:40 Inactive
@sacOO7 sacOO7 marked this pull request as ready for review May 27, 2025 11:44
@github-actions github-actions bot temporarily deployed to staging/pull/1087/javadoc May 27, 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: 6

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

50-58: LGTM! Proper protocol message handling with minor suggestion.

The handle method correctly implements RTL15b specification with proper null safety and action type checking. The logging and delegation to the adapter are appropriate.

Consider adding exception handling around the adapter.setChannelSerial call to prevent potential failures from propagating:

  fun handle(msg: ProtocolMessage) {
    // RTL15b
    msg.channelSerial?.let {
      if (msg.action === ProtocolMessage.Action.`object`) {
        Log.v(tag, "Setting channel serial for channelName: $channelName, value: ${msg.channelSerial}")
-       adapter.setChannelSerial(channelName, msg.channelSerial)
+       try {
+         adapter.setChannelSerial(channelName, msg.channelSerial)
+       } catch (e: Exception) {
+         Log.e(tag, "Failed to set channel serial", e)
+       }
      }
    }
  }
lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java (1)

23-29: Consider improving error handling.

The current implementation only logs an error when a channel is not found, but this might warrant stronger error handling depending on the use case.

Consider whether this scenario should throw an exception instead of just logging:

 @Override
 public void setChannelSerial(@NotNull String channelName, @NotNull String channelSerial) {
     if (ably.channels.containsKey(channelName)) {
         ably.channels.get(channelName).properties.channelSerial = channelSerial;
     } else {
-        Log.e(TAG, "setChannelSerial(): channel not found: " + channelName);
+        Log.e(TAG, "setChannelSerial(): channel not found: " + channelName);
+        // Consider: throw new AblyException("Channel not found: " + channelName, ErrorInfo.UNKNOWN_ERROR_CODE, HttpStatusCode.BAD_REQUEST);
     }
 }
live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (1)

3-3: Consider using ByteArray instead of java.nio.Buffer.

For Kotlin projects, ByteArray is typically more idiomatic than java.nio.Buffer and provides better interoperability.

-import java.nio.Buffer

And update the usage in line 193:

-  val initialValue: Buffer? = null,
+  val initialValue: ByteArray? = null,
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ac0ece7 and 288776b.

📒 Files selected for processing (7)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (2 hunks)
  • lib/src/main/java/io/ably/lib/transport/ConnectionManager.java (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (1)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt (1)
  • adapter (6-30)
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check (29)
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check (21)
  • GitHub Check: check (24)
  • GitHub Check: check (19)
  • GitHub Check: check-realtime
  • GitHub Check: check
  • GitHub Check: check-rest
  • GitHub Check: build
🔇 Additional comments (23)
lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (4)

9-9: LGTM: Clean import refactoring.

The import change from PluginConnectionAdapter to LiveObjectsAdapter aligns with the architectural refactoring to use a more specific adapter interface for LiveObjects functionality.


190-193:

Details

✅ Verification successful

Well-structured adapter initialization.

The changes correctly instantiate the new LiveObjectsAdapter.Adapter and pass it to the plugin constructor. The adapter delegation pattern with this (AblyRealtime instance) is appropriate.

Verify that the DefaultLiveObjectsPlugin constructor signature matches the expected LiveObjectsAdapter parameter:


🏁 Script executed:

#!/bin/bash
# Verify DefaultLiveObjectsPlugin constructor signature
ast-grep --pattern $'class DefaultLiveObjectsPlugin {
  $$$
  DefaultLiveObjectsPlugin($ADAPTER) {
    $$$
  }
  $$$
}'

Length of output: 120


This will show the class declaration and the constructor parameters so we can confirm it accepts a LiveObjectsAdapter.


🏁 Script executed:

#!/bin/bash
# Locate DefaultLiveObjectsPlugin class and its constructor signature
rg "class DefaultLiveObjectsPlugin" -A 5 -n

Length of output: 853


Plugin constructor signature verified

All checks confirm that DefaultLiveObjectsPlugin accepts a LiveObjectsAdapter and you’re correctly passing the new LiveObjectsAdapter.Adapter(this) instance:

  • In live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt the constructor is defined as DefaultLiveObjectsPlugin(private val adapter: LiveObjectsAdapter).
  • In lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java you instantiate and pass new LiveObjectsAdapter.Adapter(this).

No further changes needed.


9-9: LGTM! Clean import update for the adapter refactoring.

The import change correctly reflects the transition from PluginConnectionAdapter to the new LiveObjectsAdapter interface.


190-193: LGTM! Proper adapter pattern implementation.

The code correctly instantiates the new LiveObjectsAdapter.Adapter with the current AblyRealtime instance and passes it to the plugin constructor. The dependency injection approach is clean and follows the adapter pattern properly.

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

39-39: LGTM: Interface removal aligns with adapter refactoring.

Removing the PluginConnectionAdapter implementation from ConnectionManager is consistent with the architectural change to use the new LiveObjectsAdapter.Adapter pattern. The responsibility for plugin communication is now properly delegated to the specific adapter implementation.


39-39: LGTM! Clean separation of concerns.

Removing the PluginConnectionAdapter implementation from ConnectionManager is a good architectural improvement. The adapter functionality has been properly moved to the new LiveObjectsAdapter, which simplifies the ConnectionManager's responsibilities and follows the single responsibility principle.

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

4-7: LGTM: Constructor and imports updated for new adapter pattern.

The import additions and constructor parameter change to LiveObjectsAdapter align perfectly with the architectural refactoring seen across other files.


50-58: Excellent implementation of RTL15b specification.

The handle method correctly implements the channel serial update logic:

  • Proper null-safe access to channelSerial
  • Correctly filters for object action type
  • Appropriate logging for debugging
  • Clean delegation to adapter for serial management

This follows the RTL15b specification for handling channel serials in LiveObjects.


4-8: LGTM! Proper imports and constructor refactoring.

The new imports for ProtocolMessage and Log are appropriate for the added functionality. The constructor parameter change to LiveObjectsAdapter correctly aligns with the adapter pattern refactoring, and the tag property follows Kotlin logging conventions.

live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (4)

8-24: Excellent coroutine integration for LiveObjectsAdapter.

The sendAsync extension function provides clean coroutine support:

  • Properly uses CompletableDeferred to bridge callback-based API
  • Handles both success (onSuccess) and error (onError) cases
  • Catches synchronous exceptions from send method
  • Clean suspend function signature for easy integration

This enables seamless async/await patterns in Kotlin code using the LiveObjectsAdapter.


26-31: Well-designed MessageFormat enum.

The enum provides a clean abstraction for message formats:

  • Clear naming with MSGPACK and JSON options
  • Proper string value association
  • Overridden toString() for easy serialization
  • Internal visibility appropriate for package-level usage

8-24: LGTM! Excellent coroutine wrapper implementation.

The sendAsync extension function properly bridges callback-based async operations with Kotlin coroutines. The implementation correctly:

  • Uses CompletableDeferred<Unit> for coordination
  • Handles both synchronous exceptions (in try-catch) and asynchronous errors (in completion listener)
  • Converts ErrorInfo to Exception appropriately
  • Awaits the deferred result to suspend until completion

This provides a clean coroutine-friendly API for the LiveObjects adapter.


26-31: LGTM! Clean enum implementation.

The MessageFormat enum is well-defined with appropriate string values and a proper toString() override. The internal visibility is appropriate for this utility enum.

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

6-17: LGTM! Clean adapter refactoring with proper message handling.

The refactoring to use LiveObjectsAdapter instead of PluginConnectionAdapter is well-implemented. The handle method correctly forwards protocol messages to the appropriate DefaultLiveObjects instance based on the channel name, maintaining proper separation of concerns.


6-6: LGTM: Clean architecture refactoring.

The change from PluginConnectionAdapter to LiveObjectsAdapter aligns well with the new architecture. This creates a more focused interface for LiveObjects communication.


11-11: LGTM: Correct adapter usage.

The DefaultLiveObjects instance creation properly uses the new adapter interface, maintaining consistency with the architectural changes.


14-17: LGTM: Proper message forwarding implementation.

The handle method correctly extracts the channel name and forwards messages to the appropriate LiveObjects instance. The null-safe call operator ensures no exceptions if the channel doesn't exist.

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

11-35: LGTM! Well-designed adapter interface with proper error handling.

The LiveObjectsAdapter interface provides a clean abstraction for LiveObjects communication. The Adapter implementation includes appropriate error handling with the containsKey check before accessing channel properties, and proper error logging when channels are not found. The delegation to the connection manager with reliable delivery (true) is also correct.


11-12: LGTM: Well-designed interface extension.

The interface design is clean and extends PluginConnectionAdapter appropriately while adding the specific setChannelSerial functionality needed for LiveObjects.

live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (4)

5-317: Excellent data model design with comprehensive spec coverage.

The data models are well-structured with proper separation of concerns, comprehensive spec references (OOP2, MAP2, etc.), and appropriate nullable/non-nullable field designations. The mutually exclusive relationship between operation and object fields in ObjectMessage is clearly documented and properly represents the protocol requirements.


9-16: LGTM: Well-defined operation actions.

The enum follows the spec (OOP2) correctly and provides a comprehensive set of operation types for object manipulation.


140-199: LGTM: Comprehensive operation structure.

The ObjectOperation class provides a well-designed structure that covers all the specified operation types with appropriate payloads. The spec references are helpful for understanding the purpose of each field.


22-24:

Details

❓ Verification inconclusive

Verify if MapSemantics enum is complete.

Currently only LWW (Last Writer Wins) semantics is defined. Confirm if this is intentional or if additional semantics will be added later.


🏁 Script executed:

#!/bin/bash
# Description: Check if there are references to other map semantics in the codebase
# Expected: Find any references to semantics other than LWW

rg -i "semantics|LWW|first.*win|conflict.*resol" --type kotlin --type java

Length of output: 654


Confirm MapSemantics completeness: only LWW is defined

We ran a repository-wide search for any other map semantics and found only the single LWW(0) entry in MapSemantics.

• If Last-Writer-Wins is the only conflict-resolution model you intend to support, consider adding a comment or TODO in ObjectMessage.kt clarifying that no other semantics are currently available.
• If additional semantics are planned (e.g., first-write-wins, custom resolution), please update MapSemantics with those values now or note them in the backlog.

@sacOO7 sacOO7 force-pushed the feature/declare-data-models branch from 288776b to 760ac54 Compare May 27, 2025 12:13
@github-actions github-actions bot temporarily deployed to staging/pull/1087/features May 27, 2025 12:14 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1087/javadoc May 27, 2025 12:20 Inactive
@sacOO7 sacOO7 requested a review from ttypic May 27, 2025 12:21
@sacOO7 sacOO7 force-pushed the feature/declare-data-models branch from 760ac54 to 375328e Compare May 27, 2025 14:30
@github-actions github-actions bot temporarily deployed to staging/pull/1087/features May 27, 2025 14:31 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1087/javadoc May 27, 2025 14:37 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1087/features May 28, 2025 16:31 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/objects/Adapter.java (1)

12-12: Fix TAG field to use correct class name.

The TAG field should use the actual class name for more accurate logging.

-    private static final String TAG = LiveObjectsAdapter.class.getName();
+    private static final String TAG = Adapter.class.getName();
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 375328e and 6fdc57d.

📒 Files selected for processing (6)
  • lib/src/main/java/io/ably/lib/objects/Adapter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java (2 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (3 hunks)
  • lib/src/main/java/io/ably/lib/plugins/PluginInstance.java (0 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (1 hunks)
💤 Files with no reviewable changes (1)
  • lib/src/main/java/io/ably/lib/plugins/PluginInstance.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt
🧰 Additional context used
🧠 Learnings (1)
lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java (1)
Learnt from: sacOO7
PR: ably/ably-java#1087
File: lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java:32-34
Timestamp: 2025-05-27T12:11:25.084Z
Learning: In LiveObjects implementation (lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java), the send method intentionally hardcodes queueEvents to true rather than respecting ably.options.queueMessages. This is because LiveObjects requires reliable message delivery to ensure proper state synchronization and acknowledgment, unlike other realtime components that may allow configurable queuing behavior.
🧬 Code Graph Analysis (1)
lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java (2)
lib/src/main/java/io/ably/lib/types/ProtocolMessage.java (1)
  • ProtocolMessage (29-318)
live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt (1)
  • channelName (7-64)
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: check (21)
  • GitHub Check: check-rest
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check (29)
  • GitHub Check: check (24)
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check-realtime
  • GitHub Check: check
  • GitHub Check: check (19)
  • GitHub Check: build
🔇 Additional comments (6)
lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (1)

11-11: LGTM: Interface simplification improves clarity.

The removal of PluginInstance extension and direct declaration of handle() and dispose() methods makes the interface more self-contained and explicit about its dependencies. This aligns with interface segregation principles and reduces coupling between plugin interfaces.

Also applies to: 24-31, 42-45

lib/src/main/java/io/ably/lib/objects/Adapter.java (3)

10-16: LGTM: Clean adapter implementation with proper dependency injection.

The constructor properly encapsulates the AblyRealtime dependency, and the class serves as a clear bridge between the LiveObjects system and the Ably realtime connection.


18-25: Good error handling for missing channels.

The implementation properly checks for channel existence before setting the serial and logs an appropriate error message when the channel is not found. This prevents potential null pointer exceptions and provides useful debugging information.


27-31: Proper implementation with documented rationale.

The send method correctly implements the reliable queuing behavior with a clear comment explaining why LiveObjects always queues messages for state synchronization. This aligns with the previous discussions and learnings about reliable message delivery requirements.

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

1-1: LGTM: Improved interface naming and package organization.

Renaming from PluginConnectionAdapter to LiveObjectsAdapter and moving to the io.ably.lib.objects package better reflects the specific purpose of this interface and improves code organization by grouping LiveObjects-related components.

Also applies to: 8-8


20-25: Good addition of channel serial management.

The new setChannelSerial method provides the necessary functionality for LiveObjects to manage channel serials for state synchronization. The @NotNull annotations improve type safety and make the contract explicit.

@github-actions github-actions bot temporarily deployed to staging/pull/1087/javadoc May 28, 2025 16:38 Inactive
@sacOO7 sacOO7 force-pushed the feature/declare-data-models branch from 6fdc57d to a5457e1 Compare May 28, 2025 16:39
@github-actions github-actions bot temporarily deployed to staging/pull/1087/features May 28, 2025 16:40 Inactive
@sacOO7 sacOO7 force-pushed the feature/declare-data-models branch from a5457e1 to d20ee1b Compare May 28, 2025 16:40
@github-actions github-actions bot temporarily deployed to staging/pull/1087/features May 28, 2025 16:41 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)
live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (1)

33-43: Review null handling in equals method.

The equals implementation has a potential issue with null handling. Currently, if both data and other.data are null, the method returns false due to the == true check on line 37.

Consider this improvement for more intuitive null handling:

  override fun equals(other: Any?): Boolean {
    if (this === other) return true
    if (other !is Binary) return false
-   return data?.contentEquals(other.data) == true
+   return if (data == null && other.data == null) true
+          else data?.contentEquals(other.data) == true
  }

This ensures that two Binary instances with null data are considered equal.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6fdc57d and d20ee1b.

📒 Files selected for processing (7)
  • lib/src/main/java/io/ably/lib/objects/Adapter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java (2 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (3 hunks)
  • lib/src/main/java/io/ably/lib/plugins/PluginInstance.java (0 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (1 hunks)
💤 Files with no reviewable changes (1)
  • lib/src/main/java/io/ably/lib/plugins/PluginInstance.java
🚧 Files skipped from review as they are similar to previous changes (4)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java
  • lib/src/main/java/io/ably/lib/objects/Adapter.java
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: build
  • GitHub Check: check (21)
  • GitHub Check: check (29)
  • GitHub Check: check-realtime-okhttp
  • GitHub Check: check-rest-okhttp
  • GitHub Check: check (19)
  • GitHub Check: check-rest
  • GitHub Check: check-realtime
  • GitHub Check: check (24)
  • GitHub Check: check
🔇 Additional comments (20)
live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (5)

8-24: Well-implemented coroutine wrapper with proper error handling.

The sendAsync extension function correctly wraps the callback-based send method into a suspend function. The implementation properly handles both success and error cases, catches synchronous exceptions, and uses CompletableDeferred appropriately.


26-31: Clean enum implementation with proper toString override.

The ProtocolMessageFormat enum is well-structured with meaningful string values and a proper toString() override that returns the associated value rather than the enum name.


33-43: Correct implementation of equals and hashCode for ByteArray wrapper.

The Binary class properly implements equals and hashCode for wrapping nullable ByteArray. The use of contentEquals and contentHashCode is correct for byte array comparison, and the null handling is appropriate.


8-24: Well-implemented coroutine extension.

The sendAsync extension function properly bridges the callback-based send method to a suspend function using CompletableDeferred. The error handling correctly converts ErrorInfo to Exception and catches synchronous exceptions.


26-31: Clean enum design with proper string representation.

The ProtocolMessageFormat enum is well-designed with meaningful constants and a proper toString() implementation for string serialization.

live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (15)

7-14: Well-structured enum with clear action codes.

The ObjectOperationAction enum uses proper PascalCase naming (as addressed in past feedback) and provides clear integer codes for each operation type. The structure is clean and follows Kotlin conventions.


28-46: Flexible data model for object values.

The ObjectData class provides a well-designed union-type structure that can represent object references, encoded values, or concrete values. The nullable fields allow for flexible usage patterns while maintaining type safety.


138-197: Comprehensive operation model with proper type usage.

The ObjectOperation class effectively models all operation types with appropriate payload fields. The use of Binary and ProtocolMessageFormat from the same package (Helpers.kt) is correct and doesn't require imports. All fields are properly immutable as addressed in previous feedback.


249-315: Well-designed message structure following specifications.

The ObjectMessage class provides a comprehensive model for object messages with proper mutual exclusivity between operation and objectState fields. The extensive documentation with spec references enhances maintainability. The immutable design (using val) aligns with best practices for data models.


7-14: Well-designed operation action enum.

The ObjectOperationAction enum properly uses PascalCase naming and provides clear integer codes for protocol operations. The comprehensive set of actions covers the expected LiveObjects operations.


20-22: Consistent enum design for conflict resolution.

The MapSemantics enum follows the same well-established pattern as other enums in the file. The single LWW (Last Writer Wins) value suggests room for future conflict resolution strategies.


28-46: Well-structured data class for object values.

The ObjectData class properly models different value types (references, encoded data, concrete values) with clear separation of concerns. The use of immutable val fields and comprehensive documentation enhances maintainability.


52-64: Focused data class for map operations.

The MapOp class has a clean design with a required key and optional data field, making it suitable for both set and remove operations on maps.


70-76: Simple and effective counter operation design.

The CounterOp class appropriately uses a Double type for the amount field, allowing both integer and decimal operations while maintaining simplicity.


82-102: Well-designed map entry with temporal metadata.

The MapEntry class effectively models map entries with tombstone deletion markers and timeserial ordering, providing the necessary metadata for conflict resolution.


108-120: Clean map object representation.

The ObjectMap class properly encapsulates conflict resolution semantics and key-value entries, providing a complete map abstraction.


126-132: Simple counter object design.

The ObjectCounter class maintains a focused design with just the essential count value, appropriate for its single responsibility.


138-197: Comprehensive operation model with proper field organization.

The ObjectOperation class effectively models all operation types with appropriate optional fields for different operation payloads. The use of Binary for initialValue and the immutable design enhance reliability.


203-243: Complete object state representation.

The ObjectState class properly models object snapshots with site timeserials for distributed consistency and separate fields for different object types.


249-315: Well-structured message envelope with mutual exclusivity.

The ObjectMessage class provides a comprehensive message envelope with proper metadata fields. The mutual exclusivity between operation and objectState fields is well-documented and appropriate for the protocol design.

1. Updated enum ObjectOperationAction with PascalCase values
2. Created separate file for adapter that extends LiveObjectsAdapter
3. Added custom Binary type to handle ByteArray values
@sacOO7 sacOO7 force-pushed the feature/declare-data-models branch from d20ee1b to 431cfe7 Compare May 28, 2025 16:46
@github-actions github-actions bot temporarily deployed to staging/pull/1087/features May 28, 2025 16:47 Inactive
@sacOO7 sacOO7 requested a review from ttypic May 28, 2025 16:51
@github-actions github-actions bot temporarily deployed to staging/pull/1087/javadoc May 28, 2025 16:52 Inactive
@sacOO7
Copy link
Collaborator Author

sacOO7 commented May 29, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented May 29, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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 (1)
live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (1)

249-315: Comprehensive message class with excellent documentation.

The ObjectMessage class is well-designed with appropriate optional fields and comprehensive documentation. The mutual exclusivity between operation and objectState is clearly documented, and the fallback behavior for missing fields is well-explained.

Consider using a sealed class hierarchy to enforce the mutual exclusivity of operation and objectState at compile time:

internal sealed class ObjectMessage {
  abstract val id: String?
  abstract val timestamp: Long?
  // ... other common fields
  
  data class OperationMessage(
    override val id: String? = null,
    // ... other fields
    val operation: ObjectOperation
  ) : ObjectMessage()
  
  data class StateMessage(
    override val id: String? = null,
    // ... other fields  
    val objectState: ObjectState
  ) : ObjectMessage()
}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d20ee1b and 431cfe7.

📒 Files selected for processing (7)
  • lib/src/main/java/io/ably/lib/objects/Adapter.java (1 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java (2 hunks)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java (3 hunks)
  • lib/src/main/java/io/ably/lib/plugins/PluginInstance.java (0 hunks)
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java (2 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt (1 hunks)
  • live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (1 hunks)
💤 Files with no reviewable changes (1)
  • lib/src/main/java/io/ably/lib/plugins/PluginInstance.java
🚧 Files skipped from review as they are similar to previous changes (5)
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java
  • lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java
  • lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java
  • lib/src/main/java/io/ably/lib/objects/Adapter.java
  • live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt
🔇 Additional comments (8)
live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt (8)

7-14: Well-structured enum following Kotlin conventions.

The ObjectOperationAction enum properly uses PascalCase naming and provides integer codes for serialization. The comprehensive coverage of map operations, counter operations, and object deletion aligns well with the specification.


20-22: Clean enum design ready for future extension.

The MapSemantics enum is well-structured with proper naming conventions. While it currently only supports LWW (Last Write Wins), the design allows for easy addition of other conflict resolution strategies in the future.


28-46: Well-designed data class with appropriate flexibility.

The ObjectData class properly balances flexibility and structure. The use of Any? for the value field allows support for various data types (string, number, boolean, binary) as specified in the protocol, which is appropriate for this messaging context.


52-64: Clean and focused data class design.

The MapOp class has a clear, minimal design that properly represents map operations with a required key and optional data payload.


70-76: Appropriate design for counter operations.

The CounterOp class correctly uses Double for the amount field, which allows both positive and negative values to support increment and decrement operations.


82-102: Comprehensive design for distributed map entries.

The MapEntry class properly handles the complexities of distributed systems with tombstone markers for deletions and timeserial for operation ordering. The documentation clearly explains the behavior for missing timeserial values.


108-132: Well-structured object representation classes.

Both ObjectMap and ObjectCounter have appropriate designs. The optional fields in ObjectMap support incremental updates, and the consistent use of Double across counter-related classes maintains type consistency.


203-243: Excellent object state representation.

The ObjectState class properly distinguishes between required fields (objectId, siteTimeserials, tombstone) and optional contextual information. The design effectively supports both map and counter object types.

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, added small comment to update callback -> suspend transformation

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 : Declare internal models as per spec

3 participants