diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 721a6707..e5333445 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -59,9 +59,9 @@ jobs:
if: matrix.jdk == '8' && github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/development'
run: mvn checkstyle::check
- - name: Deploy
- if: matrix.jdk == '8' && github.event_name == 'push' && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/development'
- run: mvn --batch-mode deploy -P test
+# - name: Deploy
+# if: matrix.jdk == '8' && github.event_name == 'push' && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/development'
+# run: mvn --batch-mode deploy -P test
- name: SonarQube Scan (Push)
if: matrix.jdk == '11' && github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development')
diff --git a/CHANGES.txt b/CHANGES.txt
index a99b79df..ceaef9e6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,8 @@
+4.16.1 (Jul 21, 2025)
+- Fixed vulnerabilities:
+ - Upgraded org.apache.commons-commons-lang3 to 3.18.0
+ - Upgraded com.google.code.gson.gson to 2.13.1
+
4.16.0 (May 28, 2025)
- Added support for rule-based segments. These segments determine membership at runtime by evaluating their configured rules against the user attributes provided to the SDK.
- Added support for feature flag prerequisites. This allows customers to define dependency conditions between flags, which are evaluated before any allowlists or targeting rules.
diff --git a/client/pom.xml b/client/pom.xml
index d0ae4a78..b6337c14 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -5,9 +5,9 @@
io.split.client
java-client-parent
- 4.16.0
+ 4.16.1
- 4.16.0
+ 4.16.1
java-client
jar
Java Client
@@ -19,12 +19,15 @@
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.3
+ org.sonatype.central
+ central-publishing-maven-plugin
+ 0.8.0
true
- false
+ true
+ central
+ false
+ published
@@ -173,7 +176,7 @@
com.google.code.gson
gson
- 2.9.0
+ 2.13.1
org.yaml
@@ -185,7 +188,7 @@
org.apache.commons
commons-lang3
- 3.4
+ 3.18.0
test
diff --git a/client/src/main/java/io/split/client/events/EventsSender.java b/client/src/main/java/io/split/client/events/EventsSender.java
index 2c023ef3..d83969dc 100644
--- a/client/src/main/java/io/split/client/events/EventsSender.java
+++ b/client/src/main/java/io/split/client/events/EventsSender.java
@@ -12,7 +12,7 @@
import java.net.URISyntaxException;
import java.util.List;
-import static com.google.gson.internal.$Gson$Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkNotNull;
public class EventsSender {
diff --git a/client/src/main/java/io/split/client/events/InMemoryEventsStorage.java b/client/src/main/java/io/split/client/events/InMemoryEventsStorage.java
index fae0d070..a3463f0e 100644
--- a/client/src/main/java/io/split/client/events/InMemoryEventsStorage.java
+++ b/client/src/main/java/io/split/client/events/InMemoryEventsStorage.java
@@ -12,7 +12,7 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
-import static com.google.gson.internal.$Gson$Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkNotNull;
public class InMemoryEventsStorage implements EventsStorage{
diff --git a/client/src/main/java/io/split/client/impressions/UniqueKeysTrackerImp.java b/client/src/main/java/io/split/client/impressions/UniqueKeysTrackerImp.java
index bd2ff918..80b3703d 100644
--- a/client/src/main/java/io/split/client/impressions/UniqueKeysTrackerImp.java
+++ b/client/src/main/java/io/split/client/impressions/UniqueKeysTrackerImp.java
@@ -117,7 +117,7 @@ private void sendUniqueKeys(){
}
try {
if (uniqueKeysTracker.size() == 0) {
- _log.warn("The Unique Keys Tracker is empty");
+ _log.debug("The Unique Keys Tracker is empty");
return;
}
HashMap> uniqueKeysHashMap = popAll();
diff --git a/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java b/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java
index 53730cf9..660811ca 100644
--- a/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java
+++ b/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java
@@ -104,6 +104,6 @@ public Set getSegments() {
@Override
public boolean contains(Set ruleBasedSegmentNames) {
- return getSegments().containsAll(ruleBasedSegmentNames);
+ return _concurrentMap.keySet().containsAll(ruleBasedSegmentNames);
}
}
\ No newline at end of file
diff --git a/client/src/main/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumer.java b/client/src/main/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumer.java
index 438b7bf8..b04e4976 100644
--- a/client/src/main/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumer.java
+++ b/client/src/main/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumer.java
@@ -96,7 +96,7 @@ private List stringsToParsedRuleBasedSegments(List ruleBasedSegmentNames) {
- return getSegments().containsAll(ruleBasedSegmentNames);
+ return _userStorageWrapper.getKeysByPrefix(PrefixAdapter.buildGetAllRuleBasedSegment()).containsAll(ruleBasedSegmentNames);
}
}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImplTest.java b/client/src/test/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImplTest.java
index 32487bf5..492cc8ae 100644
--- a/client/src/test/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImplTest.java
+++ b/client/src/test/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImplTest.java
@@ -16,6 +16,8 @@
import com.google.common.collect.Lists;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
public class RuleBasedSegmentCacheInMemoryImplTest extends TestCase {
@@ -31,6 +33,8 @@ public void testAddAndDeleteSegment(){
ruleBasedSegmentCache.update(Lists.newArrayList(parsedRuleBasedSegment), null, 123);
assertEquals(123, ruleBasedSegmentCache.getChangeNumber());
assertEquals(parsedRuleBasedSegment, ruleBasedSegmentCache.get("sample_rule_based_segment"));
+ assertTrue(ruleBasedSegmentCache.contains(new HashSet<>(Arrays.asList("sample_rule_based_segment"))));
+ assertFalse(ruleBasedSegmentCache.contains(new HashSet<>(Arrays.asList("sample_rule_based_segment", "123"))));
ruleBasedSegmentCache.update(null, Lists.newArrayList("sample_rule_based_segment"), 124);
assertEquals(124, ruleBasedSegmentCache.getChangeNumber());
@@ -62,5 +66,7 @@ public void testMultipleSegment(){
ruleBasedSegmentCache.update(Lists.newArrayList(parsedRuleBasedSegment1, parsedRuleBasedSegment2), null, 123);
assertEquals(Lists.newArrayList("another_rule_based_segment", "sample_rule_based_segment"), ruleBasedSegmentCache.ruleBasedSegmentNames());
assertEquals(Sets.newHashSet("segment2", "segment1", "employees"), ruleBasedSegmentCache.getSegments());
+ assertTrue(ruleBasedSegmentCache.contains(new HashSet<>(Arrays.asList("sample_rule_based_segment", "another_rule_based_segment"))));
+ assertTrue(ruleBasedSegmentCache.contains(new HashSet<>(Arrays.asList("sample_rule_based_segment"))));
}
}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumerTest.java b/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumerTest.java
index f1f39a73..b9baee95 100644
--- a/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumerTest.java
+++ b/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumerTest.java
@@ -1,6 +1,7 @@
package io.split.storages.pluggable.adapters;
import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import io.split.client.dtos.*;
import io.split.client.utils.Json;
import io.split.engine.ConditionsTestUtil;
@@ -16,10 +17,14 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static io.split.TestHelper.makeRuleBasedSegment;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
public class UserCustomRuleBasedSegmentAdapterConsumerTest {
@@ -66,10 +71,16 @@ public void testGetChangeNumberWithGsonFailing() {
public void testGetRuleBasedSegment() {
RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser();
RuleBasedSegment ruleBasedSegment = getRuleBasedSegment(RULE_BASED_SEGMENT_NAME);
+ ParsedRuleBasedSegment expected = ruleBasedSegmentParser.parse(ruleBasedSegment);
+ ConcurrentMap rbsCollection = Maps.newConcurrentMap();
+ rbsCollection.put(RULE_BASED_SEGMENT_NAME, expected);
Mockito.when(_userStorageWrapper.get(PrefixAdapter.buildRuleBasedSegmentKey(RULE_BASED_SEGMENT_NAME))).thenReturn(getRuleBasedSegmentAsJson(ruleBasedSegment));
+ Mockito.when(_userStorageWrapper.getKeysByPrefix("SPLITIO.rbsegment*")).thenReturn(new HashSet<>(Arrays.asList(RULE_BASED_SEGMENT_NAME)));
ParsedRuleBasedSegment result = _userCustomRuleBasedSegmentAdapterConsumer.get(RULE_BASED_SEGMENT_NAME);
- ParsedRuleBasedSegment expected = ruleBasedSegmentParser.parse(ruleBasedSegment);
Assert.assertEquals(expected, result);
+ assertTrue(_userCustomRuleBasedSegmentAdapterConsumer.contains(new HashSet<>(Arrays.asList(RULE_BASED_SEGMENT_NAME))));
+ assertFalse(_userCustomRuleBasedSegmentAdapterConsumer.contains(new HashSet<>(Arrays.asList(RULE_BASED_SEGMENT_NAME, "123"))));
+
}
@Test
@@ -135,7 +146,7 @@ public void testGetSegments() {
Mockito.when(_userStorageWrapper.getMany(Mockito.anyObject())).
thenReturn(getManyExpected);
HashSet segmentResult = (HashSet) _userCustomRuleBasedSegmentAdapterConsumer.getSegments();
- Assert.assertTrue(segmentResult.contains("employee"));
+ assertTrue(segmentResult.contains("employee"));
}
@Test
diff --git a/okhttp-modules/pom.xml b/okhttp-modules/pom.xml
index a8645f9c..7346518d 100644
--- a/okhttp-modules/pom.xml
+++ b/okhttp-modules/pom.xml
@@ -5,10 +5,10 @@
java-client-parent
io.split.client
- 4.16.0
+ 4.16.1
4.0.0
- 4.16.0
+ 4.16.1
okhttp-modules
jar
http-modules
@@ -20,12 +20,15 @@
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.3
+ org.sonatype.central
+ central-publishing-maven-plugin
+ 0.8.0
true
- false
+ true
+ central
+ false
+ published
diff --git a/pluggable-storage/pom.xml b/pluggable-storage/pom.xml
index 21b0bdac..5c304f98 100644
--- a/pluggable-storage/pom.xml
+++ b/pluggable-storage/pom.xml
@@ -6,7 +6,7 @@
java-client-parent
io.split.client
- 4.16.0
+ 4.16.1
2.1.0
@@ -21,15 +21,15 @@
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.3
+ org.sonatype.central
+ central-publishing-maven-plugin
+ 0.8.0
true
- ossrh
- https://oss.sonatype.org/
- true
- true
+ true
+ central
+ false
+ published
diff --git a/pom.xml b/pom.xml
index 7b21f1ec..9f91ded1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
io.split.client
java-client-parent
- 4.16.0
+ 4.16.1
@@ -47,31 +47,14 @@
scm:git@github.com:splitio/java-client.git
git@github.com:splitio/java-client.git
-
-
- ossrh
- https://oss.sonatype.org/content/repositories/snapshots
-
-
- ossrh
- https://oss.sonatype.org/content/repositories/releases
-
-
+
ossrh
https://oss.sonatype.org/content/repositories/releases
-
- maven-all-virtual
- https://splitio.jfrog.io/artifactory/maven-all-virtual
-
-
- maven-all-virtual
- https://splitio.jfrog.io/artifactory/maven-all-virtual
-
UTF-8
@@ -154,16 +137,6 @@
test
-
-
- maven-dev
- https://splitio.jfrog.io/artifactory/maven-dev/
-
-
- maven-dev
- https://splitio.jfrog.io/artifactory/maven-dev/
-
-
@@ -188,16 +161,7 @@
release
-
-
- ossrh
- https://oss.sonatype.org/content/repositories/snapshots
-
-
- ossrh
- https://oss.sonatype.org/content/repositories/releases
-
-
+
@@ -230,16 +194,16 @@
-
+
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.3
+ org.sonatype.central
+ central-publishing-maven-plugin
+ 0.8.0
true
- ossrh
- https://oss.sonatype.org/
- true
+ central
+ false
+ published
diff --git a/redis-wrapper/pom.xml b/redis-wrapper/pom.xml
index 301739ce..9ca70894 100644
--- a/redis-wrapper/pom.xml
+++ b/redis-wrapper/pom.xml
@@ -6,7 +6,7 @@
java-client-parent
io.split.client
- 4.16.0
+ 4.16.1
redis-wrapper
3.1.1
@@ -43,15 +43,15 @@
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.3
+ org.sonatype.central
+ central-publishing-maven-plugin
+ 0.8.0
true
- ossrh
- https://oss.sonatype.org/
- true
- true
+ true
+ central
+ false
+ published
diff --git a/testing/pom.xml b/testing/pom.xml
index 0fae6cdf..5f0aa0c5 100644
--- a/testing/pom.xml
+++ b/testing/pom.xml
@@ -5,7 +5,7 @@
io.split.client
java-client-parent
- 4.16.0
+ 4.16.1
java-client-testing
jar
@@ -31,15 +31,15 @@
- org.sonatype.plugins
- nexus-staging-maven-plugin
- 1.6.3
+ org.sonatype.central
+ central-publishing-maven-plugin
+ 0.8.0
true
- ossrh
- https://oss.sonatype.org/
- true
- false
+ central
+ false
+ published
+ true
diff --git a/update_maven_settings.sh b/update_maven_settings.sh
new file mode 100755
index 00000000..8bea975f
--- /dev/null
+++ b/update_maven_settings.sh
@@ -0,0 +1,161 @@
+#!/bin/bash
+
+# Script to update Maven settings.xml with Central Repository credentials using xmlstarlet
+
+# ANSI color codes
+GREEN='\033[0;32m'
+YELLOW='\033[0;33m'
+BLUE='\033[0;34m'
+RED='\033[0;31m'
+NC='\033[0m' # No Color
+
+# Check if xmlstarlet is installed
+if ! command -v xmlstarlet &> /dev/null; then
+ echo -e "${RED}Error: xmlstarlet is not installed.${NC}"
+ echo "Please install xmlstarlet first:"
+ echo " macOS: brew install xmlstarlet"
+ echo " Debian/Ubuntu: sudo apt-get install xmlstarlet"
+ echo " RHEL/CentOS/Fedora: sudo yum install xmlstarlet"
+ echo "Then run this script again."
+ exit 1
+fi
+
+# Default values
+DEFAULT_SETTINGS_PATH="$HOME/.m2/settings.xml"
+DEFAULT_SERVER_ID="central"
+
+echo -e "${BLUE}Maven Settings.xml Update Script${NC}"
+echo "This script will update your Maven settings.xml with Central Repository credentials."
+echo
+
+# Ask for settings.xml path or use default
+read -p "Path to settings.xml [$DEFAULT_SETTINGS_PATH]: " SETTINGS_PATH
+SETTINGS_PATH=${SETTINGS_PATH:-$DEFAULT_SETTINGS_PATH}
+
+# Variables to store existing values
+EXISTING_USERNAME=""
+EXISTING_PASSWORD=""
+
+# Extract existing values if settings.xml exists
+if [ -f "$SETTINGS_PATH" ] && command -v xmlstarlet &> /dev/null; then
+ # Check if the file is valid XML
+ if xmlstarlet val "$SETTINGS_PATH" &> /dev/null; then
+ echo -e "${YELLOW}Reading existing settings from ${SETTINGS_PATH}...${NC}"
+
+ # Extract existing server ID
+ DEFAULT_SERVER_ID=$(xmlstarlet sel -t -v "/settings/servers/server[1]/id" "$SETTINGS_PATH" 2>/dev/null || echo "$DEFAULT_SERVER_ID")
+
+ # Extract existing username and password for the server
+ EXISTING_USERNAME=$(xmlstarlet sel -t -v "/settings/servers/server[id='$DEFAULT_SERVER_ID']/username" "$SETTINGS_PATH" 2>/dev/null || echo "")
+ EXISTING_PASSWORD=$(xmlstarlet sel -t -v "/settings/servers/server[id='$DEFAULT_SERVER_ID']/password" "$SETTINGS_PATH" 2>/dev/null || echo "")
+ fi
+fi
+
+# Ask for server ID or use default/existing
+read -p "Server ID [$DEFAULT_SERVER_ID]: " SERVER_ID
+SERVER_ID=${SERVER_ID:-$DEFAULT_SERVER_ID}
+
+# Ask for username (show existing if available)
+USERNAME_PROMPT="Username"
+if [ -n "$EXISTING_USERNAME" ]; then
+ USERNAME_PROMPT="Username (current: $EXISTING_USERNAME)"
+fi
+read -p "$USERNAME_PROMPT: " USERNAME
+USERNAME=${USERNAME:-$EXISTING_USERNAME}
+
+# Ask for password (indicate if existing)
+PASSWORD_PROMPT="Password"
+if [ -n "$EXISTING_PASSWORD" ]; then
+ PASSWORD_PROMPT="Password (leave empty to keep current)"
+fi
+read -s -p "$PASSWORD_PROMPT: " PASSWORD
+echo
+# Only use existing password if the user didn't enter a new one
+if [ -z "$PASSWORD" ] && [ -n "$EXISTING_PASSWORD" ]; then
+ PASSWORD="$EXISTING_PASSWORD"
+fi
+
+# Create .m2 directory if it doesn't exist
+M2_DIR=$(dirname "$SETTINGS_PATH")
+mkdir -p "$M2_DIR"
+
+# No GPG configuration needed
+
+# Function to create a new settings.xml file
+create_new_settings() {
+ echo -e "${YELLOW}Creating new settings.xml file...${NC}"
+ cat > "$SETTINGS_PATH" << EOF
+
+
+
+
+ $SERVER_ID
+ $USERNAME
+ $PASSWORD
+
+
+
+EOF
+}
+
+# Check if settings.xml exists
+if [ -f "$SETTINGS_PATH" ]; then
+ echo -e "${YELLOW}Existing settings.xml found. Backing up to ${SETTINGS_PATH}.bak${NC}"
+ cp "$SETTINGS_PATH" "${SETTINGS_PATH}.bak"
+
+ # Check if the file is valid XML
+ if ! xmlstarlet val "$SETTINGS_PATH" &> /dev/null; then
+ echo -e "${RED}Warning: The existing settings.xml is not valid XML.${NC}"
+ read -p "Do you want to create a new settings.xml file? (y/n): " CREATE_NEW
+ if [[ $CREATE_NEW =~ ^[Yy]$ ]]; then
+ create_new_settings
+ else
+ echo -e "${RED}Exiting without making changes.${NC}"
+ exit 1
+ fi
+ else
+ # Check if servers element exists
+ if ! xmlstarlet sel -t -v "/settings/servers" "$SETTINGS_PATH" &> /dev/null; then
+ echo -e "${YELLOW}No servers section found. Adding servers section...${NC}"
+ xmlstarlet ed --inplace \
+ -s "/settings" -t elem -n "servers" \
+ -s "/settings/servers" -t elem -n "server" \
+ -s "/settings/servers/server" -t elem -n "id" -v "$SERVER_ID" \
+ -s "/settings/servers/server" -t elem -n "username" -v "$USERNAME" \
+ -s "/settings/servers/server" -t elem -n "password" -v "$PASSWORD" \
+ "$SETTINGS_PATH"
+ else
+ # Check if server with this ID already exists
+ if xmlstarlet sel -t -v "/settings/servers/server[id='$SERVER_ID']" "$SETTINGS_PATH" &> /dev/null; then
+ echo -e "${YELLOW}Server with ID '$SERVER_ID' already exists. Updating credentials...${NC}"
+ # Update existing server credentials
+ xmlstarlet ed --inplace \
+ -u "/settings/servers/server[id='$SERVER_ID']/username" -v "$USERNAME" \
+ -u "/settings/servers/server[id='$SERVER_ID']/password" -v "$PASSWORD" \
+ "$SETTINGS_PATH"
+ else
+ echo -e "${YELLOW}Adding new server with ID '$SERVER_ID'...${NC}"
+ # Add new server to existing servers section
+ xmlstarlet ed --inplace \
+ -s "/settings/servers" -t elem -n "server" \
+ -s "/settings/servers/server[last()]" -t elem -n "id" -v "$SERVER_ID" \
+ -s "/settings/servers/server[last()]" -t elem -n "username" -v "$USERNAME" \
+ -s "/settings/servers/server[last()]" -t elem -n "password" -v "$PASSWORD" \
+ "$SETTINGS_PATH"
+ fi
+ fi
+ fi
+else
+ create_new_settings
+fi
+
+# Make sure the file has the right permissions
+chmod 600 "$SETTINGS_PATH"
+
+echo -e "${GREEN}Maven settings.xml updated successfully at $SETTINGS_PATH${NC}"
+echo -e "${GREEN}Server ID: $SERVER_ID${NC}"
+echo -e "${GREEN}Username: $USERNAME${NC}"
+echo -e "${GREEN}Password: ********${NC}"
+