Skip to content

Commit ef1e204

Browse files
authored
chore: commonizes several FDv2 related types in Common (#140)
This PR moves several types from java server to java common for re-use in Android SDK. ChangeSet has been made generic on the type of the data. There should be no behavioral changes due to this PR. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: this PR only adds new shared types/enums (no runtime logic changes) but may require downstream modules to update imports/types when adopting the new `ChangeSet<T>` API. > > **Overview** > **Commonizes FDv2 model types in `lib/shared/common`.** Adds a new `com.launchdarkly.sdk.fdv2` package with shared public types for FDv2 data sources. > > Introduces a generic `ChangeSet<T>` (with `ChangeSetType`, `Selector`, and persistence/environment metadata) plus enums `SourceResultType` and `SourceSignal`, and documents intended usage via `package-info.java`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 14c6425. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 823d276 commit ef1e204

6 files changed

Lines changed: 279 additions & 0 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package com.launchdarkly.sdk.fdv2;
2+
3+
import java.util.Objects;
4+
5+
/**
6+
* Represents a set of changes to apply to a data store.
7+
*
8+
* @param <T> the type of the data payload
9+
*/
10+
public final class ChangeSet<T> {
11+
private final ChangeSetType type;
12+
private final Selector selector;
13+
private final String environmentId;
14+
private final T data;
15+
private final boolean shouldPersist;
16+
17+
/**
18+
* Constructs a new ChangeSet.
19+
* <p>
20+
* When implementing a custom data source, pass {@link Selector#EMPTY} for the {@code selector}
21+
* parameter. Non-empty selectors are only meaningful for LaunchDarkly's own data sources.
22+
*
23+
* @param type the type of the changeset
24+
* @param selector the selector for this change; null is normalized to {@link Selector#EMPTY}
25+
* @param data the data payload
26+
* @param environmentId the environment ID, or null if not available
27+
* @param shouldPersist true if the data should be persisted to persistent stores
28+
*/
29+
public ChangeSet(ChangeSetType type, Selector selector, T data, String environmentId, boolean shouldPersist) {
30+
this.type = type;
31+
this.selector = selector != null ? selector : Selector.EMPTY;
32+
this.data = data;
33+
this.environmentId = environmentId;
34+
this.shouldPersist = shouldPersist;
35+
}
36+
37+
/**
38+
* Returns the type of the changeset.
39+
*
40+
* @return the changeset type
41+
*/
42+
public ChangeSetType getType() {
43+
return type;
44+
}
45+
46+
/**
47+
* Returns the selector for this change. Will not be null; may be {@link Selector#EMPTY}.
48+
*
49+
* @return the selector
50+
*/
51+
public Selector getSelector() {
52+
return selector;
53+
}
54+
55+
/**
56+
* Returns the environment ID associated with the change, or null if not available.
57+
*
58+
* @return the environment ID, or null
59+
*/
60+
public String getEnvironmentId() {
61+
return environmentId;
62+
}
63+
64+
/**
65+
* Returns the data payload for this changeset.
66+
*
67+
* @return the data
68+
*/
69+
public T getData() {
70+
return data;
71+
}
72+
73+
/**
74+
* Returns whether this data should be persisted to persistent stores.
75+
*
76+
* @return true if the data should be persisted, false otherwise
77+
*/
78+
public boolean shouldPersist() {
79+
return shouldPersist;
80+
}
81+
82+
@Override
83+
public boolean equals(Object o) {
84+
if (o instanceof ChangeSet<?>) {
85+
ChangeSet<?> other = (ChangeSet<?>) o;
86+
return type == other.type
87+
&& shouldPersist == other.shouldPersist
88+
&& Objects.equals(selector, other.selector)
89+
&& Objects.equals(environmentId, other.environmentId)
90+
&& Objects.equals(data, other.data);
91+
}
92+
return false;
93+
}
94+
95+
@Override
96+
public int hashCode() {
97+
return Objects.hash(type, selector, environmentId, data, shouldPersist);
98+
}
99+
100+
@Override
101+
public String toString() {
102+
return "ChangeSet(" + type + "," + selector + "," + environmentId + "," + data + "," + shouldPersist + ")";
103+
}
104+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.launchdarkly.sdk.fdv2;
2+
3+
/**
4+
* Indicates the type of a change set applied to a data store.
5+
*/
6+
public enum ChangeSetType {
7+
/**
8+
* Represents a full store update which replaces all data currently in the store.
9+
*/
10+
Full,
11+
12+
/**
13+
* Represents an incremental set of changes to be applied to the existing data in the store.
14+
*/
15+
Partial,
16+
17+
/**
18+
* Indicates that there are no changes; the changeset may still carry a selector to store.
19+
*/
20+
None
21+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.launchdarkly.sdk.fdv2;
2+
3+
import java.util.Objects;
4+
5+
/**
6+
* Identifies a specific version of data in the LaunchDarkly backend, used to request incremental
7+
* updates from a known point.
8+
* <p>
9+
* A selector is either empty ({@link #EMPTY}) or contains a version number and state string that
10+
* were provided by a LaunchDarkly data source. Empty selectors signal that the client has no
11+
* existing data and requires a full payload.
12+
* <p>
13+
* <strong>For SDK consumers implementing custom data sources:</strong> you should always use
14+
* {@link #EMPTY} when constructing a {@link ChangeSet}. Non-empty selectors are set by
15+
* LaunchDarkly's own data sources based on state received from the LaunchDarkly backend, and
16+
* are not meaningful when constructed externally.
17+
*/
18+
public final class Selector {
19+
private final boolean isEmpty;
20+
private final int version;
21+
private final String state;
22+
23+
private Selector(int version, String state, boolean isEmpty) {
24+
this.version = version;
25+
this.state = state;
26+
this.isEmpty = isEmpty;
27+
}
28+
29+
/**
30+
* If true, then this selector is empty. An empty selector cannot be used as a basis for
31+
* requesting incremental updates from a data source.
32+
*
33+
* @return whether the selector is empty
34+
*/
35+
public boolean isEmpty() {
36+
return isEmpty;
37+
}
38+
39+
/**
40+
* The version of the data associated with this selector.
41+
*
42+
* @return the version
43+
*/
44+
public int getVersion() {
45+
return version;
46+
}
47+
48+
/**
49+
* The state associated with the payload.
50+
*
51+
* @return the state identifier, or null if empty
52+
*/
53+
public String getState() {
54+
return state;
55+
}
56+
57+
static Selector empty() {
58+
return new Selector(0, null, true);
59+
}
60+
61+
/**
62+
* Creates a new Selector with the given version and state.
63+
* <p>
64+
* <strong>This method is intended for use by LaunchDarkly data sources only.</strong>
65+
* Custom data source implementations should use {@link #EMPTY} instead.
66+
*
67+
* @param version the version number
68+
* @param state the state identifier
69+
* @return a new Selector instance
70+
*/
71+
public static Selector make(int version, String state) {
72+
return new Selector(version, state, false);
73+
}
74+
75+
/**
76+
* An empty selector instance. Custom data source implementations should always use this
77+
* value when constructing a {@link ChangeSet}.
78+
*/
79+
public static final Selector EMPTY = empty();
80+
81+
@Override
82+
public boolean equals(Object o) {
83+
if (this == o) return true;
84+
if (!(o instanceof Selector)) return false;
85+
Selector other = (Selector) o;
86+
return isEmpty == other.isEmpty
87+
&& version == other.version
88+
&& Objects.equals(state, other.state);
89+
}
90+
91+
@Override
92+
public int hashCode() {
93+
return Objects.hash(isEmpty, version, state);
94+
}
95+
96+
@Override
97+
public String toString() {
98+
return isEmpty ? "Selector(empty)" : "Selector(" + version + "," + state + ")";
99+
}
100+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.launchdarkly.sdk.fdv2;
2+
3+
/**
4+
* Indicates whether an FDv2 source result carries a change set or a status update.
5+
*/
6+
public enum SourceResultType {
7+
/**
8+
* The source has emitted a change set. This implies that the source is in a valid state.
9+
*/
10+
CHANGE_SET,
11+
12+
/**
13+
* The source is emitting a status update, indicating a transition from being valid to being
14+
* in some kind of error or non-operational state. The source will emit a {@link #CHANGE_SET}
15+
* if it becomes valid again.
16+
*/
17+
STATUS,
18+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.launchdarkly.sdk.fdv2;
2+
3+
/**
4+
* Represents the state of an FDv2 data source when emitting a status result.
5+
*/
6+
public enum SourceSignal {
7+
/**
8+
* The data source has encountered an interruption and will attempt to reconnect. This is not
9+
* intended to be used with an initializer; use {@link #TERMINAL_ERROR} instead. When used with
10+
* an initializer it will still be treated as a terminal state.
11+
*/
12+
INTERRUPTED,
13+
14+
/**
15+
* The data source has been shut down and will not produce any further results.
16+
*/
17+
SHUTDOWN,
18+
19+
/**
20+
* The data source has encountered a terminal error and will not produce any further results.
21+
*/
22+
TERMINAL_ERROR,
23+
24+
/**
25+
* The data source has been instructed to disconnect (e.g. the server sent a goodbye message)
26+
* and will not produce any further results.
27+
*/
28+
GOODBYE,
29+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Types for the FDv2 (Flag Delivery v2).
3+
* <p>
4+
* This package contains the public types used by SDK data source implementations that support
5+
* the FDv2 data sources.
6+
*/
7+
package com.launchdarkly.sdk.fdv2;

0 commit comments

Comments
 (0)