diff --git a/android/src/main/java/io/ably/lib/realtime/Channel.java b/android/src/main/java/io/ably/lib/realtime/Channel.java index baf086cbc..9d5ee6ab0 100644 --- a/android/src/main/java/io/ably/lib/realtime/Channel.java +++ b/android/src/main/java/io/ably/lib/realtime/Channel.java @@ -3,7 +3,7 @@ import io.ably.lib.types.AblyException; import io.ably.lib.types.ChannelOptions; import io.ably.lib.push.PushChannel; -import io.ably.lib.objects.LiveObjectsPlugin; +import io.ably.lib.objects.ObjectsPlugin; public class Channel extends ChannelBase { @@ -14,8 +14,8 @@ public class Channel extends ChannelBase { */ public final PushChannel push; - Channel(AblyRealtime ably, String name, ChannelOptions options, LiveObjectsPlugin liveObjectsPlugin) throws AblyException { - super(ably, name, options, liveObjectsPlugin); + Channel(AblyRealtime ably, String name, ChannelOptions options, ObjectsPlugin objectsPlugin) throws AblyException { + super(ably, name, options, objectsPlugin); this.push = ((io.ably.lib.rest.AblyRest) ably).channels.get(name, options).push; } diff --git a/java/src/main/java/io/ably/lib/realtime/Channel.java b/java/src/main/java/io/ably/lib/realtime/Channel.java index b48c929b1..0f1d9a53e 100644 --- a/java/src/main/java/io/ably/lib/realtime/Channel.java +++ b/java/src/main/java/io/ably/lib/realtime/Channel.java @@ -1,12 +1,13 @@ package io.ably.lib.realtime; -import io.ably.lib.objects.LiveObjectsPlugin; +import io.ably.lib.objects.ObjectsPlugin; import io.ably.lib.types.AblyException; import io.ably.lib.types.ChannelOptions; +import org.jetbrains.annotations.Nullable; public class Channel extends ChannelBase { - Channel(AblyRealtime ably, String name, ChannelOptions options, LiveObjectsPlugin liveObjectsPlugin) throws AblyException { - super(ably, name, options, liveObjectsPlugin); + Channel(AblyRealtime ably, String name, ChannelOptions options, @Nullable ObjectsPlugin objectsPlugin) throws AblyException { + super(ably, name, options, objectsPlugin); } public interface MessageListener extends ChannelBase.MessageListener {} diff --git a/lib/src/main/java/io/ably/lib/objects/Adapter.java b/lib/src/main/java/io/ably/lib/objects/Adapter.java index 4c7da7551..e9a084ae7 100644 --- a/lib/src/main/java/io/ably/lib/objects/Adapter.java +++ b/lib/src/main/java/io/ably/lib/objects/Adapter.java @@ -9,9 +9,9 @@ import io.ably.lib.util.Log; import org.jetbrains.annotations.NotNull; -public class Adapter implements LiveObjectsAdapter { +public class Adapter implements ObjectsAdapter { private final AblyRealtime ably; - private static final String TAG = LiveObjectsAdapter.class.getName(); + private static final String TAG = ObjectsAdapter.class.getName(); public Adapter(@NotNull AblyRealtime ably) { this.ably = ably; diff --git a/lib/src/main/java/io/ably/lib/objects/LiveObjectsHelper.java b/lib/src/main/java/io/ably/lib/objects/LiveObjectsHelper.java deleted file mode 100644 index 288bf7459..000000000 --- a/lib/src/main/java/io/ably/lib/objects/LiveObjectsHelper.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.ably.lib.objects; - -import io.ably.lib.realtime.AblyRealtime; -import io.ably.lib.util.Log; - -import java.lang.reflect.InvocationTargetException; - -public class LiveObjectsHelper { - - private static final String TAG = LiveObjectsHelper.class.getName(); - private static volatile LiveObjectSerializer liveObjectSerializer; - - public static LiveObjectsPlugin tryInitializeLiveObjectsPlugin(AblyRealtime ablyRealtime) { - try { - Class liveObjectsImplementation = Class.forName("io.ably.lib.objects.DefaultLiveObjectsPlugin"); - LiveObjectsAdapter adapter = new Adapter(ablyRealtime); - return (LiveObjectsPlugin) liveObjectsImplementation - .getDeclaredConstructor(LiveObjectsAdapter.class) - .newInstance(adapter); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | - InvocationTargetException e) { - Log.i(TAG, "LiveObjects plugin not found in classpath. LiveObjects functionality will not be available.", e); - return null; - } - } - - public static LiveObjectSerializer getLiveObjectSerializer() { - if (liveObjectSerializer == null) { - synchronized (LiveObjectsHelper.class) { - if (liveObjectSerializer == null) { // Double-Checked Locking (DCL) - try { - Class serializerClass = Class.forName("io.ably.lib.objects.serialization.DefaultLiveObjectSerializer"); - liveObjectSerializer = (LiveObjectSerializer) serializerClass.getDeclaredConstructor().newInstance(); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | - NoSuchMethodException | - InvocationTargetException e) { - Log.w(TAG, "Failed to init LiveObjectSerializer, LiveObjects plugin not included in the classpath", e); - return null; - } - } - } - } - return liveObjectSerializer; - } -} diff --git a/lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java b/lib/src/main/java/io/ably/lib/objects/ObjectsAdapter.java similarity index 94% rename from lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java rename to lib/src/main/java/io/ably/lib/objects/ObjectsAdapter.java index 9f2db0595..21262942a 100644 --- a/lib/src/main/java/io/ably/lib/objects/LiveObjectsAdapter.java +++ b/lib/src/main/java/io/ably/lib/objects/ObjectsAdapter.java @@ -7,11 +7,11 @@ import org.jetbrains.annotations.Blocking; import org.jetbrains.annotations.NotNull; -public interface LiveObjectsAdapter { +public interface ObjectsAdapter { /** * Retrieves the client options configured for the Ably client. * Used to access client configuration parameters such as echoMessages setting - * that affect the behavior of LiveObjects operations. + * that affect the behavior of Objects operations. * * @return the client options containing configuration parameters */ diff --git a/lib/src/main/java/io/ably/lib/objects/ObjectsCallback.java b/lib/src/main/java/io/ably/lib/objects/ObjectsCallback.java index f6614918f..0afd5ef2f 100644 --- a/lib/src/main/java/io/ably/lib/objects/ObjectsCallback.java +++ b/lib/src/main/java/io/ably/lib/objects/ObjectsCallback.java @@ -3,9 +3,9 @@ import io.ably.lib.types.AblyException; /** - * Callback interface for handling results of asynchronous LiveObjects operations. + * Callback interface for handling results of asynchronous Objects operations. * Used for operations like creating LiveMaps/LiveCounters, modifying entries, and retrieving objects. - * Callbacks are executed on background threads managed by the LiveObjects system. + * Callbacks are executed on background threads managed by the Objects system. * * @param the type of the result returned by the asynchronous operation */ diff --git a/lib/src/main/java/io/ably/lib/objects/ObjectsHelper.java b/lib/src/main/java/io/ably/lib/objects/ObjectsHelper.java new file mode 100644 index 000000000..38b000a11 --- /dev/null +++ b/lib/src/main/java/io/ably/lib/objects/ObjectsHelper.java @@ -0,0 +1,48 @@ +package io.ably.lib.objects; + +import io.ably.lib.realtime.AblyRealtime; +import io.ably.lib.util.Log; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.InvocationTargetException; + +public class ObjectsHelper { + + private static final String TAG = ObjectsHelper.class.getName(); + private static volatile ObjectsSerializer objectsSerializer; + + @Nullable + public static ObjectsPlugin tryInitializeObjectsPlugin(AblyRealtime ablyRealtime) { + try { + Class objectsImplementation = Class.forName("io.ably.lib.objects.DefaultObjectsPlugin"); + ObjectsAdapter adapter = new Adapter(ablyRealtime); + return (ObjectsPlugin) objectsImplementation + .getDeclaredConstructor(ObjectsAdapter.class) + .newInstance(adapter); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | + InvocationTargetException e) { + Log.i(TAG, "LiveObjects plugin not found in classpath. LiveObjects functionality will not be available.", e); + return null; + } + } + + @Nullable + public static ObjectsSerializer getSerializer() { + if (objectsSerializer == null) { + synchronized (ObjectsHelper.class) { + if (objectsSerializer == null) { // Double-Checked Locking (DCL) + try { + Class serializerClass = Class.forName("io.ably.lib.objects.serialization.DefaultObjectsSerializer"); + objectsSerializer = (ObjectsSerializer) serializerClass.getDeclaredConstructor().newInstance(); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | + NoSuchMethodException | + InvocationTargetException e) { + Log.w(TAG, "Failed to init ObjectsSerializer, LiveObjects plugin not included in the classpath", e); + return null; + } + } + } + } + return objectsSerializer; + } +} diff --git a/lib/src/main/java/io/ably/lib/objects/LiveObjectsJsonSerializer.java b/lib/src/main/java/io/ably/lib/objects/ObjectsJsonSerializer.java similarity index 72% rename from lib/src/main/java/io/ably/lib/objects/LiveObjectsJsonSerializer.java rename to lib/src/main/java/io/ably/lib/objects/ObjectsJsonSerializer.java index 505f9c5d8..b96954ca8 100644 --- a/lib/src/main/java/io/ably/lib/objects/LiveObjectsJsonSerializer.java +++ b/lib/src/main/java/io/ably/lib/objects/ObjectsJsonSerializer.java @@ -11,14 +11,14 @@ import java.lang.reflect.Type; -public class LiveObjectsJsonSerializer implements JsonSerializer, JsonDeserializer { - private static final String TAG = LiveObjectsJsonSerializer.class.getName(); +public class ObjectsJsonSerializer implements JsonSerializer, JsonDeserializer { + private static final String TAG = ObjectsJsonSerializer.class.getName(); @Override public Object[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - LiveObjectSerializer serializer = LiveObjectsHelper.getLiveObjectSerializer(); + ObjectsSerializer serializer = ObjectsHelper.getSerializer(); if (serializer == null) { - Log.w(TAG, "Skipping 'state' field json deserialization because LiveObjectsSerializer not found."); + Log.w(TAG, "Skipping 'state' field json deserialization because ObjectsSerializer not found."); return null; } if (!json.isJsonArray()) { @@ -29,9 +29,9 @@ public Object[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationC @Override public JsonElement serialize(Object[] src, Type typeOfSrc, JsonSerializationContext context) { - LiveObjectSerializer serializer = LiveObjectsHelper.getLiveObjectSerializer(); + ObjectsSerializer serializer = ObjectsHelper.getSerializer(); if (serializer == null) { - Log.w(TAG, "Skipping 'state' field json serialization because LiveObjectsSerializer not found."); + Log.w(TAG, "Skipping 'state' field json serialization because ObjectsSerializer not found."); return JsonNull.INSTANCE; } return serializer.asJsonArray(src); diff --git a/lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java b/lib/src/main/java/io/ably/lib/objects/ObjectsPlugin.java similarity index 63% rename from lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java rename to lib/src/main/java/io/ably/lib/objects/ObjectsPlugin.java index 392b9f1df..ef30ab7f8 100644 --- a/lib/src/main/java/io/ably/lib/objects/LiveObjectsPlugin.java +++ b/lib/src/main/java/io/ably/lib/objects/ObjectsPlugin.java @@ -5,22 +5,22 @@ import org.jetbrains.annotations.NotNull; /** - * The LiveObjectsPlugin interface provides a mechanism for managing and interacting with + * The ObjectsPlugin interface provides a mechanism for managing and interacting with * live data objects in a real-time environment. It allows for the retrieval, disposal, and - * management of LiveObjects instances associated with specific channel names. + * management of Objects instances associated with specific channel names. */ -public interface LiveObjectsPlugin { +public interface ObjectsPlugin { /** - * Retrieves an instance of LiveObjects associated with the specified channel name. - * This method ensures that a LiveObjects instance is available for the given channel, + * Retrieves an instance of RealtimeObjects associated with the specified channel name. + * This method ensures that a RealtimeObjects instance is available for the given channel, * creating one if it does not already exist. * - * @param channelName the name of the channel for which the LiveObjects instance is to be retrieved. - * @return the LiveObjects instance associated with the specified channel name. + * @param channelName the name of the channel for which the RealtimeObjects instance is to be retrieved. + * @return the RealtimeObjects instance associated with the specified channel name. */ @NotNull - LiveObjects getInstance(@NotNull String channelName); + RealtimeObjects getInstance(@NotNull String channelName); /** * Handles a protocol message. @@ -34,7 +34,7 @@ public interface LiveObjectsPlugin { /** * Handles state changes for a specific channel. * This method is invoked whenever a channel's state changes, allowing the implementation - * to update the LiveObjects instances accordingly based on the new state and presence of objects. + * to update the RealtimeObjects instances accordingly based on the new state and presence of objects. * * @param channelName the name of the channel whose state has changed. * @param state the new state of the channel. @@ -43,12 +43,12 @@ public interface LiveObjectsPlugin { void handleStateChange(@NotNull String channelName, @NotNull ChannelState state, boolean hasObjects); /** - * Disposes of the LiveObjects instance associated with the specified channel name. - * This method removes the LiveObjects instance for the given channel, releasing any + * Disposes of the RealtimeObjects instance associated with the specified channel name. + * This method removes the RealtimeObjects instance for the given channel, releasing any * resources associated with it. * This is invoked when ablyRealtimeClient.channels.release(channelName) is called * - * @param channelName the name of the channel whose LiveObjects instance is to be removed. + * @param channelName the name of the channel whose RealtimeObjects instance is to be removed. */ void dispose(@NotNull String channelName); diff --git a/lib/src/main/java/io/ably/lib/objects/LiveObjectSerializer.java b/lib/src/main/java/io/ably/lib/objects/ObjectsSerializer.java similarity index 90% rename from lib/src/main/java/io/ably/lib/objects/LiveObjectSerializer.java rename to lib/src/main/java/io/ably/lib/objects/ObjectsSerializer.java index dcf0ce5cb..9bee9a8fd 100644 --- a/lib/src/main/java/io/ably/lib/objects/LiveObjectSerializer.java +++ b/lib/src/main/java/io/ably/lib/objects/ObjectsSerializer.java @@ -8,10 +8,9 @@ import java.io.IOException; /** - * Serializer interface for converting between LiveObject arrays and their - * MessagePack or JSON representations. + * Serializer interface for converting between objects and their MessagePack or JSON representations. */ -public interface LiveObjectSerializer { +public interface ObjectsSerializer { /** * Reads a MessagePack array from the given unpacker and deserializes it into an Object array. * diff --git a/lib/src/main/java/io/ably/lib/objects/LiveObjects.java b/lib/src/main/java/io/ably/lib/objects/RealtimeObjects.java similarity index 95% rename from lib/src/main/java/io/ably/lib/objects/LiveObjects.java rename to lib/src/main/java/io/ably/lib/objects/RealtimeObjects.java index 33db8b63c..950b41bf6 100644 --- a/lib/src/main/java/io/ably/lib/objects/LiveObjects.java +++ b/lib/src/main/java/io/ably/lib/objects/RealtimeObjects.java @@ -11,14 +11,14 @@ import java.util.Map; /** - * The LiveObjects interface provides methods to interact with live data objects, + * The RealtimeObjects 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. * *

Implementations of this interface must be thread-safe as they may be accessed * from multiple threads concurrently. */ -public interface LiveObjects extends ObjectsStateChange { +public interface RealtimeObjects extends ObjectsStateChange { /** * Retrieves the root LiveMap object. @@ -62,10 +62,10 @@ public interface LiveObjects extends ObjectsStateChange { * "binary", LiveMapValue.of(new byte[]{1, 2, 3}), * "array", LiveMapValue.of(new JsonArray()), * "object", LiveMapValue.of(new JsonObject()), - * "counter", LiveMapValue.of(liveObjects.createCounter()), - * "nested", LiveMapValue.of(liveObjects.createMap()) + * "counter", LiveMapValue.of(realtimeObjects.createCounter()), + * "nested", LiveMapValue.of(realtimeObjects.createMap()) * ); - * LiveMap map = liveObjects.createMap(entries); + * LiveMap map = realtimeObjects.createMap(entries); * } * * @param entries the type-safe map entries with values that can be Boolean, Binary, Number, String, JsonArray, JsonObject, LiveCounter, or LiveMap. diff --git a/lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java b/lib/src/main/java/io/ably/lib/objects/type/ObjectUpdate.java similarity index 71% rename from lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java rename to lib/src/main/java/io/ably/lib/objects/type/ObjectUpdate.java index abbb5476e..6df47cf99 100644 --- a/lib/src/main/java/io/ably/lib/objects/type/LiveObjectUpdate.java +++ b/lib/src/main/java/io/ably/lib/objects/type/ObjectUpdate.java @@ -3,12 +3,12 @@ import org.jetbrains.annotations.Nullable; /** - * Abstract base class for all LiveObject update notifications. + * Abstract base class for all LiveMap/LiveCounter update notifications. * Provides common structure for updates that occur on LiveMap and LiveCounter objects. * Contains the update data that describes what changed in the live object. * Spec: RTLO4b4 */ -public abstract class LiveObjectUpdate { +public abstract class ObjectUpdate { /** * The update data containing details about the change that occurred * Spec: RTLO4b4a @@ -17,11 +17,11 @@ public abstract class LiveObjectUpdate { protected final Object update; /** - * Creates a LiveObjectUpdate with the specified update data. + * Creates a ObjectUpdate with the specified update data. * * @param update the data describing the change, or null for no-op updates */ - protected LiveObjectUpdate(@Nullable Object update) { + protected ObjectUpdate(@Nullable Object update) { this.update = update; } } diff --git a/lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java b/lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java index d0362d27b..d7921a0b5 100644 --- a/lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java +++ b/lib/src/main/java/io/ably/lib/objects/type/counter/LiveCounterUpdate.java @@ -1,6 +1,6 @@ package io.ably.lib.objects.type.counter; -import io.ably.lib.objects.type.LiveObjectUpdate; +import io.ably.lib.objects.type.ObjectUpdate; import org.jetbrains.annotations.NotNull; /** @@ -10,7 +10,7 @@ * * @spec RTLC11, RTLC11a - LiveCounter update structure and behavior */ -public class LiveCounterUpdate extends LiveObjectUpdate { +public class LiveCounterUpdate extends ObjectUpdate { /** * Creates a no-op LiveCounterUpdate representing no actual change. diff --git a/lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java b/lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java index a6fae9ce0..46c336360 100644 --- a/lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java +++ b/lib/src/main/java/io/ably/lib/objects/type/map/LiveMap.java @@ -21,8 +21,8 @@ public interface LiveMap extends LiveMapChange { * If this map object is tombstoned (deleted), null is returned. * If no entry is associated with the specified key, null is returned. * If map entry is tombstoned (deleted), null is returned. - * If the value associated with the provided key is an objectId string of another LiveObject, a reference to that LiveObject - * is returned, provided it exists in the local pool and is not tombstoned. Otherwise, null is returned. + * If the value associated with the provided key is an objectId string of another RealtimeObject, a reference to + * that RealtimeObject is returned, provided it exists in the local pool and is not tombstoned. Otherwise, null is returned. * If the value is not an objectId, then that value is returned. * Spec: RTLM5, RTLM5a * diff --git a/lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java b/lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java index 5d753cd5c..08fe2fc39 100644 --- a/lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java +++ b/lib/src/main/java/io/ably/lib/objects/type/map/LiveMapUpdate.java @@ -1,6 +1,6 @@ package io.ably.lib.objects.type.map; -import io.ably.lib.objects.type.LiveObjectUpdate; +import io.ably.lib.objects.type.ObjectUpdate; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -11,7 +11,7 @@ * * @spec RTLM18, RTLM18a - LiveMap update structure and behavior */ -public class LiveMapUpdate extends LiveObjectUpdate { +public class LiveMapUpdate extends ObjectUpdate { /** * Creates a no-op LiveMapUpdate representing no actual change. diff --git a/lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java b/lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java index 8c0d9ee03..7cc4480f2 100644 --- a/lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java +++ b/lib/src/main/java/io/ably/lib/realtime/AblyRealtime.java @@ -5,8 +5,8 @@ import java.util.List; import java.util.Map; -import io.ably.lib.objects.LiveObjectsHelper; -import io.ably.lib.objects.LiveObjectsPlugin; +import io.ably.lib.objects.ObjectsHelper; +import io.ably.lib.objects.ObjectsPlugin; import io.ably.lib.rest.AblyRest; import io.ably.lib.rest.Auth; import io.ably.lib.transport.ConnectionManager; @@ -20,6 +20,7 @@ import io.ably.lib.util.InternalMap; import io.ably.lib.util.Log; import io.ably.lib.util.StringUtils; +import org.jetbrains.annotations.Nullable; /** * A client that extends the functionality of the {@link AblyRest} and provides additional realtime-specific features. @@ -47,7 +48,8 @@ public class AblyRealtime extends AblyRest { *

* This field is initialized only if the LiveObjects plugin is present in the classpath. */ - private final LiveObjectsPlugin liveObjectsPlugin; + @Nullable + private final ObjectsPlugin objectsPlugin; /** * Constructs a Realtime client object using an Ably API key or token string. @@ -72,9 +74,9 @@ public AblyRealtime(ClientOptions options) throws AblyException { final InternalChannels channels = new InternalChannels(); this.channels = channels; - liveObjectsPlugin = LiveObjectsHelper.tryInitializeLiveObjectsPlugin(this); + objectsPlugin = ObjectsHelper.tryInitializeObjectsPlugin(this); - connection = new Connection(this, channels, platformAgentProvider, liveObjectsPlugin); + connection = new Connection(this, channels, platformAgentProvider, objectsPlugin); if (!StringUtils.isNullOrEmpty(options.recover)) { RecoveryKeyContext recoveryKeyContext = RecoveryKeyContext.decode(options.recover); @@ -120,8 +122,8 @@ public void close() { } connection.close(); - if (liveObjectsPlugin != null) { - liveObjectsPlugin.dispose(); + if (objectsPlugin != null) { + objectsPlugin.dispose(); } } @@ -202,7 +204,7 @@ public Channel get(final String channelName, final ChannelOptions channelOptions // We're not using computeIfAbsent because that requires Java 1.8. // Hence there's the slight inefficiency of creating newChannel when it may not be // needed because there is an existingChannel. - final Channel newChannel = new Channel(AblyRealtime.this, channelName, channelOptions, liveObjectsPlugin); + final Channel newChannel = new Channel(AblyRealtime.this, channelName, channelOptions, objectsPlugin); final Channel existingChannel = map.putIfAbsent(channelName, newChannel); if (existingChannel != null) { @@ -229,8 +231,8 @@ public void release(String channelName) { Log.e(TAG, "Unexpected exception detaching channel; channelName = " + channelName, e); } } - if (liveObjectsPlugin != null) { - liveObjectsPlugin.dispose(channelName); + if (objectsPlugin != null) { + objectsPlugin.dispose(channelName); } } diff --git a/lib/src/main/java/io/ably/lib/realtime/ChannelBase.java b/lib/src/main/java/io/ably/lib/realtime/ChannelBase.java index 6ac064d56..587a13fab 100644 --- a/lib/src/main/java/io/ably/lib/realtime/ChannelBase.java +++ b/lib/src/main/java/io/ably/lib/realtime/ChannelBase.java @@ -13,8 +13,8 @@ import io.ably.lib.http.Http; import io.ably.lib.http.HttpCore; import io.ably.lib.http.HttpUtils; -import io.ably.lib.objects.LiveObjects; -import io.ably.lib.objects.LiveObjectsPlugin; +import io.ably.lib.objects.RealtimeObjects; +import io.ably.lib.objects.ObjectsPlugin; import io.ably.lib.rest.RestAnnotations; import io.ably.lib.transport.ConnectionManager; import io.ably.lib.transport.ConnectionManager.QueuedMessage; @@ -43,6 +43,7 @@ import io.ably.lib.util.Log; import io.ably.lib.util.ReconnectionStrategy; import io.ably.lib.util.StringUtils; +import org.jetbrains.annotations.Nullable; /** * Enables messages to be published and subscribed to. @@ -94,16 +95,16 @@ public abstract class ChannelBase extends EventEmitter') to your dependency tree", 400, 40019) ); } - return liveObjectsPlugin.getInstance(name); + return objectsPlugin.getInstance(name); } public final RealtimeAnnotations annotations; @@ -146,11 +147,11 @@ private void setState(ChannelState newState, ErrorInfo reason, boolean resumed, } // cover states other than attached, ChannelState.attached already covered in setAttached - if (liveObjectsPlugin != null && newState!= ChannelState.attached) { + if (objectsPlugin != null && newState!= ChannelState.attached) { try { - liveObjectsPlugin.handleStateChange(name, newState, false); + objectsPlugin.handleStateChange(name, newState, false); } catch (Throwable t) { - Log.e(TAG, "Unexpected exception in LiveObjectsPlugin.handle", t); + Log.e(TAG, "Unexpected exception in objectsPlugin.handle", t); } } @@ -448,11 +449,11 @@ private void setAttached(ProtocolMessage message) { } return; } - if (liveObjectsPlugin != null) { + if (objectsPlugin != null) { try { - liveObjectsPlugin.handleStateChange(name, ChannelState.attached, message.hasFlag(Flag.has_objects)); + objectsPlugin.handleStateChange(name, ChannelState.attached, message.hasFlag(Flag.has_objects)); } catch (Throwable t) { - Log.e(TAG, "Unexpected exception in LiveObjectsPlugin.handle", t); + Log.e(TAG, "Unexpected exception in objectsPlugin.handle", t); } } if(state == ChannelState.attached) { @@ -1325,7 +1326,7 @@ else if(stateChange.current.equals(failureState)) { } } - ChannelBase(AblyRealtime ably, String name, ChannelOptions options, LiveObjectsPlugin liveObjectsPlugin) throws AblyException { + ChannelBase(AblyRealtime ably, String name, ChannelOptions options, @Nullable ObjectsPlugin objectsPlugin) throws AblyException { Log.v(TAG, "RealtimeChannel(); channel = " + name); this.ably = ably; this.name = name; @@ -1335,9 +1336,9 @@ else if(stateChange.current.equals(failureState)) { this.attachResume = false; state = ChannelState.initialized; this.decodingContext = new DecodingContext(); - this.liveObjectsPlugin = liveObjectsPlugin; - if (liveObjectsPlugin != null) { - liveObjectsPlugin.getInstance(name); // Make objects instance ready to process sync messages + this.objectsPlugin = objectsPlugin; + if (objectsPlugin != null) { + objectsPlugin.getInstance(name); // Make objects instance ready to process sync messages } this.annotations = new RealtimeAnnotations( this, diff --git a/lib/src/main/java/io/ably/lib/realtime/Connection.java b/lib/src/main/java/io/ably/lib/realtime/Connection.java index 3ba28a434..00aa83624 100644 --- a/lib/src/main/java/io/ably/lib/realtime/Connection.java +++ b/lib/src/main/java/io/ably/lib/realtime/Connection.java @@ -1,6 +1,6 @@ package io.ably.lib.realtime; -import io.ably.lib.objects.LiveObjectsPlugin; +import io.ably.lib.objects.ObjectsPlugin; import io.ably.lib.realtime.ConnectionStateListener.ConnectionStateChange; import io.ably.lib.transport.ConnectionManager; import io.ably.lib.types.AblyException; @@ -123,10 +123,10 @@ public void close() { * internal *****************/ - Connection(AblyRealtime ably, ConnectionManager.Channels channels, PlatformAgentProvider platformAgentProvider, LiveObjectsPlugin liveObjectsPlugin) throws AblyException { + Connection(AblyRealtime ably, ConnectionManager.Channels channels, PlatformAgentProvider platformAgentProvider, ObjectsPlugin objectsPlugin) throws AblyException { this.ably = ably; this.state = ConnectionState.initialized; - this.connectionManager = new ConnectionManager(ably, this, channels, platformAgentProvider, liveObjectsPlugin); + this.connectionManager = new ConnectionManager(ably, this, channels, platformAgentProvider, objectsPlugin); } public void onConnectionStateChange(ConnectionStateChange stateChange) { diff --git a/lib/src/main/java/io/ably/lib/transport/ConnectionManager.java b/lib/src/main/java/io/ably/lib/transport/ConnectionManager.java index 993459e4f..5e5638fb1 100644 --- a/lib/src/main/java/io/ably/lib/transport/ConnectionManager.java +++ b/lib/src/main/java/io/ably/lib/transport/ConnectionManager.java @@ -14,7 +14,7 @@ import io.ably.lib.debug.DebugOptions; import io.ably.lib.debug.DebugOptions.RawProtocolListener; import io.ably.lib.http.HttpHelpers; -import io.ably.lib.objects.LiveObjectsPlugin; +import io.ably.lib.objects.ObjectsPlugin; import io.ably.lib.realtime.AblyRealtime; import io.ably.lib.realtime.Channel; import io.ably.lib.realtime.ChannelState; @@ -99,7 +99,7 @@ public class ConnectionManager implements ConnectListener { *

* This field is initialized only if the LiveObjects plugin is present in the classpath. */ - private final LiveObjectsPlugin liveObjectsPlugin; + private final ObjectsPlugin objectsPlugin; /** * Methods on the channels map owned by the {@link AblyRealtime} instance @@ -773,12 +773,12 @@ public void run() { * ConnectionManager ***********************/ - public ConnectionManager(final AblyRealtime ably, final Connection connection, final Channels channels, final PlatformAgentProvider platformAgentProvider, LiveObjectsPlugin liveObjectsPlugin) throws AblyException { + public ConnectionManager(final AblyRealtime ably, final Connection connection, final Channels channels, final PlatformAgentProvider platformAgentProvider, ObjectsPlugin objectsPlugin) throws AblyException { this.ably = ably; this.connection = connection; this.channels = channels; this.platformAgentProvider = platformAgentProvider; - this.liveObjectsPlugin = liveObjectsPlugin; + this.objectsPlugin = objectsPlugin; ClientOptions options = ably.options; this.hosts = new Hosts(options.realtimeHost, Defaults.HOST_REALTIME, options); @@ -1239,11 +1239,11 @@ public void onMessage(ITransport transport, ProtocolMessage message) throws Ably break; case object: case object_sync: - if (liveObjectsPlugin != null) { + if (objectsPlugin != null) { try { - liveObjectsPlugin.handle(message); + objectsPlugin.handle(message); } catch (Throwable t) { - Log.e(TAG, "LiveObjectsPlugin threw while handling message", t); + Log.e(TAG, "objectsPlugin threw while handling message", t); } } break; diff --git a/lib/src/main/java/io/ably/lib/types/ProtocolMessage.java b/lib/src/main/java/io/ably/lib/types/ProtocolMessage.java index efcd32519..0548e4c64 100644 --- a/lib/src/main/java/io/ably/lib/types/ProtocolMessage.java +++ b/lib/src/main/java/io/ably/lib/types/ProtocolMessage.java @@ -5,9 +5,9 @@ import java.util.Map; import com.google.gson.annotations.JsonAdapter; -import io.ably.lib.objects.LiveObjectSerializer; -import io.ably.lib.objects.LiveObjectsHelper; -import io.ably.lib.objects.LiveObjectsJsonSerializer; +import io.ably.lib.objects.ObjectsSerializer; +import io.ably.lib.objects.ObjectsHelper; +import io.ably.lib.objects.ObjectsJsonSerializer; import org.jetbrains.annotations.Nullable; import org.msgpack.core.MessageFormat; import org.msgpack.core.MessagePacker; @@ -134,7 +134,7 @@ public ProtocolMessage(Action action, String channel) { * This is targeted and specific to the state field, so won't affect other fields */ @Nullable - @JsonAdapter(LiveObjectsJsonSerializer.class) + @JsonAdapter(ObjectsJsonSerializer.class) public Object[] state; public boolean hasFlag(final Flag flag) { @@ -160,7 +160,7 @@ void writeMsgpack(MessagePacker packer) throws IOException { if(params != null) ++fieldCount; if(channelSerial != null) ++fieldCount; if(annotations != null) ++fieldCount; - if(state != null && LiveObjectsHelper.getLiveObjectSerializer() != null) ++fieldCount; + if(state != null && ObjectsHelper.getSerializer() != null) ++fieldCount; packer.packMapHeader(fieldCount); packer.packString("action"); packer.packInt(action.getValue()); @@ -201,12 +201,12 @@ void writeMsgpack(MessagePacker packer) throws IOException { AnnotationSerializer.writeMsgpackArray(annotations, packer); } if(state != null) { - LiveObjectSerializer liveObjectsSerializer = LiveObjectsHelper.getLiveObjectSerializer(); - if (liveObjectsSerializer != null) { + ObjectsSerializer objectsSerializer = ObjectsHelper.getSerializer(); + if (objectsSerializer != null) { packer.packString("state"); - liveObjectsSerializer.writeMsgpackArray(state, packer); + objectsSerializer.writeMsgpackArray(state, packer); } else { - Log.w(TAG, "Skipping 'state' field msgpack serialization because LiveObjectsSerializer not found"); + Log.w(TAG, "Skipping 'state' field msgpack serialization because ObjectsSerializer not found"); } } } @@ -272,11 +272,11 @@ ProtocolMessage readMsgpack(MessageUnpacker unpacker) throws IOException { annotations = AnnotationSerializer.readMsgpackArray(unpacker); break; case "state": - LiveObjectSerializer liveObjectsSerializer = LiveObjectsHelper.getLiveObjectSerializer(); - if (liveObjectsSerializer != null) { - state = liveObjectsSerializer.readMsgpackArray(unpacker); + ObjectsSerializer objectsSerializer = ObjectsHelper.getSerializer(); + if (objectsSerializer != null) { + state = objectsSerializer.readMsgpackArray(unpacker); } else { - Log.w(TAG, "Skipping 'state' field msgpack deserialization because LiveObjectsSerializer not found"); + Log.w(TAG, "Skipping 'state' field msgpack deserialization because ObjectsSerializer not found"); unpacker.skipValue(); } break; diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt deleted file mode 100644 index 66cab1d30..000000000 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjectsPlugin.kt +++ /dev/null @@ -1,35 +0,0 @@ -package io.ably.lib.objects - -import io.ably.lib.realtime.ChannelState -import io.ably.lib.types.ProtocolMessage -import java.util.concurrent.ConcurrentHashMap - -public class DefaultLiveObjectsPlugin(private val adapter: LiveObjectsAdapter) : LiveObjectsPlugin { - - private val liveObjects = ConcurrentHashMap() - - override fun getInstance(channelName: String): LiveObjects { - return liveObjects.getOrPut(channelName) { DefaultLiveObjects(channelName, adapter) } - } - - override fun handle(msg: ProtocolMessage) { - val channelName = msg.channel - liveObjects[channelName]?.handle(msg) - } - - override fun handleStateChange(channelName: String, state: ChannelState, hasObjects: Boolean) { - liveObjects[channelName]?.handleStateChange(state, hasObjects) - } - - override fun dispose(channelName: String) { - liveObjects[channelName]?.dispose(clientError("Channel has been released using channels.release()")) - liveObjects.remove(channelName) - } - - override fun dispose() { - liveObjects.values.forEach { - it.dispose(clientError("AblyClient has been closed using client.close()")) - } - liveObjects.clear() - } -} diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultObjectsPlugin.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultObjectsPlugin.kt new file mode 100644 index 000000000..856c15a59 --- /dev/null +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultObjectsPlugin.kt @@ -0,0 +1,35 @@ +package io.ably.lib.objects + +import io.ably.lib.realtime.ChannelState +import io.ably.lib.types.ProtocolMessage +import java.util.concurrent.ConcurrentHashMap + +public class DefaultObjectsPlugin(private val adapter: ObjectsAdapter) : ObjectsPlugin { + + private val objects = ConcurrentHashMap() + + override fun getInstance(channelName: String): RealtimeObjects { + return objects.getOrPut(channelName) { DefaultRealtimeObjects(channelName, adapter) } + } + + override fun handle(msg: ProtocolMessage) { + val channelName = msg.channel + objects[channelName]?.handle(msg) + } + + override fun handleStateChange(channelName: String, state: ChannelState, hasObjects: Boolean) { + objects[channelName]?.handleStateChange(state, hasObjects) + } + + override fun dispose(channelName: String) { + objects.remove(channelName) + ?.dispose(clientError("Channel has been released using channels.release()")) + } + + override fun dispose() { + objects.values.forEach { + it.dispose(clientError("AblyClient has been closed using client.close()")) + } + objects.clear() + } +} diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultRealtimeObjects.kt similarity index 96% rename from live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt rename to live-objects/src/main/kotlin/io/ably/lib/objects/DefaultRealtimeObjects.kt index f6c740721..0b00a1680 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultLiveObjects.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/DefaultRealtimeObjects.kt @@ -19,11 +19,11 @@ import kotlinx.coroutines.flow.MutableSharedFlow import java.util.concurrent.CancellationException /** - * Default implementation of LiveObjects interface. + * Default implementation of RealtimeObjects interface. * Provides the core functionality for managing live objects on a channel. */ -internal class DefaultLiveObjects(internal val channelName: String, internal val adapter: LiveObjectsAdapter): LiveObjects { - private val tag = "DefaultLiveObjects" +internal class DefaultRealtimeObjects(internal val channelName: String, internal val adapter: ObjectsAdapter): RealtimeObjects { + private val tag = "DefaultRealtimeObjects" /** * @spec RTO3 - Objects pool storing all live objects by object ID */ @@ -252,7 +252,7 @@ internal class DefaultLiveObjects(internal val channelName: String, internal val Log.v(tag, "Objects.onAttached() channel=$channelName, hasObjects=$hasObjects") // RTO4a - val fromInitializedState = this@DefaultLiveObjects.state == ObjectsState.Initialized + val fromInitializedState = this@DefaultRealtimeObjects.state == ObjectsState.Initialized if (hasObjects || fromInitializedState) { // should always start a new sync sequence if we're in the initialized state, no matter the HAS_OBJECTS flag value. // this guarantees we emit both "syncing" -> "synced" events in that order. @@ -285,7 +285,7 @@ internal class DefaultLiveObjects(internal val channelName: String, internal val } } - // Dispose of any resources associated with this LiveObjects instance + // Dispose of any resources associated with this RealtimeObjects instance fun dispose(cause: AblyException) { val disposeReason = CancellationException().apply { initCause(cause) } incomingObjectsHandler.cancel(disposeReason) // objectsEventBus automatically garbage collected when collector is cancelled diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt index d0f0e94a9..7b169ff8f 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/Helpers.kt @@ -13,7 +13,7 @@ import kotlin.coroutines.resumeWithException /** * Spec: RTO15g */ -internal suspend fun LiveObjectsAdapter.sendAsync(message: ProtocolMessage) = suspendCancellableCoroutine { continuation -> +internal suspend fun ObjectsAdapter.sendAsync(message: ProtocolMessage) = suspendCancellableCoroutine { continuation -> try { connectionManager.send(message, clientOptions.queueMessages, object : CompletionListener { override fun onSuccess() { @@ -29,7 +29,7 @@ internal suspend fun LiveObjectsAdapter.sendAsync(message: ProtocolMessage) = su } } -internal suspend fun LiveObjectsAdapter.attachAsync(channelName: String) = suspendCancellableCoroutine { continuation -> +internal suspend fun ObjectsAdapter.attachAsync(channelName: String) = suspendCancellableCoroutine { continuation -> try { getChannel(channelName).attach(object : CompletionListener { override fun onSuccess() { @@ -53,7 +53,7 @@ internal suspend fun LiveObjectsAdapter.attachAsync(channelName: String) = suspe * @return the array of channel modes for the specified channel, or null if the channel is not found * Spec: RTO2a, RTO2b */ -internal fun LiveObjectsAdapter.getChannelModes(channelName: String): Array? { +internal fun ObjectsAdapter.getChannelModes(channelName: String): Array? { val channel = getChannel(channelName) // RTO2a - channel.modes is only populated on channel attachment, so use it only if it is set @@ -75,7 +75,7 @@ internal fun LiveObjectsAdapter.getChannelModes(channelName: String): Array) { +internal fun ObjectsAdapter.ensureMessageSizeWithinLimit(objectMessages: Array) { val maximumAllowedSize = connectionManager.maxMessageSize val objectsTotalMessageSize = objectMessages.sumOf { it.size() } if (objectsTotalMessageSize > maximumAllowedSize) { @@ -84,14 +84,14 @@ internal fun LiveObjectsAdapter.ensureMessageSizeWithinLimit(objectMessages: Arr } } -internal fun LiveObjectsAdapter.setChannelSerial(channelName: String, protocolMessage: ProtocolMessage) { +internal fun ObjectsAdapter.setChannelSerial(channelName: String, protocolMessage: ProtocolMessage) { if (protocolMessage.action != ProtocolMessage.Action.`object`) return val channelSerial = protocolMessage.channelSerial if (channelSerial.isNullOrEmpty()) return getChannel(channelName).properties.channelSerial = channelSerial } -internal suspend fun LiveObjectsAdapter.ensureAttached(channelName: String) { +internal suspend fun ObjectsAdapter.ensureAttached(channelName: String) { val channel = getChannel(channelName) when (val currentChannelStatus = channel.state) { ChannelState.initialized -> attachAsync(channelName) @@ -119,18 +119,18 @@ internal suspend fun LiveObjectsAdapter.ensureAttached(channelName: String) { } // Spec: RTLO4b1, RTLO4b2 -internal fun LiveObjectsAdapter.throwIfInvalidAccessApiConfiguration(channelName: String) { +internal fun ObjectsAdapter.throwIfInvalidAccessApiConfiguration(channelName: String) { throwIfInChannelState(channelName, arrayOf(ChannelState.detached, ChannelState.failed)) throwIfMissingChannelMode(channelName, ChannelMode.object_subscribe) } -internal fun LiveObjectsAdapter.throwIfInvalidWriteApiConfiguration(channelName: String) { +internal fun ObjectsAdapter.throwIfInvalidWriteApiConfiguration(channelName: String) { throwIfEchoMessagesDisabled() throwIfInChannelState(channelName, arrayOf(ChannelState.detached, ChannelState.failed, ChannelState.suspended)) throwIfMissingChannelMode(channelName, ChannelMode.object_publish) } -internal fun LiveObjectsAdapter.throwIfUnpublishableState(channelName: String) { +internal fun ObjectsAdapter.throwIfUnpublishableState(channelName: String) { if (!connectionManager.isActive) { throw ablyException(connectionManager.stateErrorInfo) } @@ -138,7 +138,7 @@ internal fun LiveObjectsAdapter.throwIfUnpublishableState(channelName: String) { } // Spec: RTO2 -private fun LiveObjectsAdapter.throwIfMissingChannelMode(channelName: String, channelMode: ChannelMode) { +private fun ObjectsAdapter.throwIfMissingChannelMode(channelName: String, channelMode: ChannelMode) { val channelModes = getChannelModes(channelName) if (channelModes == null || !channelModes.contains(channelMode)) { // Spec: RTO2a2, RTO2b2 @@ -146,14 +146,14 @@ private fun LiveObjectsAdapter.throwIfMissingChannelMode(channelName: String, ch } } -private fun LiveObjectsAdapter.throwIfInChannelState(channelName: String, channelStates: Array) { +private fun ObjectsAdapter.throwIfInChannelState(channelName: String, channelStates: Array) { val currentState = getChannel(channelName).state if (currentState == null || channelStates.contains(currentState)) { throw ablyException("Channel is in invalid state: $currentState", ErrorCode.ChannelStateError) } } -internal fun LiveObjectsAdapter.throwIfEchoMessagesDisabled() { +internal fun ObjectsAdapter.throwIfEchoMessagesDisabled() { if (!clientOptions.echoMessages) { throw clientError("\"echoMessages\" client option must be enabled for this operation") } @@ -176,9 +176,9 @@ internal fun Binary.size(): Int { } internal data class CounterCreatePayload( - val counter: ObjectCounter + val counter: ObjectsCounter ) internal data class MapCreatePayload( - val map: ObjectMap + val map: ObjectsMap ) diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt index 497ec8e19..0415cc8d5 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectMessage.kt @@ -25,7 +25,7 @@ internal enum class ObjectOperationAction(val code: Int) { * An enum class representing the conflict-resolution semantics used by a Map object. * Spec: OMP2 */ -internal enum class MapSemantics(val code: Int) { +internal enum class ObjectsMapSemantics(val code: Int) { LWW(0), Unknown(-1); // code for unknown value during deserialization } @@ -69,7 +69,7 @@ internal sealed class ObjectValue { * A MapOp describes an operation to be applied to a Map object. * Spec: OMO1 */ -internal data class ObjectMapOp( +internal data class ObjectsMapOp( /** * The key of the map entry to which the operation should be applied. * Spec: OMO2a @@ -87,7 +87,7 @@ internal data class ObjectMapOp( * A CounterOp describes an operation to be applied to a Counter object. * Spec: OCO1 */ -internal data class ObjectCounterOp( +internal data class ObjectsCounterOp( /** * The data value that should be added to the counter * Spec: OCO2a @@ -99,7 +99,7 @@ internal data class ObjectCounterOp( * A MapEntry represents the value at a given key in a Map object. * Spec: ME1 */ -internal data class ObjectMapEntry( +internal data class ObjectsMapEntry( /** * Indicates whether the map entry has been removed. * Spec: OME2a @@ -131,25 +131,25 @@ internal data class ObjectMapEntry( * An ObjectMap object represents a map of key-value pairs. * Spec: OMP1 */ -internal data class ObjectMap( +internal data class ObjectsMap( /** * The conflict-resolution semantics used by the map object. * Spec: OMP3a */ - val semantics: MapSemantics? = null, + val semantics: ObjectsMapSemantics? = null, /** * The map entries, indexed by key. * Spec: OMP3b */ - val entries: Map? = null + val entries: Map? = null ) /** * An ObjectCounter object represents an incrementable and decrementable value * Spec: OCN1 */ -internal data class ObjectCounter( +internal data class ObjectsCounter( /** * The value of the counter * Spec: OCN2a @@ -179,28 +179,28 @@ internal data class ObjectOperation( * i.e. MAP_SET, MAP_REMOVE. * Spec: OOP3c */ - val mapOp: ObjectMapOp? = null, + val mapOp: ObjectsMapOp? = null, /** * The payload for the operation if it is an operation on a Counter object type. * i.e. COUNTER_INC. * Spec: OOP3d */ - val counterOp: ObjectCounterOp? = null, + val counterOp: ObjectsCounterOp? = null, /** * The payload for the operation if the operation is MAP_CREATE. * Defines the initial value for the Map object. * Spec: OOP3e */ - val map: ObjectMap? = null, + val map: ObjectsMap? = null, /** * The payload for the operation if the operation is COUNTER_CREATE. * Defines the initial value for the Counter object. * Spec: OOP3f */ - val counter: ObjectCounter? = null, + val counter: ObjectsCounter? = null, /** * The nonce, must be present on create operations. This is the random part @@ -255,14 +255,14 @@ internal data class ObjectState( * excluding the initial value from the create operation if it is a Map object type. * Spec: OST2e */ - val map: ObjectMap? = null, + val map: ObjectsMap? = null, /** * The data that represents the result of applying all operations to a Counter object * excluding the initial value from the create operation if it is a Counter object type. * Spec: OST2f */ - val counter: ObjectCounter? = null + val counter: ObjectsCounter? = null ) /** @@ -386,7 +386,7 @@ private fun ObjectState.size(): Int { * Calculates the size of an ObjectMapOp in bytes. * Spec: OMO3 */ -private fun ObjectMapOp.size(): Int { +private fun ObjectsMapOp.size(): Int { val keySize = key.length // Spec: OMO3d - Size of the key val dataSize = data?.size() ?: 0 // Spec: OMO3b - Size of the data, calculated per "OD3" return keySize + dataSize @@ -396,7 +396,7 @@ private fun ObjectMapOp.size(): Int { * Calculates the size of a CounterOp in bytes. * Spec: OCO3 */ -private fun ObjectCounterOp.size(): Int { +private fun ObjectsCounterOp.size(): Int { // Size is 8 if amount is a number, 0 if amount is null or omitted return if (amount != null) 8 else 0 // Spec: OCO3a, OCO3b } @@ -405,7 +405,7 @@ private fun ObjectCounterOp.size(): Int { * Calculates the size of an ObjectMap in bytes. * Spec: OMP4 */ -private fun ObjectMap.size(): Int { +private fun ObjectsMap.size(): Int { // Calculate the size of all map entries in the map property val entriesSize = entries?.entries?.sumOf { it.key.length + it.value.size() // // Spec: OMP4a1, OMP4a2 @@ -418,7 +418,7 @@ private fun ObjectMap.size(): Int { * Calculates the size of an ObjectCounter in bytes. * Spec: OCN3 */ -private fun ObjectCounter.size(): Int { +private fun ObjectsCounter.size(): Int { // Size is 8 if count is a number, 0 if count is null or omitted return if (count != null) 8 else 0 } @@ -427,7 +427,7 @@ private fun ObjectCounter.size(): Int { * Calculates the size of a MapEntry in bytes. * Spec: OME3 */ -private fun ObjectMapEntry.size(): Int { +private fun ObjectsMapEntry.size(): Int { // The size is equal to the size of the data property, calculated per "OD3" return data?.size() ?: 0 } diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt index 51b184ae6..2132c84e9 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsManager.kt @@ -1,7 +1,7 @@ package io.ably.lib.objects -import io.ably.lib.objects.type.BaseLiveObject -import io.ably.lib.objects.type.LiveObjectUpdate +import io.ably.lib.objects.type.BaseRealtimeObject +import io.ably.lib.objects.type.ObjectUpdate import io.ably.lib.objects.type.livecounter.DefaultLiveCounter import io.ably.lib.objects.type.livemap.DefaultLiveMap import io.ably.lib.util.Log @@ -10,7 +10,7 @@ import io.ably.lib.util.Log * @spec RTO5 - Processes OBJECT and OBJECT_SYNC messages during sync sequences * @spec RTO6 - Creates zero-value objects when needed */ -internal class ObjectsManager(private val liveObjects: DefaultLiveObjects): ObjectsStateCoordinator() { +internal class ObjectsManager(private val realtimeObjects: DefaultRealtimeObjects): ObjectsStateCoordinator() { private val tag = "ObjectsManager" /** * @spec RTO5 - Sync objects data pool for collecting sync messages @@ -28,12 +28,12 @@ internal class ObjectsManager(private val liveObjects: DefaultLiveObjects): Obje * @spec RTO8 - Buffers messages if not synced, applies immediately if synced */ internal fun handleObjectMessages(objectMessages: List) { - if (liveObjects.state != ObjectsState.Synced) { + if (realtimeObjects.state != ObjectsState.Synced) { // RTO7 - The client receives object messages in realtime over the channel concurrently with the sync sequence. // Some of the incoming object messages may have already been applied to the objects described in // the sync sequence, but others may not; therefore we must buffer these messages so that we can apply // them to the objects once the sync is complete. - Log.v(tag, "Buffering ${objectMessages.size} object messages, state: $liveObjects.state") + Log.v(tag, "Buffering ${objectMessages.size} object messages, state: ${realtimeObjects.state}") bufferedObjectOperations.addAll(objectMessages) // RTO8a return } @@ -101,7 +101,7 @@ internal class ObjectsManager(private val liveObjects: DefaultLiveObjects): Obje /** * Clears the sync objects data pool. - * Used by DefaultLiveObjects.handleStateChange. + * Used by DefaultRealtimeObjects.handleStateChange. */ internal fun clearSyncObjectsDataPool() { syncObjectsDataPool.clear() @@ -109,7 +109,7 @@ internal class ObjectsManager(private val liveObjects: DefaultLiveObjects): Obje /** * Clears the buffered object operations. - * Used by DefaultLiveObjects.handleStateChange. + * Used by DefaultRealtimeObjects.handleStateChange. */ internal fun clearBufferedObjectOperations() { bufferedObjectOperations.clear() @@ -127,13 +127,13 @@ internal class ObjectsManager(private val liveObjects: DefaultLiveObjects): Obje val receivedObjectIds = mutableSetOf() // RTO5c1a2 - List to collect updates for existing objects - val existingObjectUpdates = mutableListOf>() + val existingObjectUpdates = mutableListOf>() // RTO5c1 for ((objectId, objectMessage) in syncObjectsDataPool) { val objectState = objectMessage.objectState as ObjectState // we have non-null objectState here due to RTO5b receivedObjectIds.add(objectId) - val existingObject = liveObjects.objectsPool.get(objectId) + val existingObject = realtimeObjects.objectsPool.get(objectId) // RTO5c1a if (existingObject != null) { @@ -144,12 +144,12 @@ internal class ObjectsManager(private val liveObjects: DefaultLiveObjects): Obje // RTO5c1b1, RTO5c1b1a, RTO5c1b1b - Create new object and add it to the pool val newObject = createObjectFromState(objectState) newObject.applyObjectSync(objectMessage) - liveObjects.objectsPool.set(objectId, newObject) + realtimeObjects.objectsPool.set(objectId, newObject) } } - // RTO5c2 - need to remove LiveObject instances from the ObjectsPool for which objectIds were not received during the sync sequence - liveObjects.objectsPool.deleteExtraObjectIds(receivedObjectIds) + // RTO5c2 - need to remove realtimeObject instances from the ObjectsPool for which objectIds were not received during the sync sequence + realtimeObjects.objectsPool.deleteExtraObjectIds(receivedObjectIds) // RTO5c7 - call subscription callbacks for all updated existing objects existingObjectUpdates.forEach { (obj, update) -> @@ -183,7 +183,7 @@ internal class ObjectsManager(private val liveObjects: DefaultLiveObjects): Obje // since they need to be able to eventually initialize themselves from that *_CREATE op. // so to simplify operations handling, we always try to create a zero-value object in the pool first, // and then we can always apply the operation on the existing object in the pool. - val obj = liveObjects.objectsPool.createZeroValueObjectIfNotExists(objectOperation.objectId) // RTO9a2a1 + val obj = realtimeObjects.objectsPool.createZeroValueObjectIfNotExists(objectOperation.objectId) // RTO9a2a1 obj.applyObject(objectMessage) // RTO9a2a2, RTO9a2a3 } } @@ -215,10 +215,10 @@ internal class ObjectsManager(private val liveObjects: DefaultLiveObjects): Obje * * @spec RTO5c1b - Creates objects from object state based on type */ - private fun createObjectFromState(objectState: ObjectState): BaseLiveObject { + private fun createObjectFromState(objectState: ObjectState): BaseRealtimeObject { return when { - objectState.counter != null -> DefaultLiveCounter.zeroValue(objectState.objectId, liveObjects) // RTO5c1b1a - objectState.map != null -> DefaultLiveMap.zeroValue(objectState.objectId, liveObjects) // RTO5c1b1b + objectState.counter != null -> DefaultLiveCounter.zeroValue(objectState.objectId, realtimeObjects) // RTO5c1b1a + objectState.map != null -> DefaultLiveMap.zeroValue(objectState.objectId, realtimeObjects) // RTO5c1b1b else -> throw clientError("Object state must contain either counter or map data") // RTO5c1b1c } } @@ -229,11 +229,11 @@ internal class ObjectsManager(private val liveObjects: DefaultLiveObjects): Obje * @spec RTO2 - Emits state change events for syncing and synced states */ private fun stateChange(newState: ObjectsState, deferEvent: Boolean) { - if (liveObjects.state == newState) { + if (realtimeObjects.state == newState) { return } - Log.v(tag, "Objects state changed to: $newState from ${liveObjects.state}") - liveObjects.state = newState + Log.v(tag, "Objects state changed to: $newState from ${realtimeObjects.state}") + realtimeObjects.state = newState // deferEvent not needed since objectsStateChanged processes events in a sequential coroutine scope objectsStateChanged(newState) diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsPool.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsPool.kt index af822e948..a874d6dd6 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsPool.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsPool.kt @@ -1,6 +1,6 @@ package io.ably.lib.objects -import io.ably.lib.objects.type.BaseLiveObject +import io.ably.lib.objects.type.BaseRealtimeObject import io.ably.lib.objects.type.ObjectType import io.ably.lib.objects.type.livecounter.DefaultLiveCounter import io.ably.lib.objects.type.livemap.DefaultLiveMap @@ -33,7 +33,7 @@ internal const val ROOT_OBJECT_ID = "root" * @spec RTO3 - Maintains an objects pool for all live objects on the channel */ internal class ObjectsPool( - private val liveObjects: DefaultLiveObjects + private val realtimeObjects: DefaultRealtimeObjects ) { private val tag = "ObjectsPool" @@ -41,7 +41,7 @@ internal class ObjectsPool( * ConcurrentHashMap for thread-safe access from public APIs in LiveMap and LiveCounter. * @spec RTO3a - Pool storing all live objects by object ID */ - private val pool = ConcurrentHashMap() + private val pool = ConcurrentHashMap() /** * Coroutine scope for garbage collection @@ -51,7 +51,7 @@ internal class ObjectsPool( init { // RTO3b - Initialize pool with root object - pool[ROOT_OBJECT_ID] = DefaultLiveMap.zeroValue(ROOT_OBJECT_ID, liveObjects) + pool[ROOT_OBJECT_ID] = DefaultLiveMap.zeroValue(ROOT_OBJECT_ID, realtimeObjects) // Start garbage collection coroutine gcJob = startGCJob() } @@ -59,15 +59,15 @@ internal class ObjectsPool( /** * Gets a live object from the pool by object ID. */ - internal fun get(objectId: String): BaseLiveObject? { + internal fun get(objectId: String): BaseRealtimeObject? { return pool[objectId] } /** - * Sets a live object in the pool. + * Sets a realtime object in the pool. */ - internal fun set(objectId: String, liveObject: BaseLiveObject) { - pool[objectId] = liveObject + internal fun set(objectId: String, realtimeObject: BaseRealtimeObject) { + pool[objectId] = realtimeObject } /** @@ -103,7 +103,7 @@ internal class ObjectsPool( * * @spec RTO6 - Creates zero-value objects when needed */ - internal fun createZeroValueObjectIfNotExists(objectId: String): BaseLiveObject { + internal fun createZeroValueObjectIfNotExists(objectId: String): BaseRealtimeObject { val existingObject = get(objectId) if (existingObject != null) { return existingObject // RTO6a @@ -111,8 +111,8 @@ internal class ObjectsPool( val parsedObjectId = ObjectId.fromString(objectId) // RTO6b return when (parsedObjectId.type) { - ObjectType.Map -> DefaultLiveMap.zeroValue(objectId, liveObjects) // RTO6b2 - ObjectType.Counter -> DefaultLiveCounter.zeroValue(objectId, liveObjects) // RTO6b3 + ObjectType.Map -> DefaultLiveMap.zeroValue(objectId, realtimeObjects) // RTO6b2 + ObjectType.Counter -> DefaultLiveCounter.zeroValue(objectId, realtimeObjects) // RTO6b3 }.apply { set(objectId, this) // RTO6b4 - Add the zero-value object to the pool } diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsState.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsState.kt index 8ba280e3d..f56782613 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsState.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/ObjectsState.kt @@ -51,7 +51,7 @@ internal interface HandlesObjectsStateChange { /** * Disposes all registered state change listeners and cancels any pending operations. - * Should be called when the associated LiveObjects instance is no longer needed. + * Should be called when the associated RealtimeObjects instance is no longer needed. */ fun disposeObjectsStateListeners() } diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/ServerTime.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/ServerTime.kt index d8d4a8eb5..dfb1a12bc 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/ServerTime.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/ServerTime.kt @@ -20,7 +20,7 @@ internal object ServerTime { * Spec: RTO16a */ @Throws(AblyException::class) - internal suspend fun getCurrentTime(adapter: LiveObjectsAdapter): Long { + internal suspend fun getCurrentTime(adapter: ObjectsAdapter): Long { if (serverTimeOffset == null) { mutex.withLock { if (serverTimeOffset == null) { // Double-checked locking to ensure thread safety diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt index b675ea239..3e136163e 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/Utils.kt @@ -55,9 +55,9 @@ internal val String.byteSize: Int get() = this.toByteArray(StandardCharsets.UTF_8).size /** - * A channel-specific coroutine scope for executing callbacks asynchronously in the LiveObjects system. + * A channel-specific coroutine scope for executing callbacks asynchronously in the RealtimeObjects system. * Provides safe execution of suspend functions with results delivered via callbacks. - * Supports proper error handling and cancellation during LiveObjects disposal. + * Supports proper error handling and cancellation during DefaultRealtimeObjects disposal. */ internal class ObjectsAsyncScope(channelName: String) { private val tag = "ObjectsCallbackScope-$channelName" diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/DefaultSerialization.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/DefaultSerialization.kt index a712b3c7e..15c5fb587 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/DefaultSerialization.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/DefaultSerialization.kt @@ -10,12 +10,12 @@ import org.msgpack.core.MessagePacker import org.msgpack.core.MessageUnpacker /** - * Default implementation of {@link LiveObjectSerializer} that handles serialization/deserialization + * Default implementation of {@link ObjectsSerializer} that handles serialization/deserialization * of ObjectMessage arrays for both JSON and MessagePack formats using Jackson and Gson. - * Dynamically loaded by LiveObjectsHelper#getLiveObjectSerializer() to avoid hard dependencies. + * Dynamically loaded by ObjectsHelper#getSerializer() to avoid hard dependencies. */ -@Suppress("unused") // Used via reflection in LiveObjectsHelper -internal class DefaultLiveObjectSerializer : LiveObjectSerializer { +@Suppress("unused") // Used via reflection in ObjectsHelper +internal class DefaultObjectsSerializer : ObjectsSerializer { override fun readMsgpackArray(unpacker: MessageUnpacker): Array { val objectMessagesCount = unpacker.unpackArrayHeader() diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/JsonSerialization.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/JsonSerialization.kt index e10eb7847..e610ddc6d 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/JsonSerialization.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/JsonSerialization.kt @@ -2,7 +2,7 @@ package io.ably.lib.objects.serialization import com.google.gson.* import io.ably.lib.objects.Binary -import io.ably.lib.objects.MapSemantics +import io.ably.lib.objects.ObjectsMapSemantics import io.ably.lib.objects.ObjectData import io.ably.lib.objects.ObjectMessage import io.ably.lib.objects.ObjectOperationAction @@ -14,7 +14,7 @@ import kotlin.enums.EnumEntries // Gson instance for JSON serialization/deserialization internal val gson = GsonBuilder() .registerTypeAdapter(ObjectOperationAction::class.java, EnumCodeTypeAdapter({ it.code }, ObjectOperationAction.entries)) - .registerTypeAdapter(MapSemantics::class.java, EnumCodeTypeAdapter({ it.code }, MapSemantics.entries)) + .registerTypeAdapter(ObjectsMapSemantics::class.java, EnumCodeTypeAdapter({ it.code }, ObjectsMapSemantics.entries)) .create() internal fun ObjectMessage.toJsonObject(): JsonObject { diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/MsgpackSerialization.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/MsgpackSerialization.kt index b999286cd..797977a39 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/MsgpackSerialization.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/serialization/MsgpackSerialization.kt @@ -5,13 +5,13 @@ import com.google.gson.JsonParser import io.ably.lib.objects.* import io.ably.lib.objects.Binary import io.ably.lib.objects.ErrorCode -import io.ably.lib.objects.MapSemantics -import io.ably.lib.objects.ObjectCounter -import io.ably.lib.objects.ObjectCounterOp +import io.ably.lib.objects.ObjectsMapSemantics +import io.ably.lib.objects.ObjectsCounter +import io.ably.lib.objects.ObjectsCounterOp import io.ably.lib.objects.ObjectData -import io.ably.lib.objects.ObjectMap -import io.ably.lib.objects.ObjectMapEntry -import io.ably.lib.objects.ObjectMapOp +import io.ably.lib.objects.ObjectsMap +import io.ably.lib.objects.ObjectsMapEntry +import io.ably.lib.objects.ObjectsMapOp import io.ably.lib.objects.ObjectMessage import io.ably.lib.objects.ObjectOperation import io.ably.lib.objects.ObjectOperationAction @@ -157,7 +157,7 @@ internal fun readObjectMessage(unpacker: MessageUnpacker): ObjectMessage { */ private fun ObjectOperation.writeMsgpack(packer: MessagePacker) { var fieldCount = 1 // action is always required - require(objectId.isNotEmpty()) { "objectId must be non-empty per LiveObjects protocol" } + require(objectId.isNotEmpty()) { "objectId must be non-empty per Objects protocol" } fieldCount++ if (mapOp != null) fieldCount++ @@ -172,7 +172,7 @@ private fun ObjectOperation.writeMsgpack(packer: MessagePacker) { packer.packString("action") packer.packInt(action.code) - // Always include objectId as per LiveObjects protocol + // Always include objectId as per Objects protocol packer.packString("objectId") packer.packString(objectId) @@ -215,10 +215,10 @@ private fun readObjectOperation(unpacker: MessageUnpacker): ObjectOperation { var action: ObjectOperationAction? = null var objectId: String = "" - var mapOp: ObjectMapOp? = null - var counterOp: ObjectCounterOp? = null - var map: ObjectMap? = null - var counter: ObjectCounter? = null + var mapOp: ObjectsMapOp? = null + var counterOp: ObjectsCounterOp? = null + var map: ObjectsMap? = null + var counter: ObjectsCounter? = null var nonce: String? = null var initialValue: String? = null @@ -316,8 +316,8 @@ private fun readObjectState(unpacker: MessageUnpacker): ObjectState { var siteTimeserials = mapOf() var tombstone = false var createOp: ObjectOperation? = null - var map: ObjectMap? = null - var counter: ObjectCounter? = null + var map: ObjectsMap? = null + var counter: ObjectsCounter? = null for (i in 0 until fieldCount) { val fieldName = unpacker.unpackString().intern() @@ -361,7 +361,7 @@ private fun readObjectState(unpacker: MessageUnpacker): ObjectState { /** * Write ObjectMapOp to MessagePacker */ -private fun ObjectMapOp.writeMsgpack(packer: MessagePacker) { +private fun ObjectsMapOp.writeMsgpack(packer: MessagePacker) { var fieldCount = 1 // key is required if (data != null) fieldCount++ @@ -380,7 +380,7 @@ private fun ObjectMapOp.writeMsgpack(packer: MessagePacker) { /** * Read ObjectMapOp from MessageUnpacker */ -private fun readObjectMapOp(unpacker: MessageUnpacker): ObjectMapOp { +private fun readObjectMapOp(unpacker: MessageUnpacker): ObjectsMapOp { val fieldCount = unpacker.unpackMapHeader() var key = "" @@ -402,13 +402,13 @@ private fun readObjectMapOp(unpacker: MessageUnpacker): ObjectMapOp { } } - return ObjectMapOp(key = key, data = data) + return ObjectsMapOp(key = key, data = data) } /** * Write ObjectCounterOp to MessagePacker */ -private fun ObjectCounterOp.writeMsgpack(packer: MessagePacker) { +private fun ObjectsCounterOp.writeMsgpack(packer: MessagePacker) { var fieldCount = 0 if (amount != null) fieldCount++ @@ -424,7 +424,7 @@ private fun ObjectCounterOp.writeMsgpack(packer: MessagePacker) { /** * Read ObjectCounterOp from MessageUnpacker */ -private fun readObjectCounterOp(unpacker: MessageUnpacker): ObjectCounterOp { +private fun readObjectCounterOp(unpacker: MessageUnpacker): ObjectsCounterOp { val fieldCount = unpacker.unpackMapHeader() var amount: Double? = null @@ -444,13 +444,13 @@ private fun readObjectCounterOp(unpacker: MessageUnpacker): ObjectCounterOp { } } - return ObjectCounterOp(amount = amount) + return ObjectsCounterOp(amount = amount) } /** * Write ObjectMap to MessagePacker */ -private fun ObjectMap.writeMsgpack(packer: MessagePacker) { +private fun ObjectsMap.writeMsgpack(packer: MessagePacker) { var fieldCount = 0 if (semantics != null) fieldCount++ @@ -476,11 +476,11 @@ private fun ObjectMap.writeMsgpack(packer: MessagePacker) { /** * Read ObjectMap from MessageUnpacker */ -private fun readObjectMap(unpacker: MessageUnpacker): ObjectMap { +private fun readObjectMap(unpacker: MessageUnpacker): ObjectsMap { val fieldCount = unpacker.unpackMapHeader() - var semantics: MapSemantics? = null - var entries: Map? = null + var semantics: ObjectsMapSemantics? = null + var entries: Map? = null for (i in 0 until fieldCount) { val fieldName = unpacker.unpackString().intern() @@ -494,13 +494,13 @@ private fun readObjectMap(unpacker: MessageUnpacker): ObjectMap { when (fieldName) { "semantics" -> { val semanticsCode = unpacker.unpackInt() - semantics = MapSemantics.entries.firstOrNull { it.code == semanticsCode } - ?: MapSemantics.entries.firstOrNull { it.code == -1 } + semantics = ObjectsMapSemantics.entries.firstOrNull { it.code == semanticsCode } + ?: ObjectsMapSemantics.entries.firstOrNull { it.code == -1 } ?: throw objectError("Unknown MapSemantics code: $semanticsCode and no UNKNOWN fallback found") } "entries" -> { val mapSize = unpacker.unpackMapHeader() - val tempMap = mutableMapOf() + val tempMap = mutableMapOf() for (j in 0 until mapSize) { val key = unpacker.unpackString() val value = readObjectMapEntry(unpacker) @@ -512,13 +512,13 @@ private fun readObjectMap(unpacker: MessageUnpacker): ObjectMap { } } - return ObjectMap(semantics = semantics, entries = entries) + return ObjectsMap(semantics = semantics, entries = entries) } /** * Write ObjectCounter to MessagePacker */ -private fun ObjectCounter.writeMsgpack(packer: MessagePacker) { +private fun ObjectsCounter.writeMsgpack(packer: MessagePacker) { var fieldCount = 0 if (count != null) fieldCount++ @@ -534,7 +534,7 @@ private fun ObjectCounter.writeMsgpack(packer: MessagePacker) { /** * Read ObjectCounter from MessageUnpacker */ -private fun readObjectCounter(unpacker: MessageUnpacker): ObjectCounter { +private fun readObjectCounter(unpacker: MessageUnpacker): ObjectsCounter { val fieldCount = unpacker.unpackMapHeader() var count: Double? = null @@ -554,13 +554,13 @@ private fun readObjectCounter(unpacker: MessageUnpacker): ObjectCounter { } } - return ObjectCounter(count = count) + return ObjectsCounter(count = count) } /** * Write ObjectMapEntry to MessagePacker */ -private fun ObjectMapEntry.writeMsgpack(packer: MessagePacker) { +private fun ObjectsMapEntry.writeMsgpack(packer: MessagePacker) { var fieldCount = 0 if (tombstone != null) fieldCount++ @@ -594,7 +594,7 @@ private fun ObjectMapEntry.writeMsgpack(packer: MessagePacker) { /** * Read ObjectMapEntry from MessageUnpacker */ -private fun readObjectMapEntry(unpacker: MessageUnpacker): ObjectMapEntry { +private fun readObjectMapEntry(unpacker: MessageUnpacker): ObjectsMapEntry { val fieldCount = unpacker.unpackMapHeader() var tombstone: Boolean? = null @@ -620,7 +620,7 @@ private fun readObjectMapEntry(unpacker: MessageUnpacker): ObjectMapEntry { } } - return ObjectMapEntry(tombstone = tombstone, timeserial = timeserial, serialTimestamp = serialTimestamp, data = data) + return ObjectsMapEntry(tombstone = tombstone, timeserial = timeserial, serialTimestamp = serialTimestamp, data = data) } /** diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseRealtimeObject.kt similarity index 92% rename from live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt rename to live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseRealtimeObject.kt index 1cb4df247..7d76e7b76 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseLiveObject.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/type/BaseRealtimeObject.kt @@ -15,22 +15,21 @@ internal enum class ObjectType(val value: String) { } // Spec: RTLO4b4b -internal val LiveObjectUpdate.noOp get() = this.update == null +internal val ObjectUpdate.noOp get() = this.update == null /** - * Base implementation of LiveObject interface. - * Provides common functionality for all live objects. + * Provides common functionality and base implementation for LiveMap and LiveCounter. * * @spec RTLO1/RTLO2 - Base class for LiveMap/LiveCounter object * * This should also be included in logging */ -internal abstract class BaseLiveObject( +internal abstract class BaseRealtimeObject( internal val objectId: String, // // RTLO3a internal val objectType: ObjectType, ) { - protected open val tag = "BaseLiveObject" + protected open val tag = "BaseRealtimeObject" internal val siteTimeserials = mutableMapOf() // RTLO3b @@ -47,7 +46,7 @@ internal abstract class BaseLiveObject( * * @spec RTLM6/RTLC6 - Overrides ObjectMessage with object data state from sync to LiveMap/LiveCounter */ - internal fun applyObjectSync(objectMessage: ObjectMessage): LiveObjectUpdate { + internal fun applyObjectSync(objectMessage: ObjectMessage): ObjectUpdate { val objectState = objectMessage.objectState as ObjectState // we have non-null objectState here due to RTO5b validate(objectState) // object's site serials are still updated even if it is tombstoned, so always use the site serials received from the operation. @@ -123,14 +122,14 @@ internal abstract class BaseLiveObject( /** * Marks the object as tombstoned. */ - internal fun tombstone(serialTimestamp: Long?): LiveObjectUpdate { + internal fun tombstone(serialTimestamp: Long?): ObjectUpdate { if (serialTimestamp == null) { Log.w(tag, "Tombstoning object $objectId without serial timestamp, using local timestamp instead") } isTombstoned = true tombstonedAt = serialTimestamp?: System.currentTimeMillis() val update = clearData() - // TODO: Emit BaseLiveObject lifecycle events + // TODO: Emit BaseRealtimeObject lifecycle events return update } @@ -157,7 +156,7 @@ internal abstract class BaseLiveObject( * @return A map describing the changes made to the object's data * */ - abstract fun applyObjectState(objectState: ObjectState, message: ObjectMessage): LiveObjectUpdate + abstract fun applyObjectState(objectState: ObjectState, message: ObjectMessage): ObjectUpdate /** * Applies an operation to this live object. @@ -183,14 +182,14 @@ internal abstract class BaseLiveObject( * * @return A map representing the diff of changes made */ - abstract fun clearData(): LiveObjectUpdate + abstract fun clearData(): ObjectUpdate /** * Notifies subscribers about changes made to this live object. Propagates updates through the * appropriate manager after converting the generic update map to type-specific update objects. * Spec: RTLO4b4c */ - abstract fun notifyUpdated(update: LiveObjectUpdate) + abstract fun notifyUpdated(update: ObjectUpdate) /** * Called during garbage collection intervals to clean up expired entries. diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt index fc5d95ca6..b34188b62 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/DefaultLiveCounter.kt @@ -3,8 +3,8 @@ package io.ably.lib.objects.type.livecounter import io.ably.lib.objects.* import io.ably.lib.objects.ObjectOperation import io.ably.lib.objects.ObjectState -import io.ably.lib.objects.type.BaseLiveObject -import io.ably.lib.objects.type.LiveObjectUpdate +import io.ably.lib.objects.type.BaseRealtimeObject +import io.ably.lib.objects.type.ObjectUpdate import io.ably.lib.objects.type.ObjectType import io.ably.lib.objects.type.counter.LiveCounter import io.ably.lib.objects.type.counter.LiveCounterChange @@ -15,14 +15,12 @@ import io.ably.lib.util.Log import kotlinx.coroutines.runBlocking /** - * Implementation of LiveObject for LiveCounter. - * - * @spec RTLC1/RTLC2 - LiveCounter implementation extends LiveObject + * @spec RTLC1/RTLC2 - LiveCounter implementation extends BaseRealtimeObject */ internal class DefaultLiveCounter private constructor( objectId: String, - private val liveObjects: DefaultLiveObjects, -) : LiveCounter, BaseLiveObject(objectId, ObjectType.Counter) { + private val realtimeObjects: DefaultRealtimeObjects, +) : LiveCounter, BaseRealtimeObject(objectId, ObjectType.Counter) { override val tag = "LiveCounter" @@ -37,9 +35,9 @@ internal class DefaultLiveCounter private constructor( */ private val liveCounterManager = LiveCounterManager(this) - private val channelName = liveObjects.channelName - private val adapter: LiveObjectsAdapter get() = liveObjects.adapter - private val asyncScope get() = liveObjects.asyncScope + private val channelName = realtimeObjects.channelName + private val adapter: ObjectsAdapter get() = realtimeObjects.adapter + private val asyncScope get() = realtimeObjects.asyncScope override fun increment(amount: Number) = runBlocking { incrementAsync(amount.toDouble()) } @@ -83,12 +81,12 @@ internal class DefaultLiveCounter private constructor( operation = ObjectOperation( action = ObjectOperationAction.CounterInc, objectId = objectId, - counterOp = ObjectCounterOp(amount = amount) + counterOp = ObjectsCounterOp(amount = amount) ) ) // RTLC12f - Publish the message - liveObjects.publish(arrayOf(msg)) + realtimeObjects.publish(arrayOf(msg)) } override fun applyObjectState(objectState: ObjectState, message: ObjectMessage): LiveCounterUpdate { @@ -103,7 +101,7 @@ internal class DefaultLiveCounter private constructor( return liveCounterManager.calculateUpdateFromDataDiff(data.get(), 0.0).apply { data.set(0.0) } } - override fun notifyUpdated(update: LiveObjectUpdate) { + override fun notifyUpdated(update: ObjectUpdate) { if (update.noOp) { return } @@ -121,8 +119,8 @@ internal class DefaultLiveCounter private constructor( * Creates a zero-value counter object. * @spec RTLC4 - Returns LiveCounter with 0 value */ - internal fun zeroValue(objectId: String, liveObjects: DefaultLiveObjects): DefaultLiveCounter { - return DefaultLiveCounter(objectId, liveObjects) + internal fun zeroValue(objectId: String, realtimeObjects: DefaultRealtimeObjects): DefaultLiveCounter { + return DefaultLiveCounter(objectId, realtimeObjects) } /** @@ -131,7 +129,7 @@ internal class DefaultLiveCounter private constructor( */ internal fun initialValue(count: Number): CounterCreatePayload { return CounterCreatePayload( - counter = ObjectCounter(count = count.toDouble()) + counter = ObjectsCounter(count = count.toDouble()) ) } } diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt index 667773abf..d96d65b64 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livecounter/LiveCounterManager.kt @@ -78,7 +78,7 @@ internal class LiveCounterManager(private val liveCounter: DefaultLiveCounter): /** * @spec RTLC9 - Applies counter increment operation */ - private fun applyCounterInc(counterOp: ObjectCounterOp): LiveCounterUpdate { + private fun applyCounterInc(counterOp: ObjectsCounterOp): LiveCounterUpdate { val amount = counterOp.amount ?: 0.0 val previousValue = liveCounter.data.get() liveCounter.data.set(previousValue + amount) // RTLC9b diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt index 65079945a..8c2da8e6a 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/DefaultLiveMap.kt @@ -1,12 +1,12 @@ package io.ably.lib.objects.type.livemap import io.ably.lib.objects.* -import io.ably.lib.objects.MapSemantics +import io.ably.lib.objects.ObjectsMapSemantics import io.ably.lib.objects.ObjectMessage import io.ably.lib.objects.ObjectOperation import io.ably.lib.objects.ObjectState -import io.ably.lib.objects.type.BaseLiveObject -import io.ably.lib.objects.type.LiveObjectUpdate +import io.ably.lib.objects.type.BaseRealtimeObject +import io.ably.lib.objects.type.ObjectUpdate import io.ably.lib.objects.type.ObjectType import io.ably.lib.objects.type.map.LiveMap import io.ably.lib.objects.type.map.LiveMapChange @@ -19,15 +19,13 @@ import java.util.concurrent.ConcurrentHashMap import java.util.AbstractMap /** - * Implementation of LiveObject for LiveMap. - * - * @spec RTLM1/RTLM2 - LiveMap implementation extends LiveObject + * @spec RTLM1/RTLM2 - LiveMap implementation extends BaseRealtimeObject */ internal class DefaultLiveMap private constructor( objectId: String, - private val liveObjects: DefaultLiveObjects, - internal val semantics: MapSemantics = MapSemantics.LWW -) : LiveMap, BaseLiveObject(objectId, ObjectType.Map) { + private val realtimeObjects: DefaultRealtimeObjects, + internal val semantics: ObjectsMapSemantics = ObjectsMapSemantics.LWW +) : LiveMap, BaseRealtimeObject(objectId, ObjectType.Map) { override val tag = "LiveMap" @@ -41,10 +39,10 @@ internal class DefaultLiveMap private constructor( */ private val liveMapManager = LiveMapManager(this) - private val channelName = liveObjects.channelName - private val adapter: LiveObjectsAdapter get() = liveObjects.adapter - internal val objectsPool: ObjectsPool get() = liveObjects.objectsPool - private val asyncScope get() = liveObjects.asyncScope + private val channelName = realtimeObjects.channelName + private val adapter: ObjectsAdapter get() = realtimeObjects.adapter + internal val objectsPool: ObjectsPool get() = realtimeObjects.objectsPool + private val asyncScope get() = realtimeObjects.asyncScope override fun get(keyName: String): LiveMapValue? { adapter.throwIfInvalidAccessApiConfiguration(channelName) // RTLM5b, RTLM5c @@ -130,7 +128,7 @@ internal class DefaultLiveMap private constructor( operation = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = objectId, - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = keyName, data = fromLiveMapValue(value) ) @@ -138,7 +136,7 @@ internal class DefaultLiveMap private constructor( ) // RTLM20f - Publish the message - liveObjects.publish(arrayOf(msg)) + realtimeObjects.publish(arrayOf(msg)) } private suspend fun removeAsync(keyName: String) { @@ -155,12 +153,12 @@ internal class DefaultLiveMap private constructor( operation = ObjectOperation( action = ObjectOperationAction.MapRemove, objectId = objectId, - mapOp = ObjectMapOp(key = keyName) + mapOp = ObjectsMapOp(key = keyName) ) ) // RTLM21f - Publish the message - liveObjects.publish(arrayOf(msg)) + realtimeObjects.publish(arrayOf(msg)) } override fun applyObjectState(objectState: ObjectState, message: ObjectMessage): LiveMapUpdate { @@ -176,7 +174,7 @@ internal class DefaultLiveMap private constructor( .apply { data.clear() } } - override fun notifyUpdated(update: LiveObjectUpdate) { + override fun notifyUpdated(update: ObjectUpdate) { if (update.noOp) { return } @@ -193,7 +191,7 @@ internal class DefaultLiveMap private constructor( * Creates a zero-value map object. * @spec RTLM4 - Returns LiveMap with empty map data */ - internal fun zeroValue(objectId: String, objects: DefaultLiveObjects): DefaultLiveMap { + internal fun zeroValue(objectId: String, objects: DefaultRealtimeObjects): DefaultLiveMap { return DefaultLiveMap(objectId, objects) } @@ -203,10 +201,10 @@ internal class DefaultLiveMap private constructor( */ internal fun initialValue(entries: MutableMap): MapCreatePayload { return MapCreatePayload( - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = entries.mapValues { (_, value) -> - ObjectMapEntry( + ObjectsMapEntry( tombstone = false, data = fromLiveMapValue(value) ) @@ -221,7 +219,7 @@ internal class DefaultLiveMap private constructor( private fun fromLiveMapValue(value: LiveMapValue): ObjectData { return when { value.isLiveMap || value.isLiveCounter -> { - ObjectData(objectId = (value.value as BaseLiveObject).objectId) + ObjectData(objectId = (value.value as BaseRealtimeObject).objectId) } value.isBoolean -> { ObjectData(value = ObjectValue.Boolean(value.asBoolean)) diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.kt index 3e24f30cb..4c32366e1 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapEntry.kt @@ -4,7 +4,7 @@ import io.ably.lib.objects.* import io.ably.lib.objects.ObjectData import io.ably.lib.objects.ObjectsPool import io.ably.lib.objects.ObjectsPoolDefaults -import io.ably.lib.objects.type.BaseLiveObject +import io.ably.lib.objects.type.BaseRealtimeObject import io.ably.lib.objects.type.ObjectType import io.ably.lib.objects.type.counter.LiveCounter import io.ably.lib.objects.type.map.LiveMap @@ -22,7 +22,7 @@ internal data class LiveMapEntry( /** * Checks if entry is directly tombstoned or references a tombstoned object. Spec: RTLM14 - * @param objectsPool The object pool containing referenced LiveObjects + * @param objectsPool The object pool containing referenced DefaultRealtimeObjects */ internal fun LiveMapEntry.isEntryOrRefTombstoned(objectsPool: ObjectsPool): Boolean { if (isTombstoned) { @@ -40,7 +40,7 @@ internal fun LiveMapEntry.isEntryOrRefTombstoned(objectsPool: ObjectsPool): Bool /** * Returns value as is if object data stores a primitive type or - * a reference to another LiveObject from the pool if it stores an objectId. + * a reference to another RealtimeObject from the pool if it stores an objectId. */ internal fun LiveMapEntry.getResolvedValue(objectsPool: ObjectsPool): LiveMapValue? { if (isTombstoned) { return null } // RTLM5d2a @@ -52,7 +52,7 @@ internal fun LiveMapEntry.getResolvedValue(objectsPool: ObjectsPool): LiveMapVal if (refObject.isTombstoned) { return null // tombstoned objects must not be surfaced to the end users } - return fromLiveObject(refObject) // RTLM5d2f2 + return fromRealtimeObject(refObject) // RTLM5d2f2 } } return null // RTLM5d2g, RTLM5d2f1 @@ -77,9 +77,9 @@ private fun fromObjectValue(objValue: ObjectValue): LiveMapValue { } } -private fun fromLiveObject(baseLiveObject: BaseLiveObject): LiveMapValue { - return when (baseLiveObject.objectType) { - ObjectType.Map -> LiveMapValue.of(baseLiveObject as LiveMap) - ObjectType.Counter -> LiveMapValue.of(baseLiveObject as LiveCounter) +private fun fromRealtimeObject(realtimeObject: BaseRealtimeObject): LiveMapValue { + return when (realtimeObject.objectType) { + ObjectType.Map -> LiveMapValue.of(realtimeObject as LiveMap) + ObjectType.Counter -> LiveMapValue.of(realtimeObject as LiveCounter) } } diff --git a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt index f0f771190..19a6ef592 100644 --- a/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt +++ b/live-objects/src/main/kotlin/io/ably/lib/objects/type/livemap/LiveMapManager.kt @@ -1,7 +1,7 @@ package io.ably.lib.objects.type.livemap -import io.ably.lib.objects.MapSemantics -import io.ably.lib.objects.ObjectMapOp +import io.ably.lib.objects.ObjectsMapSemantics +import io.ably.lib.objects.ObjectsMapOp import io.ably.lib.objects.ObjectOperation import io.ably.lib.objects.ObjectOperationAction import io.ably.lib.objects.ObjectState @@ -100,8 +100,8 @@ internal class LiveMapManager(private val liveMap: DefaultLiveMap): LiveMapChang * @spec RTLM7 - Applies MAP_SET operation to LiveMap */ private fun applyMapSet( - mapOp: ObjectMapOp, // RTLM7d1 - timeSerial: String?, // RTLM7d2 + mapOp: ObjectsMapOp, // RTLM7d1 + timeSerial: String?, // RTLM7d2 ): LiveMapUpdate { val existingEntry = liveMap.data[mapOp.key] @@ -151,9 +151,9 @@ internal class LiveMapManager(private val liveMap: DefaultLiveMap): LiveMapChang * @spec RTLM8 - Applies MAP_REMOVE operation to LiveMap */ private fun applyMapRemove( - mapOp: ObjectMapOp, // RTLM8c1 - timeSerial: String?, // RTLM8c2 - timeStamp: Long?, // RTLM8c3 + mapOp: ObjectsMapOp, // RTLM8c1 + timeSerial: String?, // RTLM8c2 + timeStamp: Long?, // RTLM8c3 ): LiveMapUpdate { val existingEntry = liveMap.data[mapOp.key] @@ -233,10 +233,10 @@ internal class LiveMapManager(private val liveMap: DefaultLiveMap): LiveMapChang val opTimeserial = entry.timeserial val update = if (entry.tombstone == true) { // RTLM17a2 - entry in MAP_CREATE op is removed, try to apply MAP_REMOVE op - applyMapRemove(ObjectMapOp(key), opTimeserial, entry.serialTimestamp) + applyMapRemove(ObjectsMapOp(key), opTimeserial, entry.serialTimestamp) } else { // RTLM17a1 - entry in MAP_CREATE op is not removed, try to set it via MAP_SET op - applyMapSet(ObjectMapOp(key, entry.data), opTimeserial) + applyMapSet(ObjectsMapOp(key, entry.data), opTimeserial) } // skip noop updates @@ -324,10 +324,10 @@ internal class LiveMapManager(private val liveMap: DefaultLiveMap): LiveMapChang } } - private fun validateMapSemantics(semantics: MapSemantics?) { + private fun validateMapSemantics(semantics: ObjectsMapSemantics?) { if (semantics != liveMap.semantics) { throw objectError( - "Invalid object: incoming object map semantics=$semantics; current map semantics=${MapSemantics.LWW}" + "Invalid object: incoming object map semantics=$semantics; current map semantics=${ObjectsMapSemantics.LWW}" ) } } diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultRealtimeObjectsTest.kt similarity index 99% rename from live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt rename to live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultRealtimeObjectsTest.kt index ebef88ea1..a95954dc7 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultLiveObjectsTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/integration/DefaultRealtimeObjectsTest.kt @@ -17,7 +17,7 @@ import kotlin.test.assertNull import kotlin.test.assertTrue import kotlin.text.toByteArray -class DefaultLiveObjectsTest : IntegrationTest() { +class DefaultRealtimeObjectsTest : IntegrationTest() { @Test fun testChannelObjects() = runTest { diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt index 0e3213748..05b50b7dc 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/integration/helpers/Utils.kt @@ -1,10 +1,10 @@ package io.ably.lib.objects.integration.helpers import io.ably.lib.objects.* -import io.ably.lib.objects.DefaultLiveObjects +import io.ably.lib.objects.DefaultRealtimeObjects import io.ably.lib.objects.ObjectMessage import io.ably.lib.objects.ObjectOperation -import io.ably.lib.objects.type.BaseLiveObject +import io.ably.lib.objects.type.BaseRealtimeObject import io.ably.lib.objects.type.counter.LiveCounter import io.ably.lib.objects.type.map.LiveMap import io.ably.lib.objects.type.livecounter.DefaultLiveCounter @@ -15,15 +15,15 @@ internal val LiveMap.ObjectId get() = (this as DefaultLiveMap).objectId internal val LiveCounter.ObjectId get() = (this as DefaultLiveCounter).objectId -internal val LiveObjects.State get() = (this as DefaultLiveObjects).state +internal val RealtimeObjects.State get() = (this as DefaultRealtimeObjects).state /** * Server runs periodic garbage collection (GC) to remove orphaned objects and will send * OBJECT_DELETE events for objects that are no longer referenced. * So, we simulate the deletion of an object by sending a ProtocolMessage. */ -internal fun LiveObjects.simulateObjectDelete(baseObject: BaseLiveObject) { - val defaultLiveObjects = this as DefaultLiveObjects +internal fun RealtimeObjects.simulateObjectDelete(baseObject: BaseRealtimeObject) { + val defaultRealtimeObjects = this as DefaultRealtimeObjects val existingSiteCode = baseObject.siteTimeserials.keys.first() val existingSiteSerial = baseObject.siteTimeserials[existingSiteCode]!! @@ -36,5 +36,5 @@ internal fun LiveObjects.simulateObjectDelete(baseObject: BaseLiveObject) { objectId = baseObject.objectId, ) )) - defaultLiveObjects.handle(deleteObjectProtoMsg) + defaultRealtimeObjects.handle(deleteObjectProtoMsg) } diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/HelpersTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/HelpersTest.kt index fe1824bad..4b6662636 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/HelpersTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/HelpersTest.kt @@ -21,7 +21,7 @@ class HelpersTest { // sendAsync @Test fun testSendAsyncShouldQueueAccordingToClientOptions() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val connManager = mockk(relaxed = true) val clientOptions = ClientOptions().apply { queueMessages = false } @@ -44,7 +44,7 @@ class HelpersTest { @Test fun testSendAsyncErrorPropagatesAblyException() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val connManager = mockk(relaxed = true) val clientOptions = ClientOptions() @@ -65,7 +65,7 @@ class HelpersTest { @Test fun testSendAsyncThrowsWhenConnectionManagerThrows() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val connManager = mockk(relaxed = true) val clientOptions = ClientOptions() @@ -83,7 +83,7 @@ class HelpersTest { // attachAsync @Test fun testAttachAsyncSuccess() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel every { channel.attach(any()) } answers { @@ -97,7 +97,7 @@ class HelpersTest { @Test fun testAttachAsyncError() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel every { channel.attach(any()) } answers { @@ -113,7 +113,7 @@ class HelpersTest { // getChannelModes @Test fun testGetChannelModesPrefersChannelModes() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel every { channel.modes } returns arrayOf(ChannelMode.object_publish) @@ -125,7 +125,7 @@ class HelpersTest { @Test fun testGetChannelModesFallsBackToOptions() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel every { channel.modes } returns emptyArray() @@ -137,7 +137,7 @@ class HelpersTest { @Test fun testGetChannelModesReturnsNullWhenNoModes() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel every { channel.modes } returns null @@ -149,7 +149,7 @@ class HelpersTest { @Test fun testGetChannelModesIgnoresEmptyModes() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel every { channel.modes } returns emptyArray() @@ -162,7 +162,7 @@ class HelpersTest { // setChannelSerial @Test fun testSetChannelSerialSetsWhenObjectActionAndNonEmpty() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) val props = ChannelProperties() channel.properties = props @@ -177,7 +177,7 @@ class HelpersTest { @Test fun testSetChannelSerialNoOpForNonObjectActionOrEmpty() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) val props = ChannelProperties() channel.properties = props @@ -199,7 +199,7 @@ class HelpersTest { // ensureAttached @Test fun testEnsureAttachedFromInitializedAttaches() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel @@ -216,7 +216,7 @@ class HelpersTest { @Test fun testEnsureAttachedWhenAlreadyAttachedReturns() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel channel.state = ChannelState.attached @@ -228,7 +228,7 @@ class HelpersTest { @Test fun testEnsureAttachedWaitsForAttachingThenAttached() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel channel.state = ChannelState.attaching @@ -247,7 +247,7 @@ class HelpersTest { @Test fun testEnsureAttachedAttachingButReceivesNonAttachedEmitsError() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel channel.state = ChannelState.attaching @@ -267,7 +267,7 @@ class HelpersTest { @Test fun testEnsureAttachedThrowsForInvalidState() = runTest { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel channel.state = ChannelState.failed @@ -279,7 +279,7 @@ class HelpersTest { // throwIfInvalidAccessApiConfiguration @Test fun testThrowIfInvalidAccessApiConfigurationStateDetached() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel channel.state = ChannelState.detached @@ -290,7 +290,7 @@ class HelpersTest { @Test fun testThrowIfInvalidAccessApiConfigurationMissingMode() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel channel.state = ChannelState.attached @@ -305,7 +305,7 @@ class HelpersTest { // throwIfInvalidWriteApiConfiguration @Test fun testThrowIfInvalidWriteApiConfigurationEchoDisabled() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val clientOptions = ClientOptions().apply { echoMessages = false } every { adapter.clientOptions } returns clientOptions @@ -316,7 +316,7 @@ class HelpersTest { @Test fun testThrowIfInvalidWriteApiConfigurationInvalidState() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) every { adapter.clientOptions } returns ClientOptions() val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel @@ -328,7 +328,7 @@ class HelpersTest { @Test fun testThrowIfInvalidWriteApiConfigurationMissingMode() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) every { adapter.clientOptions } returns ClientOptions() val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel @@ -344,7 +344,7 @@ class HelpersTest { // throwIfUnpublishableState @Test fun testThrowIfUnpublishableStateInactiveConnection() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val connManager = mockk(relaxed = true) every { adapter.connectionManager } returns connManager every { connManager.isActive } returns false @@ -357,7 +357,7 @@ class HelpersTest { @Test fun testThrowIfUnpublishableStateChannelFailed() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val connManager = mockk(relaxed = true) every { adapter.connectionManager } returns connManager every { connManager.isActive } returns true @@ -371,7 +371,7 @@ class HelpersTest { @Test fun testAccessConfigThrowsWhenRequiredModeMissing() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel channel.state = ChannelState.attached @@ -386,7 +386,7 @@ class HelpersTest { @Test fun testWriteConfigThrowsWhenRequiredModeMissing() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) every { adapter.clientOptions } returns ClientOptions() // echo enabled val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel @@ -401,7 +401,7 @@ class HelpersTest { @Test fun testAccessConfigThrowsOnInvalidChannelState() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel channel.state = ChannelState.detached @@ -412,7 +412,7 @@ class HelpersTest { @Test fun testWriteConfigThrowsOnInvalidChannelStates() { - val adapter = mockk(relaxed = true) + val adapter = mockk(relaxed = true) every { adapter.clientOptions } returns ClientOptions() val channel = mockk(relaxed = true) every { adapter.getChannel("ch") } returns channel diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt index 4d3df7e7d..32a51069a 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/ObjectMessageSizeTest.kt @@ -3,7 +3,7 @@ package io.ably.lib.objects.unit import com.google.gson.JsonObject import io.ably.lib.objects.* import io.ably.lib.objects.ObjectData -import io.ably.lib.objects.ObjectMapOp +import io.ably.lib.objects.ObjectsMapOp import io.ably.lib.objects.ObjectMessage import io.ably.lib.objects.ObjectOperation import io.ably.lib.objects.ObjectOperationAction @@ -22,7 +22,7 @@ class ObjectMessageSizeTest { @Test fun testObjectMessageSizeWithinLimit() = runTest { - val mockAdapter = mockk(relaxed = true) + val mockAdapter = mockk(relaxed = true) mockAdapter.connectionManager.maxMessageSize = Defaults.maxMessageSize // 64 kb assertEquals(65536, mockAdapter.connectionManager.maxMessageSize) @@ -41,7 +41,7 @@ class ObjectMessageSizeTest { objectId = "obj_54321", // Not counted in operation size // MapOp contributes to operation size - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "mapKey", // Size: 6 bytes (UTF-8 byte length) data = ObjectData( objectId = "ref_obj", // Not counted in data size @@ -50,22 +50,22 @@ class ObjectMessageSizeTest { ), // Total ObjectMapOp size: 6 + 6 = 12 bytes // CounterOp contributes to operation size - counterOp = ObjectCounterOp( + counterOp = ObjectsCounterOp( amount = 10.0 // Size: 8 bytes (number is always 8 bytes) ), // Total ObjectCounterOp size: 8 bytes // Map contributes to operation size (for MAP_CREATE operations) - map = ObjectMap( - semantics = MapSemantics.LWW, // Not counted in size + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, // Not counted in size entries = mapOf( - "entry1" to ObjectMapEntry( // Key size: 6 bytes + "entry1" to ObjectsMapEntry( // Key size: 6 bytes tombstone = false, // Not counted in entry size timeserial = "ts_123", // Not counted in entry size data = ObjectData( value = ObjectValue.String("value1") // Size: 6 bytes ) // ObjectMapEntry size: 6 bytes ), // Total for this entry: 6 (key) + 6 (entry) = 12 bytes - "entry2" to ObjectMapEntry( // Key size: 6 bytes + "entry2" to ObjectsMapEntry( // Key size: 6 bytes data = ObjectData( value = ObjectValue.Number(42) // Size: 8 bytes (number) ) // ObjectMapEntry size: 8 bytes @@ -74,7 +74,7 @@ class ObjectMessageSizeTest { ), // Total ObjectMap size: 26 bytes // Counter contributes to operation size (for COUNTER_CREATE operations) - counter = ObjectCounter( + counter = ObjectsCounter( count = 100.0 // Size: 8 bytes (number is always 8 bytes) ), // Total ObjectCounter size: 8 bytes @@ -91,7 +91,7 @@ class ObjectMessageSizeTest { createOp = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = "create_obj", - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "createKey", // Size: 9 bytes data = ObjectData( value = ObjectValue.String("createValue") // Size: 11 bytes @@ -100,9 +100,9 @@ class ObjectMessageSizeTest { ), // Total createOp size: 20 bytes // map contributes to state size - map = ObjectMap( + map = ObjectsMap( entries = mapOf( - "stateKey" to ObjectMapEntry( // Key size: 8 bytes + "stateKey" to ObjectsMapEntry( // Key size: 8 bytes data = ObjectData( value = ObjectValue.String("stateValue") // Size: 10 bytes ) // ObjectMapEntry size: 10 bytes @@ -111,7 +111,7 @@ class ObjectMessageSizeTest { ), // Total ObjectMap size: 18 bytes // counter contributes to state size - counter = ObjectCounter( + counter = ObjectsCounter( count = 50.0 // Size: 8 bytes ) // Total ObjectCounter size: 8 bytes ), // Total ObjectState size: 20 + 18 + 8 = 46 bytes @@ -134,7 +134,7 @@ class ObjectMessageSizeTest { operation = ObjectOperation( objectId = "", action = ObjectOperationAction.MapCreate, - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "", data = ObjectData( value = ObjectValue.String("你😊") // 你 -> 3 bytes, 😊 -> 4 bytes @@ -147,7 +147,7 @@ class ObjectMessageSizeTest { @Test fun testObjectMessageSizeAboveLimit() = runTest { - val mockAdapter = mockk(relaxed = true) + val mockAdapter = mockk(relaxed = true) mockAdapter.connectionManager.maxMessageSize = Defaults.maxMessageSize // 64 kb assertEquals(65536, mockAdapter.connectionManager.maxMessageSize) diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/TestHelpers.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/TestHelpers.kt index 5fc8c590e..94354fcf9 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/TestHelpers.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/TestHelpers.kt @@ -1,9 +1,9 @@ package io.ably.lib.objects.unit import io.ably.lib.objects.* -import io.ably.lib.objects.DefaultLiveObjects +import io.ably.lib.objects.DefaultRealtimeObjects import io.ably.lib.objects.ObjectsManager -import io.ably.lib.objects.type.BaseLiveObject +import io.ably.lib.objects.type.BaseRealtimeObject import io.ably.lib.objects.type.livecounter.DefaultLiveCounter import io.ably.lib.objects.type.livecounter.LiveCounterManager import io.ably.lib.objects.type.livemap.DefaultLiveMap @@ -44,8 +44,8 @@ internal fun getMockRealtimeChannel( } } -internal fun getMockLiveObjectsAdapter(): LiveObjectsAdapter { - val mockkAdapter = mockk(relaxed = true) +internal fun getMockObjectsAdapter(): ObjectsAdapter { + val mockkAdapter = mockk(relaxed = true) every { mockkAdapter.getChannel(any()) } returns getMockRealtimeChannel("testChannelName") return mockkAdapter } @@ -55,16 +55,16 @@ internal fun getMockObjectsPool(): ObjectsPool { } internal fun ObjectsPool.size(): Int { - val pool = this.getPrivateField>("pool") + val pool = this.getPrivateField>("pool") return pool.size } -internal val BaseLiveObject.TombstonedAt: Long? +internal val BaseRealtimeObject.TombstonedAt: Long? get() = this.getPrivateField("tombstonedAt") /** * ====================================== - * START - DefaultLiveObjects dep mocks + * START - DefaultRealtimeObjects dep mocks * ====================================== */ internal val ObjectsManager.SyncObjectsDataPool: Map @@ -73,36 +73,36 @@ internal val ObjectsManager.SyncObjectsDataPool: Map internal val ObjectsManager.BufferedObjectOperations: List get() = this.getPrivateField("bufferedObjectOperations") -internal var DefaultLiveObjects.ObjectsManager: ObjectsManager +internal var DefaultRealtimeObjects.ObjectsManager: ObjectsManager get() = this.getPrivateField("objectsManager") set(value) = this.setPrivateField("objectsManager", value) -internal var DefaultLiveObjects.ObjectsPool: ObjectsPool +internal var DefaultRealtimeObjects.ObjectsPool: ObjectsPool get() = this.objectsPool set(value) = this.setPrivateField("objectsPool", value) -internal fun getDefaultLiveObjectsWithMockedDeps( +internal fun getDefaultRealtimeObjectsWithMockedDeps( channelName: String = "testChannelName", relaxed: Boolean = false -): DefaultLiveObjects { - val defaultLiveObjects = DefaultLiveObjects(channelName, getMockLiveObjectsAdapter()) +): DefaultRealtimeObjects { + val defaultRealtimeObjects = DefaultRealtimeObjects(channelName, getMockObjectsAdapter()) // mock objectsPool to allow verification of method calls if (relaxed) { - defaultLiveObjects.ObjectsPool = mockk(relaxed = true) + defaultRealtimeObjects.ObjectsPool = mockk(relaxed = true) } else { - defaultLiveObjects.ObjectsPool = spyk(defaultLiveObjects.objectsPool, recordPrivateCalls = true) + defaultRealtimeObjects.ObjectsPool = spyk(defaultRealtimeObjects.objectsPool, recordPrivateCalls = true) } // mock objectsManager to allow verification of method calls if (relaxed) { - defaultLiveObjects.ObjectsManager = mockk(relaxed = true) + defaultRealtimeObjects.ObjectsManager = mockk(relaxed = true) } else { - defaultLiveObjects.ObjectsManager = spyk(defaultLiveObjects.ObjectsManager, recordPrivateCalls = true) + defaultRealtimeObjects.ObjectsManager = spyk(defaultRealtimeObjects.ObjectsManager, recordPrivateCalls = true) } - return defaultLiveObjects + return defaultRealtimeObjects } /** * ====================================== - * END - DefaultLiveObjects dep mocks + * END - DefaultRealtimeObjects dep mocks * ====================================== */ @@ -119,7 +119,7 @@ internal fun getDefaultLiveCounterWithMockedDeps( objectId: String = "counter:testCounter@1", relaxed: Boolean = false ): DefaultLiveCounter { - val defaultLiveCounter = DefaultLiveCounter.zeroValue(objectId, getDefaultLiveObjectsWithMockedDeps()) + val defaultLiveCounter = DefaultLiveCounter.zeroValue(objectId, getDefaultRealtimeObjectsWithMockedDeps()) if (relaxed) { defaultLiveCounter.LiveCounterManager = mockk(relaxed = true) } else { @@ -146,7 +146,7 @@ internal fun getDefaultLiveMapWithMockedDeps( objectId: String = "map:testMap@1", relaxed: Boolean = false ): DefaultLiveMap { - val defaultLiveMap = DefaultLiveMap.zeroValue(objectId, getDefaultLiveObjectsWithMockedDeps()) + val defaultLiveMap = DefaultLiveMap.zeroValue(objectId, getDefaultRealtimeObjectsWithMockedDeps()) if (relaxed) { defaultLiveMap.LiveMapManager = mockk(relaxed = true) } else { diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/fixtures/ObjectMessageFixtures.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/fixtures/ObjectMessageFixtures.kt index fb26af12d..e09101ac0 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/fixtures/ObjectMessageFixtures.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/fixtures/ObjectMessageFixtures.kt @@ -23,37 +23,37 @@ internal val dummyJsonObjectValue = ObjectData(objectId = "object-id", ObjectVal val dummyJsonArray = JsonArray().apply { add(1); add(2); add(3) } internal val dummyJsonArrayValue = ObjectData(objectId = "object-id", ObjectValue.JsonArray(dummyJsonArray)) -internal val dummyObjectMapEntry = ObjectMapEntry( +internal val dummyObjectsMapEntry = ObjectsMapEntry( tombstone = false, timeserial = "dummy-timeserial", data = dummyObjectDataStringValue ) -internal val dummyObjectMap = ObjectMap( - semantics = MapSemantics.LWW, - entries = mapOf("dummy-key" to dummyObjectMapEntry) +internal val dummyObjectsMap = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, + entries = mapOf("dummy-key" to dummyObjectsMapEntry) ) -internal val dummyObjectCounter = ObjectCounter( +internal val dummyObjectsCounter = ObjectsCounter( count = 123.0 ) -internal val dummyObjectMapOp = ObjectMapOp( +internal val dummyObjectsMapOp = ObjectsMapOp( key = "dummy-key", data = dummyObjectDataStringValue ) -internal val dummyObjectCounterOp = ObjectCounterOp( +internal val dummyObjectsCounterOp = ObjectsCounterOp( amount = 10.0 ) internal val dummyObjectOperation = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "dummy-object-id", - mapOp = dummyObjectMapOp, - counterOp = dummyObjectCounterOp, - map = dummyObjectMap, - counter = dummyObjectCounter, + mapOp = dummyObjectsMapOp, + counterOp = dummyObjectsCounterOp, + map = dummyObjectsMap, + counter = dummyObjectsCounter, nonce = "dummy-nonce", initialValue = "{\"foo\":\"bar\"}" ) @@ -63,8 +63,8 @@ internal val dummyObjectState = ObjectState( siteTimeserials = mapOf("site1" to "serial1"), tombstone = false, createOp = dummyObjectOperation, - map = dummyObjectMap, - counter = dummyObjectCounter + map = dummyObjectsMap, + counter = dummyObjectsCounter ) internal val dummyObjectMessage = ObjectMessage( @@ -84,9 +84,9 @@ internal fun dummyObjectMessageWithStringData(): ObjectMessage { } internal fun dummyObjectMessageWithBinaryData(): ObjectMessage { - val binaryObjectMapEntry = dummyObjectMapEntry.copy(data = dummyBinaryObjectValue) - val binaryObjectMap = dummyObjectMap.copy(entries = mapOf("dummy-key" to binaryObjectMapEntry)) - val binaryObjectMapOp = dummyObjectMapOp.copy(data = dummyBinaryObjectValue) + val binaryObjectMapEntry = dummyObjectsMapEntry.copy(data = dummyBinaryObjectValue) + val binaryObjectMap = dummyObjectsMap.copy(entries = mapOf("dummy-key" to binaryObjectMapEntry)) + val binaryObjectMapOp = dummyObjectsMapOp.copy(data = dummyBinaryObjectValue) val binaryObjectOperation = dummyObjectOperation.copy( mapOp = binaryObjectMapOp, map = binaryObjectMap @@ -102,9 +102,9 @@ internal fun dummyObjectMessageWithBinaryData(): ObjectMessage { } internal fun dummyObjectMessageWithNumberData(): ObjectMessage { - val numberObjectMapEntry = dummyObjectMapEntry.copy(data = dummyNumberObjectValue) - val numberObjectMap = dummyObjectMap.copy(entries = mapOf("dummy-key" to numberObjectMapEntry)) - val numberObjectMapOp = dummyObjectMapOp.copy(data = dummyNumberObjectValue) + val numberObjectMapEntry = dummyObjectsMapEntry.copy(data = dummyNumberObjectValue) + val numberObjectMap = dummyObjectsMap.copy(entries = mapOf("dummy-key" to numberObjectMapEntry)) + val numberObjectMapOp = dummyObjectsMapOp.copy(data = dummyNumberObjectValue) val numberObjectOperation = dummyObjectOperation.copy( mapOp = numberObjectMapOp, map = numberObjectMap @@ -120,9 +120,9 @@ internal fun dummyObjectMessageWithNumberData(): ObjectMessage { } internal fun dummyObjectMessageWithBooleanData(): ObjectMessage { - val booleanObjectMapEntry = dummyObjectMapEntry.copy(data = dummyBooleanObjectValue) - val booleanObjectMap = dummyObjectMap.copy(entries = mapOf("dummy-key" to booleanObjectMapEntry)) - val booleanObjectMapOp = dummyObjectMapOp.copy(data = dummyBooleanObjectValue) + val booleanObjectMapEntry = dummyObjectsMapEntry.copy(data = dummyBooleanObjectValue) + val booleanObjectMap = dummyObjectsMap.copy(entries = mapOf("dummy-key" to booleanObjectMapEntry)) + val booleanObjectMapOp = dummyObjectsMapOp.copy(data = dummyBooleanObjectValue) val booleanObjectOperation = dummyObjectOperation.copy( mapOp = booleanObjectMapOp, map = booleanObjectMap @@ -138,9 +138,9 @@ internal fun dummyObjectMessageWithBooleanData(): ObjectMessage { } internal fun dummyObjectMessageWithJsonObjectData(): ObjectMessage { - val jsonObjectMapEntry = dummyObjectMapEntry.copy(data = dummyJsonObjectValue) - val jsonObjectMap = dummyObjectMap.copy(entries = mapOf("dummy-key" to jsonObjectMapEntry)) - val jsonObjectMapOp = dummyObjectMapOp.copy(data = dummyJsonObjectValue) + val jsonObjectMapEntry = dummyObjectsMapEntry.copy(data = dummyJsonObjectValue) + val jsonObjectMap = dummyObjectsMap.copy(entries = mapOf("dummy-key" to jsonObjectMapEntry)) + val jsonObjectMapOp = dummyObjectsMapOp.copy(data = dummyJsonObjectValue) val jsonObjectOperation = dummyObjectOperation.copy( action = ObjectOperationAction.MapSet, mapOp = jsonObjectMapOp, @@ -157,9 +157,9 @@ internal fun dummyObjectMessageWithJsonObjectData(): ObjectMessage { } internal fun dummyObjectMessageWithJsonArrayData(): ObjectMessage { - val jsonArrayMapEntry = dummyObjectMapEntry.copy(data = dummyJsonArrayValue) - val jsonArrayMap = dummyObjectMap.copy(entries = mapOf("dummy-key" to jsonArrayMapEntry)) - val jsonArrayMapOp = dummyObjectMapOp.copy(data = dummyJsonArrayValue) + val jsonArrayMapEntry = dummyObjectsMapEntry.copy(data = dummyJsonArrayValue) + val jsonArrayMap = dummyObjectsMap.copy(entries = mapOf("dummy-key" to jsonArrayMapEntry)) + val jsonArrayMapOp = dummyObjectsMapOp.copy(data = dummyJsonArrayValue) val jsonArrayOperation = dummyObjectOperation.copy( action = ObjectOperationAction.MapSet, mapOp = jsonArrayMapOp, diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/DefaultLiveObjectsTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/DefaultRealtimeObjectsTest.kt similarity index 73% rename from live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/DefaultLiveObjectsTest.kt rename to live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/DefaultRealtimeObjectsTest.kt index ea57da9a6..40565cabe 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/DefaultLiveObjectsTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/DefaultRealtimeObjectsTest.kt @@ -1,7 +1,7 @@ package io.ably.lib.objects.unit.objects import io.ably.lib.objects.* -import io.ably.lib.objects.ObjectCounterOp +import io.ably.lib.objects.ObjectsCounterOp import io.ably.lib.objects.ObjectData import io.ably.lib.objects.ObjectMessage import io.ably.lib.objects.ObjectOperation @@ -15,7 +15,7 @@ import io.ably.lib.objects.type.livemap.LiveMapEntry import io.ably.lib.objects.unit.BufferedObjectOperations import io.ably.lib.objects.unit.ObjectsManager import io.ably.lib.objects.unit.SyncObjectsDataPool -import io.ably.lib.objects.unit.getDefaultLiveObjectsWithMockedDeps +import io.ably.lib.objects.unit.getDefaultRealtimeObjectsWithMockedDeps import io.ably.lib.objects.unit.size import io.ably.lib.realtime.ChannelState import io.ably.lib.types.ProtocolMessage @@ -25,77 +25,77 @@ import org.junit.Test import kotlin.test.assertEquals import io.mockk.every -class DefaultLiveObjectsTest { +class DefaultRealtimeObjectsTest { @Test fun `(RTO4, RTO4a) When channel ATTACHED with HAS_OBJECTS flag true should start sync sequence`() = runTest { - val defaultLiveObjects = getDefaultLiveObjectsWithMockedDeps() + val defaultRealtimeObjects = getDefaultRealtimeObjectsWithMockedDeps() // RTO4a - If the HAS_OBJECTS flag is 1, the server will shortly perform an OBJECT_SYNC sequence - defaultLiveObjects.handleStateChange(ChannelState.attached, true) + defaultRealtimeObjects.handleStateChange(ChannelState.attached, true) - assertWaiter { defaultLiveObjects.state == ObjectsState.Syncing } + assertWaiter { defaultRealtimeObjects.state == ObjectsState.Syncing } // It is expected that the client will start a new sync sequence verify(exactly = 1) { - defaultLiveObjects.ObjectsManager.startNewSync(null) + defaultRealtimeObjects.ObjectsManager.startNewSync(null) } verify(exactly = 0) { - defaultLiveObjects.ObjectsManager.endSync(any()) + defaultRealtimeObjects.ObjectsManager.endSync(any()) } } @Test fun `(RTO4, RTO4b) When channel ATTACHED with HAS_OBJECTS flag false should complete sync immediately`() = runTest { - val defaultLiveObjects = getDefaultLiveObjectsWithMockedDeps() + val defaultRealtimeObjects = getDefaultRealtimeObjectsWithMockedDeps() // Set up some objects in objectPool that should be cleared - val rootObject = defaultLiveObjects.objectsPool.get(ROOT_OBJECT_ID) as DefaultLiveMap + val rootObject = defaultRealtimeObjects.objectsPool.get(ROOT_OBJECT_ID) as DefaultLiveMap rootObject.data["key1"] = LiveMapEntry(data = ObjectData("testValue1")) - defaultLiveObjects.objectsPool.set("counter:testObject@1", DefaultLiveCounter.zeroValue("counter:testObject@1", defaultLiveObjects)) - assertEquals(2, defaultLiveObjects.objectsPool.size(), "RTO4b - Should have 2 objects before state change") + defaultRealtimeObjects.objectsPool.set("counter:testObject@1", DefaultLiveCounter.zeroValue("counter:testObject@1", defaultRealtimeObjects)) + assertEquals(2, defaultRealtimeObjects.objectsPool.size(), "RTO4b - Should have 2 objects before state change") // RTO4b - If the HAS_OBJECTS flag is 0, the sync sequence must be considered complete immediately - defaultLiveObjects.handleStateChange(ChannelState.attached, false) + defaultRealtimeObjects.handleStateChange(ChannelState.attached, false) // Verify expected outcomes - assertWaiter { defaultLiveObjects.state == ObjectsState.Synced } // RTO4b4 + assertWaiter { defaultRealtimeObjects.state == ObjectsState.Synced } // RTO4b4 verify(exactly = 1) { - defaultLiveObjects.objectsPool.resetToInitialPool(true) + defaultRealtimeObjects.objectsPool.resetToInitialPool(true) } verify(exactly = 1) { - defaultLiveObjects.ObjectsManager.endSync(any()) + defaultRealtimeObjects.ObjectsManager.endSync(any()) } - assertEquals(0, defaultLiveObjects.ObjectsManager.SyncObjectsDataPool.size) // RTO4b3 - assertEquals(0, defaultLiveObjects.ObjectsManager.BufferedObjectOperations.size) // RTO4b5 - assertEquals(1, defaultLiveObjects.objectsPool.size()) // RTO4b1 - Only root remains - assertEquals(rootObject, defaultLiveObjects.objectsPool.get(ROOT_OBJECT_ID)) // points to previously created root object + assertEquals(0, defaultRealtimeObjects.ObjectsManager.SyncObjectsDataPool.size) // RTO4b3 + assertEquals(0, defaultRealtimeObjects.ObjectsManager.BufferedObjectOperations.size) // RTO4b5 + assertEquals(1, defaultRealtimeObjects.objectsPool.size()) // RTO4b1 - Only root remains + assertEquals(rootObject, defaultRealtimeObjects.objectsPool.get(ROOT_OBJECT_ID)) // points to previously created root object assertEquals(0, rootObject.data.size) // RTO4b2 - root object must be empty } @Test fun `(RTO4) When channel ATTACHED from INITIALIZED state should always start sync`() = runTest { - val defaultLiveObjects = getDefaultLiveObjectsWithMockedDeps() + val defaultRealtimeObjects = getDefaultRealtimeObjectsWithMockedDeps() // Ensure we're in INITIALIZED state - defaultLiveObjects.state = ObjectsState.Initialized + defaultRealtimeObjects.state = ObjectsState.Initialized // RTO4a - Should start sync even with HAS_OBJECTS flag false when in INITIALIZED state - defaultLiveObjects.handleStateChange(ChannelState.attached, false) + defaultRealtimeObjects.handleStateChange(ChannelState.attached, false) verify(exactly = 1) { - defaultLiveObjects.ObjectsManager.startNewSync(null) + defaultRealtimeObjects.ObjectsManager.startNewSync(null) } verify(exactly = 1) { - defaultLiveObjects.ObjectsManager.endSync(true) // deferStateEvent = true + defaultRealtimeObjects.ObjectsManager.endSync(true) // deferStateEvent = true } } @Test fun `(RTO5, RTO7) Should delegate OBJECT and OBJECT_SYNC protocolMessage to ObjectManager`() = runTest { - val defaultLiveObjects = getDefaultLiveObjectsWithMockedDeps(relaxed = true) + val defaultRealtimeObjects = getDefaultRealtimeObjectsWithMockedDeps(relaxed = true) // Create test ObjectMessage for OBJECT action val objectMessage = ObjectMessage( @@ -105,7 +105,7 @@ class DefaultLiveObjectsTest { operation = ObjectOperation( action = ObjectOperationAction.CounterInc, objectId = "counter:testObject@1", - counterOp = ObjectCounterOp(amount = 5.0) + counterOp = ObjectsCounterOp(amount = 5.0) ), serial = "serial1", siteCode = "site1" @@ -119,11 +119,11 @@ class DefaultLiveObjectsTest { state = arrayOf(objectMessage) } // Test OBJECT action delegation - defaultLiveObjects.handle(objectProtocolMessage) + defaultRealtimeObjects.handle(objectProtocolMessage) // Verify that handleObjectMessages was called with the correct parameters verify(exactly = 1) { - defaultLiveObjects.ObjectsManager.handleObjectMessages(listOf(objectMessage)) + defaultRealtimeObjects.ObjectsManager.handleObjectMessages(listOf(objectMessage)) } // Create test ObjectMessage for OBJECT_SYNC action @@ -148,23 +148,23 @@ class DefaultLiveObjectsTest { state = arrayOf(objectSyncMessage) } // Test OBJECT_SYNC action delegation - defaultLiveObjects.handle(objectSyncProtocolMessage) + defaultRealtimeObjects.handle(objectSyncProtocolMessage) // Verify that handleObjectSyncMessages was called with the correct parameters verify(exactly = 1) { - defaultLiveObjects.ObjectsManager.handleObjectSyncMessages(listOf(objectSyncMessage), "syncChannelSerial1") + defaultRealtimeObjects.ObjectsManager.handleObjectSyncMessages(listOf(objectSyncMessage), "syncChannelSerial1") } } @Test fun `(OM2) Populate objectMessage missing id, timestamp and connectionId from protocolMessage`() = runTest { - val defaultLiveObjects = getDefaultLiveObjectsWithMockedDeps() + val defaultRealtimeObjects = getDefaultRealtimeObjectsWithMockedDeps() // Capture the ObjectMessages that are passed to ObjectsManager methods var capturedObjectMessages: List? = null var capturedObjectSyncMessages: List? = null // Mock the ObjectsManager to capture the messages - defaultLiveObjects.ObjectsManager.apply { + defaultRealtimeObjects.ObjectsManager.apply { every { handleObjectMessages(any>()) } answers { capturedObjectMessages = firstArg() } @@ -191,7 +191,7 @@ class DefaultLiveObjectsTest { } // Test OBJECT action - should populate missing fields - defaultLiveObjects.handle(objectProtocolMessage) + defaultRealtimeObjects.handle(objectProtocolMessage) // Verify that the captured ObjectMessage has populated fields assertWaiter { capturedObjectMessages != null } @@ -221,7 +221,7 @@ class DefaultLiveObjectsTest { } // Test OBJECT_SYNC action - should populate missing fields - defaultLiveObjects.handle(objectSyncProtocolMessage) + defaultRealtimeObjects.handle(objectSyncProtocolMessage) // Verify that the captured ObjectMessage has populated fields assertWaiter { capturedObjectSyncMessages != null } diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/ObjectsManagerTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/ObjectsManagerTest.kt index ff9c621cd..3e04d9e06 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/ObjectsManagerTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/ObjectsManagerTest.kt @@ -7,7 +7,7 @@ import io.ably.lib.objects.ObjectsState import io.ably.lib.objects.type.livecounter.DefaultLiveCounter import io.ably.lib.objects.type.livemap.DefaultLiveMap import io.ably.lib.objects.unit.* -import io.ably.lib.objects.unit.getDefaultLiveObjectsWithMockedDeps +import io.ably.lib.objects.unit.getDefaultRealtimeObjectsWithMockedDeps import io.mockk.* import org.junit.Test import kotlin.test.* @@ -16,15 +16,15 @@ class ObjectsManagerTest { @Test fun `(RTO5) ObjectsManager should handle object sync messages`() { - val defaultLiveObjects = getDefaultLiveObjectsWithMockedDeps() - assertEquals(ObjectsState.Initialized, defaultLiveObjects.state, "Initial state should be INITIALIZED") + val defaultRealtimeObjects = getDefaultRealtimeObjectsWithMockedDeps() + assertEquals(ObjectsState.Initialized, defaultRealtimeObjects.state, "Initial state should be INITIALIZED") - val objectsManager = defaultLiveObjects.ObjectsManager + val objectsManager = defaultRealtimeObjects.ObjectsManager mockZeroValuedObjects() // Populate objectsPool with existing objects - val objectsPool = defaultLiveObjects.ObjectsPool + val objectsPool = defaultRealtimeObjects.ObjectsPool objectsPool.set("map:testObject@1", mockk(relaxed = true)) objectsPool.set("counter:testObject@4", mockk(relaxed = true)) @@ -35,7 +35,7 @@ class ObjectsManagerTest { objectId = "map:testObject@1", // already exists in pool tombstone = false, siteTimeserials = mapOf("site1" to "syncSerial1"), - map = ObjectMap(), + map = ObjectsMap(), ) ) val objectMessage2 = ObjectMessage( @@ -44,7 +44,7 @@ class ObjectsManagerTest { objectId = "counter:testObject@2", // Does not exist in pool tombstone = false, siteTimeserials = mapOf("site1" to "syncSerial1"), - counter = ObjectCounter(count = 20.0) + counter = ObjectsCounter(count = 20.0) ) ) val objectMessage3 = ObjectMessage( @@ -53,7 +53,7 @@ class ObjectsManagerTest { objectId = "map:testObject@3", // Does not exist in pool tombstone = false, siteTimeserials = mapOf("site1" to "syncSerial1"), - map = ObjectMap(), + map = ObjectsMap(), ) ) // Should start and end sync, apply object states, and create new objects for missing ones @@ -72,7 +72,7 @@ class ObjectsManagerTest { assertEquals("counter:testObject@2", newlyCreatedObjects[0].objectId) assertEquals("map:testObject@3", newlyCreatedObjects[1].objectId) - assertEquals(ObjectsState.Synced, defaultLiveObjects.state, "State should be SYNCED after sync sequence") + assertEquals(ObjectsState.Synced, defaultRealtimeObjects.state, "State should be SYNCED after sync sequence") // After sync `counter:testObject@4` will be removed from pool assertNull(objectsPool.get("counter:testObject@4")) assertEquals(4, objectsPool.size(), "Objects pool should contain 4 objects after sync including root") @@ -96,15 +96,15 @@ class ObjectsManagerTest { @Test fun `(RTO8) ObjectsManager should apply object operation when state is synced`() { - val defaultLiveObjects = getDefaultLiveObjectsWithMockedDeps() - defaultLiveObjects.state = ObjectsState.Synced // Ensure we're in SYNCED state + val defaultRealtimeObjects = getDefaultRealtimeObjectsWithMockedDeps() + defaultRealtimeObjects.state = ObjectsState.Synced // Ensure we're in SYNCED state - val objectsManager = defaultLiveObjects.ObjectsManager + val objectsManager = defaultRealtimeObjects.ObjectsManager mockZeroValuedObjects() // Populate objectsPool with existing objects - val objectsPool = defaultLiveObjects.ObjectsPool + val objectsPool = defaultRealtimeObjects.ObjectsPool objectsPool.set("map:testObject@1", mockk(relaxed = true)) // Incoming object messages with operation field instead of objectState @@ -164,26 +164,26 @@ class ObjectsManagerTest { @Test fun `(RTO7) ObjectsManager should buffer operations when not in sync, apply them after synced`() { - val defaultLiveObjects = getDefaultLiveObjectsWithMockedDeps() - assertEquals(ObjectsState.Initialized, defaultLiveObjects.state, "Initial state should be INITIALIZED") + val defaultRealtimeObjects = getDefaultRealtimeObjectsWithMockedDeps() + assertEquals(ObjectsState.Initialized, defaultRealtimeObjects.state, "Initial state should be INITIALIZED") - val objectsManager = defaultLiveObjects.ObjectsManager + val objectsManager = defaultRealtimeObjects.ObjectsManager assertEquals(0, objectsManager.BufferedObjectOperations.size, "RTO7a1 - Initial buffer should be empty") - val objectsPool = defaultLiveObjects.ObjectsPool + val objectsPool = defaultRealtimeObjects.ObjectsPool assertEquals(1, objectsPool.size(), "RTO7a2 - Initial pool should contain only root object") mockZeroValuedObjects() // Set state to SYNCING - defaultLiveObjects.state = ObjectsState.Syncing + defaultRealtimeObjects.state = ObjectsState.Syncing val objectMessage = ObjectMessage( id = "testId", operation = ObjectOperation( action = ObjectOperationAction.CounterCreate, objectId = "counter:testObject@1", - counterOp = ObjectCounterOp(amount = 5.0) + counterOp = ObjectsCounterOp(amount = 5.0) ), serial = "serial1", siteCode = "site1" @@ -213,13 +213,13 @@ class ObjectsManagerTest { private fun mockZeroValuedObjects() { mockkObject(DefaultLiveMap.Companion) every { - DefaultLiveMap.zeroValue(any(), any()) + DefaultLiveMap.zeroValue(any(), any()) } answers { mockk(relaxed = true) } mockkObject(DefaultLiveCounter.Companion) every { - DefaultLiveCounter.zeroValue(any(), any()) + DefaultLiveCounter.zeroValue(any(), any()) } answers { mockk(relaxed = true) } diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/ObjectsPoolTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/ObjectsPoolTest.kt index 1d1bcb8aa..656b1e7c1 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/ObjectsPoolTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/objects/ObjectsPoolTest.kt @@ -1,6 +1,6 @@ package io.ably.lib.objects.unit.objects -import io.ably.lib.objects.DefaultLiveObjects +import io.ably.lib.objects.DefaultRealtimeObjects import io.ably.lib.objects.ObjectData import io.ably.lib.objects.ROOT_OBJECT_ID import io.ably.lib.objects.type.livecounter.DefaultLiveCounter @@ -19,8 +19,8 @@ class ObjectsPoolTest { @Test fun `(RTO3, RTO3a, RTO3b) An internal ObjectsPool should be used to maintain the list of objects present on a channel`() { - val defaultLiveObjects = DefaultLiveObjects("dummyChannel", mockk(relaxed = true)) - val objectsPool = defaultLiveObjects.objectsPool + val defaultRealtimeObjects = DefaultRealtimeObjects("dummyChannel", mockk(relaxed = true)) + val objectsPool = defaultRealtimeObjects.objectsPool assertNotNull(objectsPool) // RTO3b - It must always contain a LiveMap object with id root @@ -31,7 +31,7 @@ class ObjectsPoolTest { assertEquals(ROOT_OBJECT_ID, rootLiveMap.objectId) assertEquals(1, objectsPool.size(), "RTO3 - Should only contain the root object initially") - // RTO3a - ObjectsPool is a Dict, a map of LiveObjects keyed by objectId string + // RTO3a - ObjectsPool is a Dict, a map of RealtimeObjects keyed by objectId string val testLiveMap = DefaultLiveMap.zeroValue("map:testObject@1", mockk(relaxed = true)) objectsPool.set("map:testObject@1", testLiveMap) val testLiveCounter = DefaultLiveCounter.zeroValue("counter:testObject@1", mockk(relaxed = true)) @@ -44,8 +44,8 @@ class ObjectsPoolTest { @Test fun `(RTO6) ObjectsPool should create zero-value objects if not exists`() { - val defaultLiveObjects = DefaultLiveObjects("dummyChannel", mockk(relaxed = true)) - val objectsPool = spyk(defaultLiveObjects.objectsPool) + val defaultRealtimeObjects = DefaultRealtimeObjects("dummyChannel", mockk(relaxed = true)) + val objectsPool = spyk(defaultRealtimeObjects.objectsPool) assertEquals(1, objectsPool.size(), "RTO3 - Should only contain the root object initially") // Test creating zero-value map @@ -78,8 +78,8 @@ class ObjectsPoolTest { @Test fun `(RTO4b1, RTO4b2) ObjectsPool should reset to initial pool retaining original root map`() { - val defaultLiveObjects = DefaultLiveObjects("dummyChannel", mockk(relaxed = true)) - val objectsPool = defaultLiveObjects.objectsPool + val defaultRealtimeObjects = DefaultRealtimeObjects("dummyChannel", mockk(relaxed = true)) + val objectsPool = defaultRealtimeObjects.objectsPool assertEquals(1, objectsPool.size()) val rootMap = objectsPool.get(ROOT_OBJECT_ID) as DefaultLiveMap // add some data to the root map @@ -107,8 +107,8 @@ class ObjectsPoolTest { @Test fun `(RTO5c2, RTO5c2a) ObjectsPool should delete extra object IDs`() { - val defaultLiveObjects = DefaultLiveObjects("dummyChannel", mockk(relaxed = true)) - val objectsPool = defaultLiveObjects.objectsPool + val defaultRealtimeObjects = DefaultRealtimeObjects("dummyChannel", mockk(relaxed = true)) + val objectsPool = defaultRealtimeObjects.objectsPool // Add some objects objectsPool.set("counter:testObject@1", DefaultLiveCounter.zeroValue("counter:testObject@1", mockk(relaxed = true))) diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseRealtimeObjectTest.kt similarity index 75% rename from live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt rename to live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseRealtimeObjectTest.kt index ee6673c3d..9868bf680 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseLiveObjectTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/BaseRealtimeObjectTest.kt @@ -1,37 +1,37 @@ package io.ably.lib.objects.unit.type import io.ably.lib.objects.* -import io.ably.lib.objects.type.BaseLiveObject +import io.ably.lib.objects.type.BaseRealtimeObject import io.ably.lib.objects.type.livecounter.DefaultLiveCounter import io.ably.lib.objects.type.livemap.DefaultLiveMap -import io.ably.lib.objects.unit.getDefaultLiveObjectsWithMockedDeps +import io.ably.lib.objects.unit.getDefaultRealtimeObjectsWithMockedDeps import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue import kotlin.test.assertFailsWith -class BaseLiveObjectTest { +class BaseRealtimeObjectTest { - private val defaultLiveObjects = getDefaultLiveObjectsWithMockedDeps() + private val defaultRealtimeObjects = getDefaultRealtimeObjectsWithMockedDeps() @Test - fun `(RTLO1, RTLO2) BaseLiveObject should be abstract base class for LiveMap and LiveCounter`() { - // RTLO2 - Check that BaseLiveObject is abstract - val isAbstract = java.lang.reflect.Modifier.isAbstract(BaseLiveObject::class.java.modifiers) - assertTrue(isAbstract, "BaseLiveObject should be an abstract class") - - // RTLO1 - Check that BaseLiveObject is the parent class of DefaultLiveMap and DefaultLiveCounter - assertTrue(BaseLiveObject::class.java.isAssignableFrom(DefaultLiveMap::class.java), - "DefaultLiveMap should extend BaseLiveObject") - assertTrue(BaseLiveObject::class.java.isAssignableFrom(DefaultLiveCounter::class.java), - "DefaultLiveCounter should extend BaseLiveObject") + fun `(RTLO1, RTLO2) BaseRealtimeObject should be abstract base class for LiveMap and LiveCounter`() { + // RTLO2 - Check that BaseRealtimeObject is abstract + val isAbstract = java.lang.reflect.Modifier.isAbstract(BaseRealtimeObject::class.java.modifiers) + assertTrue(isAbstract, "BaseRealtimeObject should be an abstract class") + + // RTLO1 - Check that BaseRealtimeObject is the parent class of DefaultLiveMap and DefaultLiveCounter + assertTrue(BaseRealtimeObject::class.java.isAssignableFrom(DefaultLiveMap::class.java), + "DefaultLiveMap should extend BaseRealtimeObject") + assertTrue(BaseRealtimeObject::class.java.isAssignableFrom(DefaultLiveCounter::class.java), + "DefaultLiveCounter should extend BaseRealtimeObject") } @Test - fun `(RTLO3) BaseLiveObject should have required properties`() { - val liveMap: BaseLiveObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultLiveObjects) - val liveCounter: BaseLiveObject = DefaultLiveCounter.zeroValue("counter:testObject@1", defaultLiveObjects) + fun `(RTLO3) BaseRealtimeObject should have required properties`() { + val liveMap: BaseRealtimeObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultRealtimeObjects) + val liveCounter: BaseRealtimeObject = DefaultLiveCounter.zeroValue("counter:testObject@1", defaultRealtimeObjects) // RTLO3a - check that objectId is set correctly assertEquals("map:testObject@1", liveMap.objectId) assertEquals("counter:testObject@1", liveCounter.objectId) @@ -48,7 +48,7 @@ class BaseLiveObjectTest { @Test fun `(RTLO4a1, RTLO4a2) canApplyOperation should accept ObjectMessage params and return boolean`() { // RTLO4a1a - Assert parameter types and return type based on method signature using reflection - val method = BaseLiveObject::class.java.findMethod("canApplyOperation") + val method = BaseRealtimeObject::class.java.findMethod("canApplyOperation") // RTLO4a1a - Verify parameter types val parameters = method.parameters @@ -68,7 +68,7 @@ class BaseLiveObjectTest { @Test fun `(RTLO4a3) canApplyOperation should throw error for null or empty incoming siteSerial`() { - val liveMap: BaseLiveObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultLiveObjects) + val liveMap: BaseRealtimeObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultRealtimeObjects) // Test null serial assertFailsWith("Should throw error for null serial") { @@ -93,7 +93,7 @@ class BaseLiveObjectTest { @Test fun `(RTLO4a4, RTLO4a5) canApplyOperation should return true when existing siteSerial is null or empty`() { - val liveMap: BaseLiveObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultLiveObjects) + val liveMap: BaseRealtimeObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultRealtimeObjects) assertTrue(liveMap.siteTimeserials.isEmpty(), "Initial siteTimeserials should be empty") // RTLO4a4 - Get siteSerial from siteTimeserials map @@ -109,7 +109,7 @@ class BaseLiveObjectTest { @Test fun `(RTLO4a6) canApplyOperation should return true when message siteSerial is greater than existing siteSerial`() { - val liveMap: BaseLiveObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultLiveObjects) + val liveMap: BaseRealtimeObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultRealtimeObjects) // Set existing siteSerial liveMap.siteTimeserials["site1"] = "serial1" @@ -127,7 +127,7 @@ class BaseLiveObjectTest { @Test fun `(RTLO4a6) canApplyOperation should return false when message siteSerial is less than or equal to siteSerial`() { - val liveMap: BaseLiveObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultLiveObjects) + val liveMap: BaseRealtimeObject = DefaultLiveMap.zeroValue("map:testObject@1", defaultRealtimeObjects) // Set existing siteSerial liveMap.siteTimeserials["site1"] = "serial2" @@ -147,7 +147,7 @@ class BaseLiveObjectTest { @Test fun `(RTLO4a) canApplyOperation should work with different site codes`() { - val liveMap: BaseLiveObject = DefaultLiveCounter.zeroValue("counter:testObject@1", defaultLiveObjects) + val liveMap: BaseRealtimeObject = DefaultLiveCounter.zeroValue("counter:testObject@1", defaultRealtimeObjects) // Set serials for different sites liveMap.siteTimeserials["site1"] = "serial1" diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/DefaultLiveCounterTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/DefaultLiveCounterTest.kt index 76902ef3e..77576a907 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/DefaultLiveCounterTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/DefaultLiveCounterTest.kt @@ -1,6 +1,6 @@ package io.ably.lib.objects.unit.type.livecounter -import io.ably.lib.objects.ObjectCounter +import io.ably.lib.objects.ObjectsCounter import io.ably.lib.objects.ObjectMessage import io.ably.lib.objects.ObjectOperation import io.ably.lib.objects.ObjectOperationAction @@ -26,14 +26,14 @@ class DefaultLiveCounterTest { siteTimeserials = mapOf("site3" to "serial3", "site4" to "serial4"), tombstone = false, ) - + val objectMessage = ObjectMessage( id = "testId", objectState = objectState, serial = "serial1", siteCode = "site1" ) - + liveCounter.applyObjectSync(objectMessage) assertEquals(mapOf("site3" to "serial3", "site4" to "serial4"), liveCounter.siteTimeserials) // RTLC6a } @@ -45,7 +45,7 @@ class DefaultLiveCounterTest { val operation = ObjectOperation( action = ObjectOperationAction.CounterCreate, objectId = "counter:testCounter@2", // Different objectId - counter = ObjectCounter(count = 20.0) + counter = ObjectsCounter(count = 20.0) ) val message = ObjectMessage( @@ -77,7 +77,7 @@ class DefaultLiveCounterTest { val operation = ObjectOperation( action = ObjectOperationAction.CounterCreate, objectId = "counter:testCounter@1", // Matching objectId - counter = ObjectCounter(count = 20.0) + counter = ObjectsCounter(count = 20.0) ) val message = ObjectMessage( @@ -104,7 +104,7 @@ class DefaultLiveCounterTest { val operation = ObjectOperation( action = ObjectOperationAction.CounterCreate, objectId = "counter:testCounter@1", // Matching objectId - counter = ObjectCounter(count = 20.0) + counter = ObjectsCounter(count = 20.0) ) val message = ObjectMessage( diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt index 88bc6b738..6c1e49748 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livecounter/LiveCounterManagerTest.kt @@ -20,7 +20,7 @@ class DefaultLiveCounterManagerTest { val objectState = ObjectState( objectId = "testCounterId", - counter = ObjectCounter(count = 25.0), + counter = ObjectsCounter(count = 25.0), siteTimeserials = mapOf("site3" to "serial3", "site4" to "serial4"), tombstone = false, ) @@ -44,12 +44,12 @@ class DefaultLiveCounterManagerTest { val createOp = ObjectOperation( action = ObjectOperationAction.CounterCreate, objectId = "testCounterId", - counter = ObjectCounter(count = 10.0) + counter = ObjectsCounter(count = 10.0) ) val objectState = ObjectState( objectId = "testCounterId", - counter = ObjectCounter(count = 15.0), + counter = ObjectsCounter(count = 15.0), createOp = createOp, siteTimeserials = mapOf("site1" to "serial1"), tombstone = false, @@ -71,7 +71,7 @@ class DefaultLiveCounterManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapCreate, // Unsupported action for counter objectId = "testCounterId", - map = ObjectMap(semantics = MapSemantics.LWW, entries = emptyMap()) + map = ObjectsMap(semantics = ObjectsMapSemantics.LWW, entries = emptyMap()) ) // RTLC7d3 - Should throw error for unsupported action @@ -93,7 +93,7 @@ class DefaultLiveCounterManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.CounterCreate, objectId = "testCounterId", - counter = ObjectCounter(count = 20.0) + counter = ObjectsCounter(count = 20.0) ) // RTLC7d1 - Apply counter create operation @@ -116,7 +116,7 @@ class DefaultLiveCounterManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.CounterCreate, objectId = "testCounterId", - counter = ObjectCounter(count = 20.0) + counter = ObjectsCounter(count = 20.0) ) // RTLC8b - Should skip if already merged @@ -139,7 +139,7 @@ class DefaultLiveCounterManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.CounterCreate, objectId = "testCounterId", - counter = ObjectCounter(count = 20.0) + counter = ObjectsCounter(count = 20.0) ) // RTLC8c - Should apply if not merged @@ -183,7 +183,7 @@ class DefaultLiveCounterManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.CounterInc, objectId = "testCounterId", - counterOp = ObjectCounterOp(amount = 5.0) + counterOp = ObjectsCounterOp(amount = 5.0) ) // RTLC7d2 - Apply counter increment operation @@ -223,7 +223,7 @@ class DefaultLiveCounterManagerTest { // Set initial data liveCounter.data.set(10.0) - val counterOp = ObjectCounterOp(amount = 7.0) + val counterOp = ObjectsCounterOp(amount = 7.0) // RTLC9b - Apply counter increment liveCounterManager.applyOperation(ObjectOperation( @@ -243,7 +243,7 @@ class DefaultLiveCounterManagerTest { // Set initial data liveCounter.data.set(10.0) - val counterOp = ObjectCounterOp(amount = null) // Null amount + val counterOp = ObjectsCounterOp(amount = null) // Null amount // RTLC9b - Apply counter increment with null amount liveCounterManager.applyOperation(ObjectOperation( diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/DefaultLiveMapTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/DefaultLiveMapTest.kt index 2f31e597e..783cfe928 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/DefaultLiveMapTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/DefaultLiveMapTest.kt @@ -1,7 +1,7 @@ package io.ably.lib.objects.unit.type.livemap -import io.ably.lib.objects.MapSemantics -import io.ably.lib.objects.ObjectMap +import io.ably.lib.objects.ObjectsMapSemantics +import io.ably.lib.objects.ObjectsMap import io.ably.lib.objects.ObjectState import io.ably.lib.objects.ObjectMessage import io.ably.lib.objects.ObjectOperation @@ -26,18 +26,18 @@ class DefaultLiveMapTest { objectId = "map:testMap@1", siteTimeserials = mapOf("site3" to "serial3", "site4" to "serial4"), tombstone = false, - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, ) ) - + val objectMessage = ObjectMessage( id = "testId", objectState = objectState, serial = "serial1", siteCode = "site1" ) - + liveMap.applyObjectSync(objectMessage) assertEquals(mapOf("site3" to "serial3", "site4" to "serial4"), liveMap.siteTimeserials) // RTLM6a } @@ -49,8 +49,8 @@ class DefaultLiveMapTest { val operation = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "map:testMap@2", // Different objectId - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = emptyMap() ) ) @@ -84,8 +84,8 @@ class DefaultLiveMapTest { val operation = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "map:testMap@1", // Matching objectId - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = emptyMap() ) ) @@ -114,8 +114,8 @@ class DefaultLiveMapTest { val operation = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "map:testMap@1", // Matching objectId - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = emptyMap() ) ) diff --git a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt index eb79fa997..8f5e37bbd 100644 --- a/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt +++ b/live-objects/src/test/kotlin/io/ably/lib/objects/unit/type/livemap/LiveMapManagerTest.kt @@ -31,14 +31,14 @@ class LiveMapManagerTest { val objectState = ObjectState( objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = mapOf( - "key1" to ObjectMapEntry( + "key1" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("newValue1")), timeserial = "serial1" ), - "key2" to ObjectMapEntry( + "key2" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("value2")), timeserial = "serial2" ) @@ -77,8 +77,8 @@ class LiveMapManagerTest { val objectState = ObjectState( objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = emptyMap() // Empty map entries ), siteTimeserials = mapOf("site1" to "serial1"), @@ -139,14 +139,14 @@ class LiveMapManagerTest { val createOp = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = mapOf( - "key1" to ObjectMapEntry( + "key1" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("createValue")), timeserial = "serial1" ), - "key2" to ObjectMapEntry( + "key2" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("newValue")), timeserial = "serial2" ) @@ -156,10 +156,10 @@ class LiveMapManagerTest { val objectState = ObjectState( objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = mapOf( - "key1" to ObjectMapEntry( + "key1" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("stateValue")), timeserial = "serial3" ) @@ -200,16 +200,16 @@ class LiveMapManagerTest { val expectedTimestamp = 1234567890L val objectState = ObjectState( objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = mapOf( - "key1" to ObjectMapEntry( + "key1" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("newValue")), timeserial = "serial1", tombstone = true, serialTimestamp = expectedTimestamp ), - "key2" to ObjectMapEntry( + "key2" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("value2")), timeserial = "serial2" ) @@ -249,16 +249,16 @@ class LiveMapManagerTest { val objectState = ObjectState( objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = mapOf( - "key1" to ObjectMapEntry( + "key1" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("newValue")), timeserial = "serial1", tombstone = true, serialTimestamp = null // No timestamp provided ), - "key2" to ObjectMapEntry( + "key2" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("value2")), timeserial = "serial2" ) @@ -297,14 +297,14 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = mapOf( - "key1" to ObjectMapEntry( + "key1" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("value1")), timeserial = "serial1" ), - "key2" to ObjectMapEntry( + "key2" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("value2")), timeserial = "serial2" ) @@ -337,20 +337,20 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = mapOf( - "key1" to ObjectMapEntry( + "key1" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("createValue")), timeserial = "serial2", tombstone = true, serialTimestamp = expectedTimestamp ), - "key2" to ObjectMapEntry( + "key2" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("newValue")), timeserial = "serial3" ), - "key3" to ObjectMapEntry( + "key3" to ObjectsMapEntry( data = null, timeserial = "serial4", tombstone = true @@ -385,7 +385,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = "map:testMap@1", - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "key1", data = ObjectData(value = ObjectValue.String("newValue")) ) @@ -414,7 +414,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapRemove, objectId = "map:testMap@1", - mapOp = ObjectMapOp(key = "key1") + mapOp = ObjectsMapOp(key = "key1") ) val expectedTimestamp = 1234567890L @@ -442,7 +442,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapRemove, objectId = "map:testMap@1", - mapOp = ObjectMapOp(key = "key1") + mapOp = ObjectsMapOp(key = "key1") ) val beforeOperation = System.currentTimeMillis() @@ -466,7 +466,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.CounterCreate, // Unsupported action for map objectId = "map:testMap@1", - counter = ObjectCounter(count = 20.0) + counter = ObjectsCounter(count = 20.0) ) // RTLM15d4 - Should throw error for unsupported action @@ -491,10 +491,10 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = mapOf( - "key1" to ObjectMapEntry( + "key1" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("value1")), timeserial = "serial1" ) @@ -526,18 +526,18 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.LWW, + map = ObjectsMap( + semantics = ObjectsMapSemantics.LWW, entries = mapOf( - "key1" to ObjectMapEntry( + "key1" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("createValue")), timeserial = "serial2" ), - "key2" to ObjectMapEntry( + "key2" to ObjectsMapEntry( data = ObjectData(value = ObjectValue.String("newValue")), timeserial = "serial3" ), - "key3" to ObjectMapEntry( + "key3" to ObjectsMapEntry( data = null, timeserial = "serial4", tombstone = true @@ -564,7 +564,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = "map:testMap@1", - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "newKey", data = ObjectData(value = ObjectValue.String("newValue")) ) @@ -594,7 +594,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = "map:testMap@1", - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "key1", data = ObjectData(value = ObjectValue.String("newValue")) ) @@ -615,7 +615,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapRemove, objectId = "map:testMap@1", - mapOp = ObjectMapOp(key = "nonExistingKey") + mapOp = ObjectsMapOp(key = "nonExistingKey") ) // RTLM8b - Create tombstoned entry for non-existing key @@ -642,7 +642,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapRemove, objectId = "map:testMap@1", - mapOp = ObjectMapOp(key = "key1") + mapOp = ObjectsMapOp(key = "key1") ) // RTLM8a - Should skip operation with lower serial @@ -668,7 +668,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = "map:testMap@1", - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "key1", data = ObjectData(value = ObjectValue.String("newValue")) ) @@ -695,7 +695,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = "map:testMap@1", - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "key1", data = ObjectData(value = ObjectValue.String("newValue")) ) @@ -723,7 +723,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = "map:testMap@1", - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "key1", data = ObjectData(value = ObjectValue.String("newValue")) ) @@ -751,7 +751,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = "map:testMap@1", - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "key1", data = ObjectData(value = ObjectValue.String("newValue")) ) @@ -779,7 +779,7 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapSet, objectId = "map:testMap@1", - mapOp = ObjectMapOp( + mapOp = ObjectsMapOp( key = "key1", data = ObjectData(value = ObjectValue.String("newValue")) ) @@ -800,8 +800,8 @@ class LiveMapManagerTest { val operation = ObjectOperation( action = ObjectOperationAction.MapCreate, objectId = "map:testMap@1", - map = ObjectMap( - semantics = MapSemantics.Unknown, // This should match, but we'll test error case + map = ObjectsMap( + semantics = ObjectsMapSemantics.Unknown, // This should match, but we'll test error case entries = emptyMap() ) )