Skip to content

Commit 5c0aaaa

Browse files
feat: implement domain scoping (#934)
* initial changes for implementing domain scoping Signed-off-by: jarebudev <[email protected]> * completed the rest of the renaming and tidying up Signed-off-by: jarebudev <[email protected]> * applied code review suggested changes Signed-off-by: jarebudev <[email protected]> * introdcue a dedicated interface for client metadata Signed-off-by: Kavindu Dodanduwa <[email protected]> * add deprecated default getName to be backward compatible as much as possible Signed-off-by: Kavindu Dodanduwa <[email protected]> --------- Signed-off-by: jarebudev <[email protected]> Signed-off-by: Kavindu Dodanduwa <[email protected]> Co-authored-by: Kavindu Dodanduwa <[email protected]> Co-authored-by: Kavindu Dodanduwa <[email protected]>
1 parent 4ea74d8 commit 5c0aaaa

21 files changed

+199
-188
lines changed

README.md

+12-12
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ See [here](https://javadoc.io/doc/dev.openfeature/sdk/latest/) for the Javadocs.
126126
|| [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
127127
|| [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
128128
|| [Logging](#logging) | Integrate with popular logging packages. |
129-
|| [Named clients](#named-clients) | Utilize multiple providers in a single application. |
129+
|| [Domains](#domains) | Logically bind clients with providers. |
130130
|| [Eventing](#eventing) | React to state changes in the provider or flag management system. |
131131
|| [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
132132
|| [Transaction Context Propagation](#transaction-context-propagation) | Set a specific [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context) for a transaction (e.g. an HTTP request or a thread). |
@@ -160,7 +160,7 @@ To register a provider in a non-blocking manner, you can use the `setProvider` m
160160
```
161161

162162
In some situations, it may be beneficial to register multiple providers in the same application.
163-
This is possible using [named clients](#named-clients), which is covered in more details below.
163+
This is possible using [domains](#domains), which is covered in more detail below.
164164

165165
### Targeting
166166

@@ -219,27 +219,27 @@ Once you've added a hook as a dependency, it can be registered at the global, cl
219219

220220
The Java SDK uses SLF4J. See the [SLF4J manual](https://slf4j.org/manual.html) for complete documentation.
221221

222-
### Named clients
222+
### Domains
223223

224-
Clients can be given a name.
225-
A name is a logical identifier which can be used to associate clients with a particular provider.
226-
If a name has no associated provider, the global provider is used.
224+
Clients can be assigned to a domain.
225+
A domain is a logical identifier which can be used to associate clients with a particular provider.
226+
If a domain has no associated provider, the global provider is used.
227227

228228
```java
229229
FeatureProvider scopedProvider = new MyProvider();
230230

231231
// registering the default provider
232232
OpenFeatureAPI.getInstance().setProvider(LocalProvider());
233-
// registering a named provider
234-
OpenFeatureAPI.getInstance().setProvider("clientForCache", new CachedProvider());
233+
// registering a provider to a domain
234+
OpenFeatureAPI.getInstance().setProvider("my-domain", new CachedProvider());
235235

236-
// a client backed by default provider
236+
// A client bound to the default provider
237237
Client clientDefault = OpenFeatureAPI.getInstance().getClient();
238-
// a client backed by CachedProvider
239-
Client clientNamed = OpenFeatureAPI.getInstance().getClient("clientForCache");
238+
// A client bound to the CachedProvider provider
239+
Client domainScopedClient = OpenFeatureAPI.getInstance().getClient("my-domain");
240240
```
241241

242-
Named providers can be set in a blocking or non-blocking way.
242+
Providers for domains can be set in a blocking or non-blocking way.
243243
For more details, please refer to the [providers](#providers) section.
244244

245245
### Eventing

src/main/java/dev/openfeature/sdk/Client.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Interface used to resolve flags of varying types.
77
*/
88
public interface Client extends Features, EventBus<Client> {
9-
Metadata getMetadata();
9+
ClientMetadata getMetadata();
1010

1111
/**
1212
* Return an optional client-level evaluation context.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package dev.openfeature.sdk;
2+
3+
/**
4+
* Metadata specific to an OpenFeature {@code Client}.
5+
*/
6+
public interface ClientMetadata {
7+
String getDomain();
8+
9+
@Deprecated
10+
// this is here for compatibility with getName() exposed from {@link Metadata}
11+
default String getName() {
12+
return getDomain();
13+
}
14+
}

src/main/java/dev/openfeature/sdk/EventDetails.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
@Data
1010
@SuperBuilder(toBuilder = true)
1111
public class EventDetails extends ProviderEventDetails {
12-
private String clientName;
12+
private String domain;
1313
private String providerName;
1414

1515
static EventDetails fromProviderEventDetails(ProviderEventDetails providerEventDetails, String providerName) {
@@ -19,9 +19,9 @@ static EventDetails fromProviderEventDetails(ProviderEventDetails providerEventD
1919
static EventDetails fromProviderEventDetails(
2020
ProviderEventDetails providerEventDetails,
2121
String providerName,
22-
String clientName) {
22+
String domain) {
2323
return builder()
24-
.clientName(clientName)
24+
.domain(domain)
2525
.providerName(providerName)
2626
.flagsChanged(providerEventDetails.getFlagsChanged())
2727
.eventMetadata(providerEventDetails.getEventMetadata())

src/main/java/dev/openfeature/sdk/EventSupport.java

+17-18
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ class EventSupport {
3333
});
3434

3535
/**
36-
* Run all the event handlers associated with this client name.
37-
* If the client name is null, handlers attached to unnamed clients will run.
36+
* Run all the event handlers associated with this domain.
37+
* If the domain is null, handlers attached to unnamed clients will run.
3838
*
39-
* @param clientName the client name to run event handlers for, or null
39+
* @param domain the domain to run event handlers for, or null
4040
* @param event the event type
4141
* @param eventDetails the event details
4242
*/
43-
public void runClientHandlers(String clientName, ProviderEvent event, EventDetails eventDetails) {
44-
clientName = Optional.ofNullable(clientName)
43+
public void runClientHandlers(String domain, ProviderEvent event, EventDetails eventDetails) {
44+
domain = Optional.ofNullable(domain)
4545
.orElse(defaultClientUuid);
4646

4747
// run handlers if they exist
48-
Optional.ofNullable(handlerStores.get(clientName))
48+
Optional.ofNullable(handlerStores.get(domain))
4949
.filter(store -> Optional.of(store).isPresent())
5050
.map(store -> store.handlerMap.get(event))
5151
.ifPresent(handlers -> handlers
@@ -66,15 +66,14 @@ public void runGlobalHandlers(ProviderEvent event, EventDetails eventDetails) {
6666
}
6767

6868
/**
69-
* Add a handler for the specified client name, or all unnamed clients.
69+
* Add a handler for the specified domain, or all unnamed clients.
7070
*
71-
* @param clientName the client name to add handlers for, or else the unnamed
72-
* client
71+
* @param domain the domain to add handlers for, or else unnamed
7372
* @param event the event type
7473
* @param handler the handler function to run
7574
*/
76-
public void addClientHandler(String clientName, ProviderEvent event, Consumer<EventDetails> handler) {
77-
final String name = Optional.ofNullable(clientName)
75+
public void addClientHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
76+
final String name = Optional.ofNullable(domain)
7877
.orElse(defaultClientUuid);
7978

8079
// lazily create and cache a HandlerStore if it doesn't exist
@@ -90,15 +89,15 @@ public void addClientHandler(String clientName, ProviderEvent event, Consumer<Ev
9089
/**
9190
* Remove a client event handler for the specified event type.
9291
*
93-
* @param clientName the name of the client handler to remove, or null to remove
92+
* @param domain the domain of the client handler to remove, or null to remove
9493
* from unnamed clients
9594
* @param event the event type
9695
* @param handler the handler ref to be removed
9796
*/
98-
public void removeClientHandler(String clientName, ProviderEvent event, Consumer<EventDetails> handler) {
99-
clientName = Optional.ofNullable(clientName)
97+
public void removeClientHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
98+
domain = Optional.ofNullable(domain)
10099
.orElse(defaultClientUuid);
101-
this.handlerStores.get(clientName).removeHandler(event, handler);
100+
this.handlerStores.get(domain).removeHandler(event, handler);
102101
}
103102

104103
/**
@@ -122,11 +121,11 @@ public void removeGlobalHandler(ProviderEvent event, Consumer<EventDetails> hand
122121
}
123122

124123
/**
125-
* Get all client names for which we have event handlers registered.
124+
* Get all domain names for which we have event handlers registered.
126125
*
127-
* @return set of client names
126+
* @return set of domain names
128127
*/
129-
public Set<String> getAllClientNames() {
128+
public Set<String> getAllDomainNames() {
130129
return this.handlerStores.keySet();
131130
}
132131

src/main/java/dev/openfeature/sdk/HookContext.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class HookContext<T> {
1616
@NonNull FlagValueType type;
1717
@NonNull T defaultValue;
1818
@NonNull EvaluationContext ctx;
19-
Metadata clientMetadata;
19+
ClientMetadata clientMetadata;
2020
Metadata providerMetadata;
2121

2222
/**
@@ -30,7 +30,7 @@ public class HookContext<T> {
3030
* @param <T> type that the flag is evaluating against
3131
* @return resulting context for hook
3232
*/
33-
public static <T> HookContext<T> from(String key, FlagValueType type, Metadata clientMetadata,
33+
public static <T> HookContext<T> from(String key, FlagValueType type, ClientMetadata clientMetadata,
3434
Metadata providerMetadata, EvaluationContext ctx, T defaultValue) {
3535
return HookContext.<T>builder()
3636
.flagKey(key)

src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java

+41-41
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package dev.openfeature.sdk;
22

3+
import dev.openfeature.sdk.exceptions.OpenFeatureError;
4+
import dev.openfeature.sdk.internal.AutoCloseableLock;
5+
import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock;
6+
import lombok.extern.slf4j.Slf4j;
7+
38
import java.util.ArrayList;
49
import java.util.Arrays;
510
import java.util.List;
611
import java.util.Optional;
712
import java.util.Set;
813
import java.util.function.Consumer;
914

10-
import dev.openfeature.sdk.exceptions.OpenFeatureError;
11-
import dev.openfeature.sdk.internal.AutoCloseableLock;
12-
import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock;
13-
import lombok.extern.slf4j.Slf4j;
14-
1515
/**
1616
* A global singleton which holds base configuration for the OpenFeature
1717
* library.
@@ -52,8 +52,8 @@ public Metadata getProviderMetadata() {
5252
return getProvider().getMetadata();
5353
}
5454

55-
public Metadata getProviderMetadata(String clientName) {
56-
return getProvider(clientName).getMetadata();
55+
public Metadata getProviderMetadata(String domain) {
56+
return getProvider(domain).getMetadata();
5757
}
5858

5959
/**
@@ -66,16 +66,16 @@ public Client getClient() {
6666
/**
6767
* {@inheritDoc}
6868
*/
69-
public Client getClient(String name) {
70-
return getClient(name, null);
69+
public Client getClient(String domain) {
70+
return getClient(domain, null);
7171
}
7272

7373
/**
7474
* {@inheritDoc}
7575
*/
76-
public Client getClient(String name, String version) {
76+
public Client getClient(String domain, String version) {
7777
return new OpenFeatureClient(this,
78-
name,
78+
domain,
7979
version);
8080
}
8181

@@ -154,14 +154,14 @@ public void setProvider(FeatureProvider provider) {
154154
}
155155

156156
/**
157-
* Add a provider for a named client.
157+
* Add a provider for a domain.
158158
*
159-
* @param clientName The name of the client.
159+
* @param domain The domain to bind the provider to.
160160
* @param provider The provider to set.
161161
*/
162-
public void setProvider(String clientName, FeatureProvider provider) {
162+
public void setProvider(String domain, FeatureProvider provider) {
163163
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
164-
providerRepository.setProvider(clientName,
164+
providerRepository.setProvider(domain,
165165
provider,
166166
this::attachEventProvider,
167167
this::emitReady,
@@ -187,14 +187,14 @@ public void setProviderAndWait(FeatureProvider provider) throws OpenFeatureError
187187
}
188188

189189
/**
190-
* Add a provider for a named client and wait for initialization to finish.
190+
* Add a provider for a domain and wait for initialization to finish.
191191
*
192-
* @param clientName The name of the client.
192+
* @param domain The domain to bind the provider to.
193193
* @param provider The provider to set.
194194
*/
195-
public void setProviderAndWait(String clientName, FeatureProvider provider) throws OpenFeatureError {
195+
public void setProviderAndWait(String domain, FeatureProvider provider) throws OpenFeatureError {
196196
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
197-
providerRepository.setProvider(clientName,
197+
providerRepository.setProvider(domain,
198198
provider,
199199
this::attachEventProvider,
200200
this::emitReady,
@@ -240,13 +240,13 @@ public FeatureProvider getProvider() {
240240
}
241241

242242
/**
243-
* Fetch a provider for a named client. If not found, return the default.
243+
* Fetch a provider for a domain. If not found, return the default.
244244
*
245-
* @param name The client name to look for.
245+
* @param domain The domain to look for.
246246
* @return A named {@link FeatureProvider}
247247
*/
248-
public FeatureProvider getProvider(String name) {
249-
return providerRepository.getProvider(name);
248+
public FeatureProvider getProvider(String domain) {
249+
return providerRepository.getProvider(domain);
250250
}
251251

252252
/**
@@ -344,20 +344,20 @@ public OpenFeatureAPI removeHandler(ProviderEvent event, Consumer<EventDetails>
344344
return this;
345345
}
346346

347-
void removeHandler(String clientName, ProviderEvent event, Consumer<EventDetails> handler) {
347+
void removeHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
348348
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
349-
eventSupport.removeClientHandler(clientName, event, handler);
349+
eventSupport.removeClientHandler(domain, event, handler);
350350
}
351351
}
352352

353-
void addHandler(String clientName, ProviderEvent event, Consumer<EventDetails> handler) {
353+
void addHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
354354
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
355355
// if the provider is in the state associated with event, run immediately
356-
if (Optional.ofNullable(this.providerRepository.getProvider(clientName).getState())
356+
if (Optional.ofNullable(this.providerRepository.getProvider(domain).getState())
357357
.orElse(ProviderState.READY).matchesEvent(event)) {
358-
eventSupport.runHandler(handler, EventDetails.builder().clientName(clientName).build());
358+
eventSupport.runHandler(handler, EventDetails.builder().domain(domain).build());
359359
}
360-
eventSupport.addClientHandler(clientName, event, handler);
360+
eventSupport.addClientHandler(domain, event, handler);
361361
}
362362
}
363363

@@ -371,8 +371,8 @@ void addHandler(String clientName, ProviderEvent event, Consumer<EventDetails> h
371371
private void runHandlersForProvider(FeatureProvider provider, ProviderEvent event, ProviderEventDetails details) {
372372
try (AutoCloseableLock __ = lock.readLockAutoCloseable()) {
373373

374-
List<String> clientNamesForProvider = providerRepository
375-
.getClientNamesForProvider(provider);
374+
List<String> domainsForProvider = providerRepository
375+
.getDomainsForProvider(provider);
376376

377377
final String providerName = Optional.ofNullable(provider.getMetadata())
378378
.map(metadata -> metadata.getName())
@@ -381,20 +381,20 @@ private void runHandlersForProvider(FeatureProvider provider, ProviderEvent even
381381
// run the global handlers
382382
eventSupport.runGlobalHandlers(event, EventDetails.fromProviderEventDetails(details, providerName));
383383

384-
// run the handlers associated with named clients for this provider
385-
clientNamesForProvider.forEach(name -> {
386-
eventSupport.runClientHandlers(name, event,
387-
EventDetails.fromProviderEventDetails(details, providerName, name));
384+
// run the handlers associated with domains for this provider
385+
domainsForProvider.forEach(domain -> {
386+
eventSupport.runClientHandlers(domain, event,
387+
EventDetails.fromProviderEventDetails(details, providerName, domain));
388388
});
389389

390390
if (providerRepository.isDefaultProvider(provider)) {
391391
// run handlers for clients that have no bound providers (since this is the default)
392-
Set<String> allClientNames = eventSupport.getAllClientNames();
393-
Set<String> boundClientNames = providerRepository.getAllBoundClientNames();
394-
allClientNames.removeAll(boundClientNames);
395-
allClientNames.forEach(name -> {
396-
eventSupport.runClientHandlers(name, event,
397-
EventDetails.fromProviderEventDetails(details, providerName, name));
392+
Set<String> allDomainNames = eventSupport.getAllDomainNames();
393+
Set<String> boundDomains = providerRepository.getAllBoundDomains();
394+
allDomainNames.removeAll(boundDomains);
395+
allDomainNames.forEach(domain -> {
396+
eventSupport.runClientHandlers(domain, event,
397+
EventDetails.fromProviderEventDetails(details, providerName, domain));
398398
});
399399
}
400400
}

0 commit comments

Comments
 (0)