Skip to content

Commit fa5627f

Browse files
authored
Merge branch 'main' into zero-copy-contexts
2 parents ab46556 + 393eddd commit fa5627f

21 files changed

+652
-19
lines changed

.github/workflows/manual-publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ jobs:
3838
name: Get secrets
3939
with:
4040
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
41-
ssm_parameter_pairs: '/production/common/releasing/sonatype/username = SONATYPE_USER_NAME,
42-
/production/common/releasing/sonatype/password = SONATYPE_PASSWORD,
41+
ssm_parameter_pairs: '/production/common/releasing/sonatype/central/username = SONATYPE_USER_NAME,
42+
/production/common/releasing/sonatype/central/password = SONATYPE_PASSWORD,
4343
/production/common/releasing/java/keyId = SIGNING_KEY_ID'
4444
s3_path_pairs: 'launchdarkly-releaser/java/code-signing-keyring.gpg = code-signing-keyring.gpg'
4545

.github/workflows/release-please.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ jobs:
3838
name: Get secrets
3939
with:
4040
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
41-
ssm_parameter_pairs: '/production/common/releasing/sonatype/username = SONATYPE_USER_NAME,
42-
/production/common/releasing/sonatype/password = SONATYPE_PASSWORD,
41+
ssm_parameter_pairs: '/production/common/releasing/sonatype/central/username = SONATYPE_USER_NAME,
42+
/production/common/releasing/sonatype/central/password = SONATYPE_PASSWORD,
4343
/production/common/releasing/java/keyId = SIGNING_KEY_ID'
4444
s3_path_pairs: 'launchdarkly-releaser/java/code-signing-keyring.gpg = code-signing-keyring.gpg'
4545

@@ -71,8 +71,8 @@ jobs:
7171
name: Get secrets
7272
with:
7373
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
74-
ssm_parameter_pairs: '/production/common/releasing/sonatype/username = SONATYPE_USER_NAME,
75-
/production/common/releasing/sonatype/password = SONATYPE_PASSWORD,
74+
ssm_parameter_pairs: '/production/common/releasing/sonatype/central/username = SONATYPE_USER_NAME,
75+
/production/common/releasing/sonatype/central/password = SONATYPE_PASSWORD,
7676
/production/common/releasing/java/keyId = SIGNING_KEY_ID'
7777
s3_path_pairs: 'launchdarkly-releaser/java/code-signing-keyring.gpg = code-signing-keyring.gpg'
7878

@@ -104,8 +104,8 @@ jobs:
104104
name: Get secrets
105105
with:
106106
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
107-
ssm_parameter_pairs: '/production/common/releasing/sonatype/username = SONATYPE_USER_NAME,
108-
/production/common/releasing/sonatype/password = SONATYPE_PASSWORD,
107+
ssm_parameter_pairs: '/production/common/releasing/sonatype/central/username = SONATYPE_USER_NAME,
108+
/production/common/releasing/sonatype/central/password = SONATYPE_PASSWORD,
109109
/production/common/releasing/java/keyId = SIGNING_KEY_ID'
110110
s3_path_pairs: 'launchdarkly-releaser/java/code-signing-keyring.gpg = code-signing-keyring.gpg'
111111

@@ -137,8 +137,8 @@ jobs:
137137
name: Get secrets
138138
with:
139139
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
140-
ssm_parameter_pairs: '/production/common/releasing/sonatype/username = SONATYPE_USER_NAME,
141-
/production/common/releasing/sonatype/password = SONATYPE_PASSWORD,
140+
ssm_parameter_pairs: '/production/common/releasing/sonatype/central/username = SONATYPE_USER_NAME,
141+
/production/common/releasing/sonatype/central/password = SONATYPE_PASSWORD,
142142
/production/common/releasing/java/keyId = SIGNING_KEY_ID'
143143
s3_path_pairs: 'launchdarkly-releaser/java/code-signing-keyring.gpg = code-signing-keyring.gpg'
144144

@@ -171,8 +171,8 @@ jobs:
171171
name: Get secrets
172172
with:
173173
aws_assume_role: ${{ vars.AWS_ROLE_ARN }}
174-
ssm_parameter_pairs: '/production/common/releasing/sonatype/username = SONATYPE_USER_NAME,
175-
/production/common/releasing/sonatype/password = SONATYPE_PASSWORD,
174+
ssm_parameter_pairs: '/production/common/releasing/sonatype/central/username = SONATYPE_USER_NAME,
175+
/production/common/releasing/sonatype/central/password = SONATYPE_PASSWORD,
176176
/production/common/releasing/java/keyId = SIGNING_KEY_ID'
177177
s3_path_pairs: 'launchdarkly-releaser/java/code-signing-keyring.gpg = code-signing-keyring.gpg'
178178

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
"lib/java-server-sdk-redis-store": "3.0.1",
44
"lib/shared/common": "2.1.1",
55
"lib/shared/internal": "1.5.0",
6-
"lib/sdk/server": "7.9.1"
6+
"lib/sdk/server": "7.10.1"
77
}

lib/sdk/server/CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
All notable changes to the LaunchDarkly Java SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
44

5+
## [7.10.1](https://github.com/launchdarkly/java-core/compare/launchdarkly-java-server-sdk-7.10.0...launchdarkly-java-server-sdk-7.10.1) (2025-06-30)
6+
7+
8+
### Bug Fixes
9+
10+
* migrating publishing to use central portal ([#78](https://github.com/launchdarkly/java-core/issues/78)) ([cf4e46e](https://github.com/launchdarkly/java-core/commit/cf4e46e05bc5f95cc791af3244900d05e458fe64))
11+
12+
## [7.10.0](https://github.com/launchdarkly/java-core/compare/launchdarkly-java-server-sdk-7.9.1...launchdarkly-java-server-sdk-7.10.0) (2025-06-27)
13+
14+
15+
### Features
16+
17+
* Add experimental plugin support ([#76](https://github.com/launchdarkly/java-core/issues/76)) ([13dc0e4](https://github.com/launchdarkly/java-core/commit/13dc0e42318ac090c72b2fbc89454b50434a1ff6))
18+
519
## [7.9.1](https://github.com/launchdarkly/java-core/compare/launchdarkly-java-server-sdk-7.9.0...launchdarkly-java-server-sdk-7.9.1) (2025-06-20)
620

721

lib/sdk/server/build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,10 @@ if (project == rootProject) {
600600
nexusPublishing {
601601
clientTimeout = java.time.Duration.ofMinutes(2) // we've seen extremely long delays in creating repositories
602602
repositories {
603-
sonatype()
603+
sonatype{
604+
nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
605+
snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
606+
}
604607
}
605608
}
606609
}

lib/sdk/server/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#x-release-please-start-version
2-
version=7.9.1
2+
version=7.10.1
33
#x-release-please-end
44

55
# See https://github.com/gradle/gradle/issues/11308 regarding the following property

lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/Components.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.launchdarkly.sdk.server.ComponentsImpl.LoggingConfigurationBuilderImpl;
1111
import com.launchdarkly.sdk.server.ComponentsImpl.NullDataSourceFactory;
1212
import com.launchdarkly.sdk.server.ComponentsImpl.PersistentDataStoreBuilderImpl;
13+
import com.launchdarkly.sdk.server.ComponentsImpl.PluginsConfigurationBuilderImpl;
1314
import com.launchdarkly.sdk.server.ComponentsImpl.PollingDataSourceBuilderImpl;
1415
import com.launchdarkly.sdk.server.ComponentsImpl.ServiceEndpointsBuilderImpl;
1516
import com.launchdarkly.sdk.server.ComponentsImpl.StreamingDataSourceBuilderImpl;
@@ -21,6 +22,7 @@
2122
import com.launchdarkly.sdk.server.integrations.HttpConfigurationBuilder;
2223
import com.launchdarkly.sdk.server.integrations.LoggingConfigurationBuilder;
2324
import com.launchdarkly.sdk.server.integrations.PersistentDataStoreBuilder;
25+
import com.launchdarkly.sdk.server.integrations.PluginsConfigurationBuilder;
2426
import com.launchdarkly.sdk.server.integrations.PollingDataSourceBuilder;
2527
import com.launchdarkly.sdk.server.integrations.ServiceEndpointsBuilder;
2628
import com.launchdarkly.sdk.server.integrations.StreamingDataSourceBuilder;
@@ -445,6 +447,26 @@ public static HooksConfigurationBuilder hooks() {
445447
return new HooksConfigurationBuilderImpl();
446448
}
447449

450+
/**
451+
* Returns a builder for configuring plugins.
452+
*
453+
* Passing this to {@link LDConfig.Builder#plugins(com.launchdarkly.sdk.server.integrations.PluginsConfigurationBuilder)},
454+
* after setting any desired plugins on the builder, applies this configuration to the SDK.
455+
* <pre><code>
456+
* List plugins = myCreatePluginsFunc();
457+
* LDConfig config = new LDConfig.Builder()
458+
* .plugins(
459+
* Components.plugins()
460+
* .setPlugins(plugins)
461+
* )
462+
* .build();
463+
* </code></pre>
464+
* @return a {@link PluginsConfigurationBuilder} that can be used for customization
465+
*/
466+
public static PluginsConfigurationBuilder plugins() {
467+
return new PluginsConfigurationBuilderImpl();
468+
}
469+
448470
/**
449471
* Returns a wrapper information builder.
450472
* <p>

lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/ComponentsImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.launchdarkly.sdk.server.integrations.HttpConfigurationBuilder;
1818
import com.launchdarkly.sdk.server.integrations.LoggingConfigurationBuilder;
1919
import com.launchdarkly.sdk.server.integrations.PersistentDataStoreBuilder;
20+
import com.launchdarkly.sdk.server.integrations.PluginsConfigurationBuilder;
2021
import com.launchdarkly.sdk.server.integrations.PollingDataSourceBuilder;
2122
import com.launchdarkly.sdk.server.integrations.ServiceEndpointsBuilder;
2223
import com.launchdarkly.sdk.server.integrations.StreamingDataSourceBuilder;
@@ -35,6 +36,8 @@
3536
import com.launchdarkly.sdk.server.subsystems.HttpConfiguration;
3637
import com.launchdarkly.sdk.server.subsystems.LoggingConfiguration;
3738
import com.launchdarkly.sdk.server.subsystems.PersistentDataStore;
39+
import com.launchdarkly.sdk.server.subsystems.PluginsConfiguration;
40+
3841
import okhttp3.Credentials;
3942

4043
import java.io.IOException;
@@ -478,6 +481,19 @@ public HookConfiguration build() {
478481
}
479482
}
480483

484+
static final class PluginsConfigurationBuilderImpl extends PluginsConfigurationBuilder {
485+
public static PluginsConfigurationBuilderImpl fromPluginsConfiguration(PluginsConfiguration pluginsConfiguration) {
486+
PluginsConfigurationBuilderImpl builder = new PluginsConfigurationBuilderImpl();
487+
builder.setPlugins(pluginsConfiguration.getPlugins());
488+
return builder;
489+
}
490+
491+
@Override
492+
public PluginsConfiguration build() {
493+
return new PluginsConfiguration(plugins);
494+
}
495+
}
496+
481497
static final class WrapperInfoBuilderImpl extends WrapperInfoBuilder {
482498
public WrapperInfoBuilderImpl() {
483499
this(null, null);

lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/LDClient.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
import com.launchdarkly.sdk.LDValue;
1010
import com.launchdarkly.sdk.LDValueType;
1111
import com.launchdarkly.sdk.internal.http.HttpHelpers;
12+
import com.launchdarkly.sdk.server.integrations.EnvironmentMetadata;
13+
import com.launchdarkly.sdk.server.integrations.Hook;
14+
import com.launchdarkly.sdk.server.integrations.Plugin;
15+
import com.launchdarkly.sdk.server.integrations.SdkMetadata;
1216
import com.launchdarkly.sdk.server.interfaces.BigSegmentStoreStatusProvider;
1317
import com.launchdarkly.sdk.server.interfaces.BigSegmentsConfiguration;
1418
import com.launchdarkly.sdk.server.interfaces.DataSourceStatusProvider;
@@ -30,6 +34,9 @@
3034
import java.io.UnsupportedEncodingException;
3135
import java.security.InvalidKeyException;
3236
import java.security.NoSuchAlgorithmException;
37+
import java.util.ArrayList;
38+
import java.util.Collections;
39+
import java.util.List;
3340
import java.util.concurrent.Executors;
3441
import java.util.concurrent.Future;
3542
import java.util.concurrent.ScheduledExecutorService;
@@ -206,13 +213,33 @@ public LDClient(String sdkKey, LDConfig config) {
206213

207214
EvaluatorInterface evaluator = new InputValidatingEvaluator(dataStore, bigSegmentStoreWrapper, eventProcessor, evaluationLogger);
208215

216+
// build environment metadata for plugins
217+
SdkMetadata sdkMetadata;
218+
if (config.wrapperInfo == null) {
219+
sdkMetadata = new SdkMetadata("JavaClient", Version.SDK_VERSION);
220+
} else {
221+
sdkMetadata = new SdkMetadata("JavaClient", Version.SDK_VERSION, config.wrapperInfo.getWrapperName(), config.wrapperInfo.getWrapperVersion());
222+
}
223+
EnvironmentMetadata environmentMetadata = new EnvironmentMetadata(config.applicationInfo, sdkMetadata, sdkKey);
224+
225+
// add plugin hooks
226+
List<Hook> allHooks = new ArrayList<>(config.hooks.getHooks());
227+
for (Plugin plugin : config.plugins.getPlugins()) {
228+
try {
229+
allHooks.addAll(plugin.getHooks(environmentMetadata));
230+
} catch (Exception e) {
231+
baseLogger.error("Exception thrown getting hooks for plugin " + plugin.getMetadata().getName() + ". Unable to get hooks, plugin will not be registered.");
232+
}
233+
}
234+
allHooks = Collections.unmodifiableList(allHooks);
235+
209236
// decorate evaluator with hooks if hooks were provided
210-
if (config.hooks.getHooks().isEmpty()) {
237+
if (allHooks.isEmpty()) {
211238
this.evaluator = evaluator;
212239
this.migrationEvaluator = new MigrationStageEnforcingEvaluator(evaluator, evaluationLogger);
213240
} else {
214-
this.evaluator = new EvaluatorWithHooks(evaluator, config.hooks.getHooks(), this.baseLogger.subLogger(Loggers.HOOKS_LOGGER_NAME));
215-
this.migrationEvaluator = new EvaluatorWithHooks(new MigrationStageEnforcingEvaluator(evaluator, evaluationLogger), config.hooks.getHooks(), this.baseLogger.subLogger(Loggers.HOOKS_LOGGER_NAME));
241+
this.evaluator = new EvaluatorWithHooks(evaluator, allHooks, this.baseLogger.subLogger(Loggers.HOOKS_LOGGER_NAME));
242+
this.migrationEvaluator = new EvaluatorWithHooks(new MigrationStageEnforcingEvaluator(evaluator, evaluationLogger), allHooks, this.baseLogger.subLogger(Loggers.HOOKS_LOGGER_NAME));
216243
}
217244

218245
this.flagChangeBroadcaster = EventBroadcasterImpl.forFlagChangeEvents(sharedExecutor, baseLogger);
@@ -236,6 +263,15 @@ public LDClient(String sdkKey, LDConfig config) {
236263
this.dataSource = config.dataSource.build(context.withDataSourceUpdateSink(dataSourceUpdates));
237264
this.dataSourceStatusProvider = new DataSourceStatusProviderImpl(dataSourceStatusNotifier, dataSourceUpdates);
238265

266+
// register plugins as soon as possible after client is valid
267+
for (Plugin plugin : config.plugins.getPlugins()) {
268+
try {
269+
plugin.register(this, environmentMetadata);
270+
} catch (Exception e) {
271+
baseLogger.error("Exception thrown registering plugin " + plugin.getMetadata().getName() + ". Plugin will not be registered.");
272+
}
273+
}
274+
239275
Future<Void> startFuture = dataSource.start();
240276
if (!config.startWait.isZero() && !config.startWait.isNegative()) {
241277
if (!(dataSource instanceof ComponentsImpl.NullDataSource)) {

lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/LDConfig.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.launchdarkly.sdk.EvaluationReason.BigSegmentsStatus;
55
import com.launchdarkly.sdk.server.integrations.ApplicationInfoBuilder;
66
import com.launchdarkly.sdk.server.integrations.HooksConfigurationBuilder;
7+
import com.launchdarkly.sdk.server.integrations.PluginsConfigurationBuilder;
78
import com.launchdarkly.sdk.server.integrations.ServiceEndpointsBuilder;
89
import com.launchdarkly.sdk.server.integrations.WrapperInfoBuilder;
910
import com.launchdarkly.sdk.server.interfaces.ApplicationInfo;
@@ -17,6 +18,7 @@
1718
import com.launchdarkly.sdk.server.subsystems.HookConfiguration;
1819
import com.launchdarkly.sdk.server.subsystems.HttpConfiguration;
1920
import com.launchdarkly.sdk.server.subsystems.LoggingConfiguration;
21+
import com.launchdarkly.sdk.server.subsystems.PluginsConfiguration;
2022

2123
import java.time.Duration;
2224

@@ -38,6 +40,7 @@ public final class LDConfig {
3840
final boolean diagnosticOptOut;
3941
final ComponentConfigurer<EventProcessor> events;
4042
final HookConfiguration hooks;
43+
final PluginsConfiguration plugins;
4144
final ComponentConfigurer<HttpConfiguration> http;
4245
final ComponentConfigurer<LoggingConfiguration> logging;
4346
final ServiceEndpoints serviceEndpoints;
@@ -61,6 +64,7 @@ protected LDConfig(Builder builder) {
6164
this.dataStore = builder.dataStore == null ? Components.inMemoryDataStore() : builder.dataStore;
6265
this.diagnosticOptOut = builder.diagnosticOptOut;
6366
this.hooks = (builder.hooksConfigurationBuilder == null ? Components.hooks() : builder.hooksConfigurationBuilder).build();
67+
this.plugins = (builder.pluginsConfigurationBuilder == null ? Components.plugins() : builder.pluginsConfigurationBuilder).build();
6468
this.http = builder.http == null ? Components.httpConfiguration() : builder.http;
6569
this.logging = builder.logging == null ? Components.logging() : builder.logging;
6670
this.offline = builder.offline;
@@ -91,6 +95,7 @@ public static class Builder {
9195
private boolean diagnosticOptOut = false;
9296
private ComponentConfigurer<EventProcessor> events = null;
9397
private HooksConfigurationBuilder hooksConfigurationBuilder = null;
98+
private PluginsConfigurationBuilder pluginsConfigurationBuilder = null;
9499
private ComponentConfigurer<HttpConfiguration> http = null;
95100
private ComponentConfigurer<LoggingConfiguration> logging = null;
96101
private ServiceEndpointsBuilder serviceEndpointsBuilder = null;
@@ -120,6 +125,7 @@ public static Builder fromConfig(LDConfig config) {
120125
newBuilder.diagnosticOptOut = config.diagnosticOptOut;
121126
newBuilder.events = config.events;
122127
newBuilder.hooksConfigurationBuilder = ComponentsImpl.HooksConfigurationBuilderImpl.fromHooksConfiguration(config.hooks);
128+
newBuilder.pluginsConfigurationBuilder = ComponentsImpl.PluginsConfigurationBuilderImpl.fromPluginsConfiguration(config.plugins);
123129
newBuilder.http = config.http;
124130
newBuilder.logging = config.logging;
125131

@@ -270,6 +276,22 @@ public Builder hooks(HooksConfigurationBuilder hooksConfiguration) {
270276
return this;
271277
}
272278

279+
/**
280+
* Sets the SDK's plugins configuration, using a builder. This is normally a obtained from
281+
* {@link Components#plugins()} ()}, which has methods for setting individual other plugin
282+
* related properties.
283+
* <p>
284+
* Plugin support is currently experimental and subject to change.
285+
*
286+
* @param pluginsConfiguration the plugins configuration builder
287+
* @return the main configuration builder
288+
* @see Components#plugins()
289+
*/
290+
public Builder plugins(PluginsConfigurationBuilder pluginsConfiguration) {
291+
this.pluginsConfigurationBuilder = pluginsConfiguration;
292+
return this;
293+
}
294+
273295
/**
274296
* Sets the SDK's networking configuration, using a configuration builder. This builder is
275297
* obtained from {@link Components#httpConfiguration()}, and has methods for setting individual

0 commit comments

Comments
 (0)