Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/src/main/java/io/ably/lib/object/ValueType.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ public enum ValueType {
LIVE_MAP,
/** Corresponds to a {@code LiveCounter} object. Spec: RTTS2a8 */
LIVE_COUNTER,
/** Returned when path resolution fails or the resolved value has none of the known types; never produced by an {@code Instance} in normal operation. Spec: RTTS2a9 */
/** Returned by {@code PathObject#getType()} only when a value is present but matches none of the known types. Never produced by an {@code Instance} in normal operation. Spec: RTTS2a9 */
UNKNOWN,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.ably.lib.object.adapter;

import io.ably.lib.realtime.ChannelBase;
import io.ably.lib.realtime.Connection;
import io.ably.lib.types.AblyException;
import io.ably.lib.types.ClientOptions;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.NotNull;

/**
* Bridges the path-based LiveObjects implementation to the core Ably client, exposing the
* client configuration, connection and channel state it needs without coupling it to the
* concrete {@link io.ably.lib.realtime.AblyRealtime} type.
*
* <p>This is the adapter for the path-based {@code io.ably.lib.object} API and is intentionally
* kept independent of the legacy {@code io.ably.lib.objects} package.
*/
public interface AblyClientAdapter {
/**
* Retrieves the client options configured for the Ably client.
* Used to access client configuration parameters such as echoMessages setting
* that affect the behavior of Objects operations.
*
* @return the client options containing configuration parameters
*/
@NotNull ClientOptions getClientOptions();

/**
* Retrieves the connection instance for handling connection state and operations.
* Used to check connection status, obtain error information, and manage
* message transmission across the Ably connection.
*
* @return the connection instance
*/
@NotNull Connection getConnection();

/**
* Retrieves the current time in milliseconds from the Ably server.
* Spec: RTO16
*/
@Blocking
long getTime() throws AblyException;

/**
* Retrieves the channel instance for the specified channel name.
* If the channel does not exist, an AblyException is thrown.
*
* @param channelName the name of the channel to retrieve
* @return the ChannelBase instance for the specified channel
* @throws AblyException if the channel is not found or cannot be retrieved
*/
@NotNull ChannelBase getChannel(@NotNull String channelName) throws AblyException;
}
50 changes: 50 additions & 0 deletions lib/src/main/java/io/ably/lib/object/adapter/Adapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.ably.lib.object.adapter;

import io.ably.lib.realtime.AblyRealtime;
import io.ably.lib.realtime.ChannelBase;
import io.ably.lib.realtime.Connection;
import io.ably.lib.types.AblyException;
import io.ably.lib.types.ClientOptions;
import io.ably.lib.types.ErrorInfo;
import io.ably.lib.util.Log;
import org.jetbrains.annotations.NotNull;

/**
* Default {@link AblyClientAdapter} implementation backed by an {@link AblyRealtime} client.
* Holding the {@code AblyRealtime} reference gives the path-based LiveObjects implementation
* access to the full client configuration and runtime state it may need.
*/
public class Adapter implements AblyClientAdapter {
private final AblyRealtime ably;
private static final String TAG = AblyClientAdapter.class.getName();

public Adapter(@NotNull AblyRealtime ably) {
this.ably = ably;
}

@Override
public @NotNull ClientOptions getClientOptions() {
return ably.options;
}

@Override
public @NotNull Connection getConnection() {
return ably.connection;
}

@Override
public long getTime() throws AblyException {
return ably.time();
}

@Override
public @NotNull ChannelBase getChannel(@NotNull String channelName) throws AblyException {
if (ably.channels.containsKey(channelName)) {
return ably.channels.get(channelName);
} else {
Log.e(TAG, "getChannel(): channel not found: " + channelName);
ErrorInfo errorInfo = new ErrorInfo("Channel not found: " + channelName, 404);
throw AblyException.fromErrorInfo(errorInfo);
Comment thread
sacOO7 marked this conversation as resolved.
Outdated
}
}
}
10 changes: 10 additions & 0 deletions lib/src/main/java/io/ably/lib/object/adapter/package-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Adapter layer bridging the path-based LiveObjects implementation to the core Ably client.
* {@link io.ably.lib.object.adapter.AblyClientAdapter} is the abstraction the implementation
* depends on; {@link io.ably.lib.object.adapter.Adapter} is the default implementation backed
* by an {@link io.ably.lib.realtime.AblyRealtime} client.
*
* <p>This package is intentionally independent of the legacy {@code io.ably.lib.objects}
* package so the path-based API can evolve on its own.
*/
package io.ably.lib.object.adapter;
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.ably.lib.object.instance.types;

import com.google.gson.JsonPrimitive;
import io.ably.lib.object.instance.Instance;
import org.jetbrains.annotations.NotNull;

Expand All @@ -22,4 +23,15 @@ public interface BinaryInstance extends Instance {
* @return the wrapped bytes
*/
byte @NotNull [] value();

/**
* Returns the compacted JSON snapshot of the wrapped value, narrowed to a
* {@link JsonPrimitive}: binary compacts to a base64-encoded JSON string.
*
* <p>Spec: RTTS7a
*
* @return the compacted JSON primitive
*/
@Override
@NotNull JsonPrimitive compactJson();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.ably.lib.object.instance.types;

import com.google.gson.JsonPrimitive;
import io.ably.lib.object.instance.Instance;
import org.jetbrains.annotations.NotNull;

Expand All @@ -22,4 +23,16 @@ public interface BooleanInstance extends Instance {
*/
@NotNull
Boolean value();

/**
* Returns the compacted JSON snapshot of the wrapped value, narrowed to a
* {@link JsonPrimitive}: a {@code BooleanInstance} always compacts to a single
* JSON primitive.
*
* <p>Spec: RTTS7a
*
* @return the compacted JSON primitive
*/
@Override
@NotNull JsonPrimitive compactJson();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,15 @@ public interface JsonArrayInstance extends Instance {
*/
@NotNull
JsonArray value();

/**
* Returns the compacted JSON snapshot of the wrapped value, narrowed to a
* {@link JsonArray}: a {@code JsonArrayInstance} always compacts to a JSON array.
*
* <p>Spec: RTTS7a
*
* @return the compacted JSON array
*/
@Override
@NotNull JsonArray compactJson();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,15 @@ public interface JsonObjectInstance extends Instance {
*/
@NotNull
JsonObject value();

/**
* Returns the compacted JSON snapshot of the wrapped value, narrowed to a
* {@link JsonObject}: a {@code JsonObjectInstance} always compacts to a JSON object.
*
* <p>Spec: RTTS7a
*
* @return the compacted JSON object
*/
@Override
@NotNull JsonObject compactJson();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.ably.lib.object.instance.types;

import com.google.gson.JsonPrimitive;
import io.ably.lib.object.instance.Instance;
import io.ably.lib.object.instance.InstanceListener;
import io.ably.lib.object.Subscription;
Expand Down Expand Up @@ -37,6 +38,18 @@ public interface LiveCounterInstance extends Instance {
@NotNull
Double value();

/**
* Returns the compacted JSON snapshot of the wrapped value, narrowed to a
* {@link JsonPrimitive}: a {@code LiveCounterInstance} always compacts to a numeric
* JSON primitive.
*
* <p>Spec: RTTS7a
*
* @return the compacted JSON primitive
*/
@Override
@NotNull JsonPrimitive compactJson();

/**
* Increments the wrapped {@code LiveCounter} by {@code 1}. Equivalent to
* calling {@link #increment(Number)} with {@code 1}.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.ably.lib.object.instance.types;

import com.google.gson.JsonObject;
import io.ably.lib.object.instance.Instance;
import io.ably.lib.object.instance.InstanceListener;
import io.ably.lib.object.Subscription;
Expand Down Expand Up @@ -34,6 +35,18 @@ public interface LiveMapInstance extends Instance {
@NotNull
String getId();

/**
* Returns the compacted JSON snapshot of the wrapped value, narrowed to a
* {@link JsonObject}: a {@code LiveMapInstance} compacts to a JSON object (or, for a
* cyclic reference, an object-id reference object).
*
* <p>Spec: RTTS7a
*
* @return the compacted JSON object
*/
@Override
@NotNull JsonObject compactJson();

/**
* Returns a {@link Instance} wrapping the value at {@code key} of the
* wrapped {@code LiveMap}, or {@code null} when the key is absent / tombstoned.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.ably.lib.object.instance.types;

import com.google.gson.JsonPrimitive;
import io.ably.lib.object.instance.Instance;
import org.jetbrains.annotations.NotNull;

Expand All @@ -22,4 +23,16 @@ public interface NumberInstance extends Instance {
*/
@NotNull
Number value();

/**
* Returns the compacted JSON snapshot of the wrapped value, narrowed to a
* {@link JsonPrimitive}: a {@code NumberInstance} always compacts to a single
* JSON primitive.
*
* <p>Spec: RTTS7a
*
* @return the compacted JSON primitive
*/
@Override
@NotNull JsonPrimitive compactJson();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.ably.lib.object.instance.types;

import com.google.gson.JsonPrimitive;
import io.ably.lib.object.instance.Instance;
import org.jetbrains.annotations.NotNull;

Expand All @@ -22,4 +23,16 @@ public interface StringInstance extends Instance {
*/
@NotNull
String value();

/**
* Returns the compacted JSON snapshot of the wrapped value, narrowed to a
* {@link JsonPrimitive}: a {@code StringInstance} always compacts to a single
* JSON primitive.
*
* <p>Spec: RTTS7a
*
* @return the compacted JSON primitive
*/
@Override
@NotNull JsonPrimitive compactJson();
}
17 changes: 11 additions & 6 deletions lib/src/main/java/io/ably/lib/object/path/PathObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,22 @@
public interface PathObject {

/**
* Returns the {@link ValueType} of the value resolved at this path currently.
* Use this instead of dedicated {@code isLiveMap}/{@code isLiveCounter}/etc. checks.
* Returns the {@link ValueType} of the value currently resolved at this path, or
* {@code null} when the path does not resolve to any value. Use this instead of
* dedicated {@code isLiveMap}/{@code isLiveCounter}/etc. checks.
*
* <p>Returns {@link ValueType#UNKNOWN} when the path does not resolve or the
* resolved value falls into none of the known categories.
* <p>A {@code null} result means there is no value at this path - nothing is stored
* there (e.g. an absent or removed map entry). This is deliberately distinct from
* {@link ValueType#UNKNOWN}, which is returned only when a value <em>is</em> present
* but its type matches none of the known categories. In other words: {@code null}
* means "no value", {@code UNKNOWN} means "a value of an unrecognized type".
*
* <p>Spec: RTTS4b
*
* @return the resolved value type at this path
* @return the resolved value type at this path, or {@code null} if the path does
* not resolve to a value
*/
@NotNull ValueType getType();
@Nullable ValueType getType();

/**
* Returns a dot-delimited string representation of the stored path segments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*/
public abstract class LiveCounter {

private static final String IMPLEMENTATION_CLASS = "io.ably.lib.object.DefaultLiveCounter";
private static final String IMPLEMENTATION_CLASS = "io.ably.lib.object.value.DefaultLiveCounter";

/**
* Extended by the LiveObjects implementation; not intended for
Expand Down
2 changes: 1 addition & 1 deletion lib/src/main/java/io/ably/lib/object/value/LiveMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
*/
public abstract class LiveMap {

private static final String IMPLEMENTATION_CLASS = "io.ably.lib.object.DefaultLiveMap";
private static final String IMPLEMENTATION_CLASS = "io.ably.lib.object.value.DefaultLiveMap";

/**
* Extended by the LiveObjects implementation; not intended for
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.ably.lib.`object`

import io.ably.lib.`object`.adapter.AblyClientAdapter
import io.ably.lib.`object`.path.types.LiveMapPathObject
import io.ably.lib.`object`.state.ObjectStateChange
import io.ably.lib.`object`.state.ObjectStateEvent
import java.util.concurrent.CompletableFuture

/**
* Default implementation of [RealtimeObject], the entry point to the strongly-typed,
* path-based LiveObjects API for a single channel.
*
* This is currently a skeleton: the path-based read and subscribe operations are not yet
* implemented. The method bodies will be filled in as the path-based API is built out.
*
* Spec: RTO23
*/
internal class DefaultRealtimeObject(
internal val channelName: String,
internal val adapter: AblyClientAdapter,
) : RealtimeObject {

override fun get(): CompletableFuture<LiveMapPathObject> = TODO("Not yet implemented")
Comment thread
coderabbitai[bot] marked this conversation as resolved.

override fun on(event: ObjectStateEvent, listener: ObjectStateChange.Listener): Subscription {
// TODO - subscribe logic goes here
return onceSubscription {
// TODO - remove ObjectStateChange.Listener
}
}

override fun off(listener: ObjectStateChange.Listener): Unit = TODO("Not yet implemented")

override fun offAll(): Unit = TODO("Not yet implemented")
}
Loading
Loading