Skip to content

Commit cd32b16

Browse files
[FSSDK-11161] update: implement CMAB service (#582)
* add: implement CmabDecision class and CmabService interface for CMAB decision handling * add: implement CmabCacheValue and CmabServiceOptions classes for CMAB service functionality * add: extend OptimizelyDecideOption with new cache management options and implement DefaultCmabService class * add: implement DefaultCmabService with decision retrieval and attribute filtering logic * add: implement fetchDecision method in DefaultCmabService for decision retrieval * add: enhance getDecision method in DefaultCmabService with caching logic and attribute filtering * refactor: optimize hashAttributes method using MurmurHash3 and improve null handling * chore: add Apache License 2.0 header to multiple service classes * add: implement unit tests for DefaultCmabService with caching and decision retrieval logic * Empty commit to trigger tests
1 parent b912f62 commit cd32b16

File tree

9 files changed

+791
-1
lines changed

9 files changed

+791
-1
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Copyright 2025, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.optimizely.ab.cmab.service;
17+
18+
import java.util.Objects;
19+
20+
public class CmabCacheValue {
21+
private final String attributesHash;
22+
private final String variationId;
23+
private final String cmabUUID;
24+
25+
public CmabCacheValue(String attributesHash, String variationId, String cmabUUID) {
26+
this.attributesHash = attributesHash;
27+
this.variationId = variationId;
28+
this.cmabUUID = cmabUUID;
29+
}
30+
31+
public String getAttributesHash() {
32+
return attributesHash;
33+
}
34+
35+
public String getVariationId() {
36+
return variationId;
37+
}
38+
39+
public String getCmabUuid() {
40+
return cmabUUID;
41+
}
42+
43+
@Override
44+
public String toString() {
45+
return "CmabCacheValue{" +
46+
"attributesHash='" + attributesHash + '\'' +
47+
", variationId='" + variationId + '\'' +
48+
", cmabUuid='" + cmabUUID + '\'' +
49+
'}';
50+
}
51+
52+
@Override
53+
public boolean equals(Object o) {
54+
if (this == o) return true;
55+
if (o == null || getClass() != o.getClass()) return false;
56+
CmabCacheValue that = (CmabCacheValue) o;
57+
return Objects.equals(attributesHash, that.attributesHash) &&
58+
Objects.equals(variationId, that.variationId) &&
59+
Objects.equals(cmabUUID, that.cmabUUID);
60+
}
61+
62+
@Override
63+
public int hashCode() {
64+
return Objects.hash(attributesHash, variationId, cmabUUID);
65+
}
66+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Copyright 2025, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.optimizely.ab.cmab.service;
17+
18+
import java.util.Objects;
19+
20+
public class CmabDecision {
21+
private final String variationId;
22+
private final String cmabUUID;
23+
24+
public CmabDecision(String variationId, String cmabUUID) {
25+
this.variationId = variationId;
26+
this.cmabUUID = cmabUUID;
27+
}
28+
29+
public String getVariationId() {
30+
return variationId;
31+
}
32+
33+
public String getCmabUUID() {
34+
return cmabUUID;
35+
}
36+
37+
@Override
38+
public String toString() {
39+
return "CmabDecision{" +
40+
"variationId='" + variationId + '\'' +
41+
", cmabUUID='" + cmabUUID + '\'' +
42+
'}';
43+
}
44+
45+
@Override
46+
public boolean equals(Object o) {
47+
if (this == o) return true;
48+
if (o == null || getClass() != o.getClass()) return false;
49+
CmabDecision that = (CmabDecision) o;
50+
return Objects.equals(variationId, that.variationId) &&
51+
Objects.equals(cmabUUID, that.cmabUUID);
52+
}
53+
54+
@Override
55+
public int hashCode() {
56+
return Objects.hash(variationId, cmabUUID);
57+
}
58+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright 2025, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.optimizely.ab.cmab.service;
17+
18+
import java.util.List;
19+
20+
import com.optimizely.ab.OptimizelyUserContext;
21+
import com.optimizely.ab.config.ProjectConfig;
22+
import com.optimizely.ab.optimizelydecision.OptimizelyDecideOption;
23+
24+
public interface CmabService {
25+
/**
26+
* Get variation id for the user
27+
* @param projectConfig the project configuration
28+
* @param userContext the user context
29+
* @param ruleId the rule identifier
30+
* @param options list of decide options
31+
* @return CompletableFuture containing the CMAB decision
32+
*/
33+
CmabDecision getDecision(
34+
ProjectConfig projectConfig,
35+
OptimizelyUserContext userContext,
36+
String ruleId,
37+
List<OptimizelyDecideOption> options
38+
);
39+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Copyright 2025, Optimizely
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.optimizely.ab.cmab.service;
17+
18+
import org.slf4j.Logger;
19+
20+
import com.optimizely.ab.cmab.client.CmabClient;
21+
import com.optimizely.ab.internal.DefaultLRUCache;
22+
23+
public class CmabServiceOptions {
24+
private final Logger logger;
25+
private final DefaultLRUCache<CmabCacheValue> cmabCache;
26+
private final CmabClient cmabClient;
27+
28+
public CmabServiceOptions(DefaultLRUCache<CmabCacheValue> cmabCache, CmabClient cmabClient) {
29+
this(null, cmabCache, cmabClient);
30+
}
31+
32+
public CmabServiceOptions(Logger logger, DefaultLRUCache<CmabCacheValue> cmabCache, CmabClient cmabClient) {
33+
this.logger = logger;
34+
this.cmabCache = cmabCache;
35+
this.cmabClient = cmabClient;
36+
}
37+
38+
public Logger getLogger() {
39+
return logger;
40+
}
41+
42+
public DefaultLRUCache<CmabCacheValue> getCmabCache() {
43+
return cmabCache;
44+
}
45+
46+
public CmabClient getCmabClient() {
47+
return cmabClient;
48+
}
49+
}

0 commit comments

Comments
 (0)