Skip to content

Commit 8264313

Browse files
committed
Refactored/Updated public API types as per spec
1 parent e226ba4 commit 8264313

49 files changed

Lines changed: 1658 additions & 173 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.ably.lib.object;
2+
3+
/**
4+
* Represents a registration for receiving events from a subscribe operation.
5+
* Provides a way to clean up and remove a subscription when it is no longer
6+
* needed.
7+
*
8+
* <p>Example usage:
9+
* <pre>
10+
* {@code
11+
* Subscription s = pathObject.subscribe(event -> { ... });
12+
* // Later, when done with the subscription
13+
* s.unsubscribe();
14+
* }
15+
* </pre>
16+
*
17+
* <p>Spec: SUB1
18+
*/
19+
public interface Subscription {
20+
21+
/**
22+
* Deregisters the listener that was registered by the corresponding
23+
* {@code subscribe} call. Once called, the listener will not be invoked for
24+
* any subsequent events and references to it are cleaned up. Calling this
25+
* method more than once is a no-op.
26+
*
27+
* <p>Spec: SUB2a, SUB2b
28+
*/
29+
void unsubscribe();
30+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
11
package io.ably.lib.object;
22

3+
/**
4+
* The type of a value resolved by a {@code PathObject} or wrapped by an
5+
* {@code Instance} in the LiveObjects graph.
6+
*
7+
* <p>Spec: RTTS2
8+
*/
39
public enum ValueType {
10+
/** Corresponds to the {@code String} primitive. Spec: RTTS2a1 */
411
STRING,
12+
/** Corresponds to the {@code Number} primitive. Spec: RTTS2a2 */
513
NUMBER,
14+
/** Corresponds to the {@code Boolean} primitive. Spec: RTTS2a3 */
615
BOOLEAN,
16+
/** Corresponds to the {@code Binary} primitive. Spec: RTTS2a4 */
717
BINARY,
18+
/** Corresponds to the {@code JsonObject} primitive. Spec: RTTS2a5 */
819
JSON_OBJECT,
20+
/** Corresponds to the {@code JsonArray} primitive. Spec: RTTS2a6 */
921
JSON_ARRAY,
22+
/** Corresponds to a {@code LiveMap} object. Spec: RTTS2a7 */
1023
LIVE_MAP,
24+
/** Corresponds to a {@code LiveCounter} object. Spec: RTTS2a8 */
1125
LIVE_COUNTER,
26+
/** Returned when path resolution fails or the resolved value has none of the known types; never produced by an {@code Instance} in normal operation. Spec: RTTS2a9 */
1227
UNKNOWN,
1328
}

lib/src/main/java/io/ably/lib/object/instance/Instance.java

Lines changed: 42 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,40 @@
1010
import io.ably.lib.object.instance.types.LiveMapInstance;
1111
import io.ably.lib.object.instance.types.NumberInstance;
1212
import io.ably.lib.object.instance.types.StringInstance;
13-
import io.ably.lib.objects.ObjectsSubscription;
14-
import org.jetbrains.annotations.NonBlocking;
1513
import org.jetbrains.annotations.NotNull;
1614

1715
/**
18-
* A direct-reference view of a single LiveObject (a {@code LiveMap} or {@code LiveCounter})
19-
* or a primitive value. Unlike {@code PathObject}, which resolves a path lazily against
20-
* the LiveObjects graph at every call, an {@code Instance} is bound to a specific
21-
* underlying value and dereferenced in O(1).
16+
* A direct-reference view of a single resolved LiveObject ({@code LiveMap} or
17+
* {@code LiveCounter}) or primitive value.
2218
*
23-
* <p>Java exposes type-specific sub-types ({@link LiveMapInstance},
24-
* {@link LiveCounterInstance}, and the primitive {@code *Instance} types). Use the
25-
* {@code as*} helpers to obtain a sub-type wrapper without performing type validation.
26-
* Only {@link LiveMapInstance} and {@link LiveCounterInstance} expose an object id
27-
* (via their own {@code getId()} methods); primitive instances are anonymous.
19+
* <p>Unlike {@code PathObject}, which re-resolves its path on every call, an
20+
* {@code Instance} is identity-addressed: it is bound to a specific underlying value
21+
* and dereferenced in O(1), regardless of where that value sits in the graph. Read
22+
* operations validate the access API preconditions and fail with an
23+
* {@code AblyException} if they are not satisfied.
2824
*
29-
* <p>Spec: RTINS1
25+
* <p>This base type exposes only the methods whose behaviour is independent of the
26+
* wrapped type; everything else - including {@code subscribe} (RTTS7b) - is
27+
* partitioned onto the sub-types. Use the {@code as*} helpers to obtain a sub-type
28+
* view without type validation, or discriminate via {@link #getType()}.
29+
*
30+
* <p>Spec: RTINS1, RTTS7
31+
*
32+
* @see LiveMapInstance
33+
* @see LiveCounterInstance
34+
* @see InstanceListener
3035
*/
3136
public interface Instance {
3237

3338
/**
3439
* Returns the {@link ValueType} of the value wrapped by this instance. Use this
3540
* instead of dedicated {@code isLiveMap}/{@code isLiveCounter}/etc. checks.
3641
*
42+
* <p>An {@code Instance} is always constructed from a resolved value, so this never
43+
* returns {@link ValueType#UNKNOWN} in normal operation.
44+
*
45+
* <p>Spec: RTTS8a
46+
*
3747
* @return the wrapped value type
3848
*/
3949
@NotNull ValueType getType();
@@ -45,38 +55,24 @@ public interface Instance {
4555
* always bound to a resolved value, so this always returns a non-null result;
4656
* failures of the access API preconditions are signalled via {@code AblyException}.
4757
*
48-
* <p>Spec: RTINS11
58+
* <p>Spec: RTINS11 / RTINS11c (universal non-null invariant - Instance is bound
59+
* to an already-resolved value, so the path-resolution failure mode of
60+
* PathObject#compactJson does not apply) / RTTS7a (typed-SDK signature reflects
61+
* the universal invariant)
4962
*
5063
* @return the compacted JSON snapshot
5164
*/
5265
@NotNull JsonElement compactJson();
5366

54-
/**
55-
* Subscribes a listener for updates on the underlying LiveObject. The listener is
56-
* invoked whenever the wrapped object is changed by a local or remote operation.
57-
* Call {@link ObjectsSubscription#unsubscribe()} on the returned handle to stop
58-
* receiving events for this listener.
59-
*
60-
* <p>Subscribe is not supported on primitive instances; implementations may throw
61-
* when called on {@link NumberInstance}, {@link StringInstance},
62-
* {@link BooleanInstance}, {@link BinaryInstance}, {@link JsonObjectInstance} or
63-
* {@link JsonArrayInstance}.
64-
*
65-
* <p>Spec: RTINS16
66-
*
67-
* @param listener the listener to invoke on updates
68-
* @return a subscription handle that can be used to unsubscribe this listener
69-
*/
70-
@NonBlocking
71-
@NotNull ObjectsSubscription subscribe(@NotNull Listener listener);
72-
7367
/**
7468
* Returns this instance wrapped as a {@link LiveMapInstance}.
7569
*
7670
* <p>Best-effort cast; does not validate the underlying type. Read operations on
7771
* the returned wrapper are always permitted; write/terminal operations will fail
7872
* at call time if the wrapped value is not a {@code LiveMap}.
7973
*
74+
* <p>Spec: RTTS9a
75+
*
8076
* @return a {@link LiveMapInstance} view of this instance
8177
*/
8278
@NotNull LiveMapInstance asLiveMap();
@@ -85,6 +81,8 @@ public interface Instance {
8581
* Returns this instance wrapped as a {@link LiveCounterInstance}.
8682
* Best-effort cast; does not validate the underlying type.
8783
*
84+
* <p>Spec: RTTS9b
85+
*
8886
* @return a {@link LiveCounterInstance} view of this instance
8987
*/
9088
@NotNull LiveCounterInstance asLiveCounter();
@@ -93,6 +91,8 @@ public interface Instance {
9391
* Returns this instance wrapped as a {@link NumberInstance}.
9492
* Best-effort cast; does not validate the underlying type.
9593
*
94+
* <p>Spec: RTTS9c
95+
*
9696
* @return a {@link NumberInstance} view of this instance
9797
*/
9898
@NotNull NumberInstance asNumber();
@@ -101,6 +101,8 @@ public interface Instance {
101101
* Returns this instance wrapped as a {@link StringInstance}.
102102
* Best-effort cast; does not validate the underlying type.
103103
*
104+
* <p>Spec: RTTS9c
105+
*
104106
* @return a {@link StringInstance} view of this instance
105107
*/
106108
@NotNull StringInstance asString();
@@ -109,6 +111,8 @@ public interface Instance {
109111
* Returns this instance wrapped as a {@link BooleanInstance}.
110112
* Best-effort cast; does not validate the underlying type.
111113
*
114+
* <p>Spec: RTTS9c
115+
*
112116
* @return a {@link BooleanInstance} view of this instance
113117
*/
114118
@NotNull BooleanInstance asBoolean();
@@ -117,6 +121,8 @@ public interface Instance {
117121
* Returns this instance wrapped as a {@link BinaryInstance}.
118122
* Best-effort cast; does not validate the underlying type.
119123
*
124+
* <p>Spec: RTTS9c
125+
*
120126
* @return a {@link BinaryInstance} view of this instance
121127
*/
122128
@NotNull BinaryInstance asBinary();
@@ -125,6 +131,8 @@ public interface Instance {
125131
* Returns this instance wrapped as a {@link JsonObjectInstance}.
126132
* Best-effort cast; does not validate the underlying type.
127133
*
134+
* <p>Spec: RTTS9c
135+
*
128136
* @return a {@link JsonObjectInstance} view of this instance
129137
*/
130138
@NotNull JsonObjectInstance asJsonObject();
@@ -133,37 +141,9 @@ public interface Instance {
133141
* Returns this instance wrapped as a {@link JsonArrayInstance}.
134142
* Best-effort cast; does not validate the underlying type.
135143
*
144+
* <p>Spec: RTTS9c
145+
*
136146
* @return a {@link JsonArrayInstance} view of this instance
137147
*/
138148
@NotNull JsonArrayInstance asJsonArray();
139-
140-
/**
141-
* Listener interface for {@link Instance#subscribe(Listener) instance
142-
* subscriptions}.
143-
*
144-
* <p>Spec: RTINS16a1
145-
*/
146-
interface Listener {
147-
/**
148-
* Invoked when the wrapped LiveObject is modified.
149-
*
150-
* @param event the event describing the change
151-
*/
152-
void onUpdated(@NotNull SubscriptionEvent event);
153-
}
154-
155-
/**
156-
* Event delivered to {@link Listener#onUpdated(SubscriptionEvent)} when the wrapped
157-
* LiveObject is updated.
158-
*
159-
* <p>Spec: RTINS16e
160-
*/
161-
interface SubscriptionEvent {
162-
/**
163-
* Returns the {@link Instance} that was updated.
164-
*
165-
* @return the updated instance
166-
*/
167-
@NotNull Instance getInstance();
168-
}
169149
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.ably.lib.object.instance;
2+
3+
import io.ably.lib.object.instance.types.LiveCounterInstance;
4+
import io.ably.lib.object.instance.types.LiveMapInstance;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
/**
8+
* Listener interface for instance subscriptions created via
9+
* {@link LiveMapInstance#subscribe(InstanceListener)} or
10+
* {@link LiveCounterInstance#subscribe(InstanceListener)}.
11+
*
12+
* <p>Spec: RTINS16a1
13+
*/
14+
public interface InstanceListener {
15+
16+
/**
17+
* Invoked when the wrapped LiveObject is modified.
18+
*
19+
* @param event the event describing the change
20+
*/
21+
void onUpdated(@NotNull InstanceSubscriptionEvent event);
22+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.ably.lib.object.instance;
2+
3+
import io.ably.lib.object.instance.types.LiveCounterInstance;
4+
import io.ably.lib.object.instance.types.LiveMapInstance;
5+
import io.ably.lib.object.message.ObjectMessage;
6+
import org.jetbrains.annotations.NotNull;
7+
import org.jetbrains.annotations.Nullable;
8+
9+
/**
10+
* Event delivered to {@link InstanceListener#onUpdated(InstanceSubscriptionEvent)} when
11+
* the LiveObject wrapped by a subscribed {@link LiveMapInstance} or
12+
* {@link LiveCounterInstance} is updated.
13+
*
14+
* <p>Spec: RTINS16e
15+
*/
16+
public interface InstanceSubscriptionEvent {
17+
18+
/**
19+
* Returns an {@link Instance} wrapping the LiveObject that was updated.
20+
*
21+
* <p>Spec: RTINS16e1
22+
*
23+
* @return the updated instance
24+
*/
25+
@NotNull Instance getObject();
26+
27+
/**
28+
* Returns the {@link ObjectMessage} describing the operation that caused this
29+
* event, if any. The value is present whenever the underlying update carried an
30+
* object message with an operation; otherwise it is {@code null}.
31+
*
32+
* <p>Spec: RTINS16e2 / PAOM1
33+
*
34+
* @return the source {@code ObjectMessage}, or {@code null} if unavailable
35+
*/
36+
@Nullable ObjectMessage getMessage();
37+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* The identity-addressed view of the LiveObjects graph.
3+
* {@link io.ably.lib.object.instance.Instance} wraps a specific resolved
4+
* LiveObject or primitive value and dereferences it in O(1), following the
5+
* object wherever it sits in the graph. Type-specific operations live on the
6+
* sub-types in {@link io.ably.lib.object.instance.types}; instance
7+
* subscriptions use {@link io.ably.lib.object.instance.InstanceListener} and
8+
* {@link io.ably.lib.object.instance.InstanceSubscriptionEvent}.
9+
*
10+
* <p>Spec: RTINS1-RTINS16, RTTS7-RTTS9
11+
*/
12+
package io.ably.lib.object.instance;

lib/src/main/java/io/ably/lib/object/instance/types/BinaryInstance.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@
55

66
/**
77
* A read-only {@link Instance} bound to a binary primitive value
8-
* (a {@code byte[]}). Primitive instances are anonymous (no object id) and do not
9-
* support subscribe.
8+
* (a {@code byte[]}).
9+
* Primitive instances are anonymous (no object id) and deliberately do not expose
10+
* {@code subscribe}, {@code set}, {@code remove} or any other id/iteration/write
11+
* methods - only {@code value()} - per RTTS10c.
12+
*
13+
* <p>Spec: RTTS10c
1014
*/
1115
public interface BinaryInstance extends Instance {
1216

1317
/**
1418
* Returns the wrapped binary value.
1519
*
16-
* <p>Spec: RTINS4
20+
* <p>Spec: RTINS4 / RTTS10c
1721
*
1822
* @return the wrapped bytes
1923
*/

lib/src/main/java/io/ably/lib/object/instance/types/BooleanInstance.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55

66
/**
77
* A read-only {@link Instance} bound to a {@code Boolean} primitive value.
8-
* Primitive instances are anonymous (no object id) and do not support subscribe.
8+
* Primitive instances are anonymous (no object id) and deliberately do not expose
9+
* {@code subscribe}, {@code set}, {@code remove} or any other id/iteration/write
10+
* methods - only {@code value()} - per RTTS10c.
11+
*
12+
* <p>Spec: RTTS10c
913
*/
1014
public interface BooleanInstance extends Instance {
1115

1216
/**
1317
* Returns the wrapped boolean.
1418
*
15-
* <p>Spec: RTINS4
19+
* <p>Spec: RTINS4 / RTTS10c
1620
*
1721
* @return the wrapped boolean value
1822
*/

lib/src/main/java/io/ably/lib/object/instance/types/JsonArrayInstance.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@
66

77
/**
88
* A read-only {@link Instance} bound to a {@link JsonArray} primitive value.
9-
* Primitive instances are anonymous (no object id) and do not support subscribe.
9+
* Primitive instances are anonymous (no object id) and deliberately do not expose
10+
* {@code subscribe}, {@code set}, {@code remove} or any other id/iteration/write
11+
* methods - only {@code value()} - per RTTS10c.
12+
*
13+
* <p>Spec: RTTS10c
1014
*/
1115
public interface JsonArrayInstance extends Instance {
1216

1317
/**
1418
* Returns the wrapped JSON array.
1519
*
16-
* <p>Spec: RTINS4
20+
* <p>Spec: RTINS4 / RTTS10c
1721
*
1822
* @return the wrapped JsonArray value
1923
*/

0 commit comments

Comments
 (0)