├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── BUG-REPORT.yml │ ├── ENHANCEMENT.yml │ ├── FEATURE-REQUEST.md │ └── config.yml ├── pull_request_template.md └── workflows │ ├── build.yml │ ├── integration_test.yml │ ├── java.yml │ ├── source_clear_cron.yml │ └── ticket_reference_check.yml ├── .gitignore ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.gradle ├── core-api ├── README.md ├── build.gradle └── src │ ├── jmh │ ├── java │ │ └── com │ │ │ └── optimizely │ │ │ └── ab │ │ │ ├── BenchmarkUtils.java │ │ │ ├── OptimizelyBenchmark.java │ │ │ ├── OptimizelyBuilderBenchmark.java │ │ │ └── config │ │ │ └── parser │ │ │ └── JacksonConfigParserBenchmark.java │ └── resources │ │ ├── benchmark.properties │ │ ├── config │ │ ├── profiling-test-data-10-experiments.json │ │ ├── profiling-test-data-25-experiments.json │ │ └── profiling-test-data-50-experiments.json │ │ └── logback.xml │ ├── main │ ├── java │ │ └── com │ │ │ └── optimizely │ │ │ └── ab │ │ │ ├── Optimizely.java │ │ │ ├── OptimizelyDecisionContext.java │ │ │ ├── OptimizelyForcedDecision.java │ │ │ ├── OptimizelyRuntimeException.java │ │ │ ├── OptimizelyUserContext.java │ │ │ ├── UnknownEventTypeException.java │ │ │ ├── UnknownExperimentException.java │ │ │ ├── annotations │ │ │ └── VisibleForTesting.java │ │ │ ├── bucketing │ │ │ ├── Bucketer.java │ │ │ ├── Decision.java │ │ │ ├── DecisionService.java │ │ │ ├── FeatureDecision.java │ │ │ ├── UserProfile.java │ │ │ ├── UserProfileService.java │ │ │ ├── UserProfileTracker.java │ │ │ ├── UserProfileUtils.java │ │ │ └── internal │ │ │ │ └── MurmurHash3.java │ │ │ ├── config │ │ │ ├── AtomicProjectConfigManager.java │ │ │ ├── Attribute.java │ │ │ ├── DatafileProjectConfig.java │ │ │ ├── EventType.java │ │ │ ├── Experiment.java │ │ │ ├── FeatureFlag.java │ │ │ ├── FeatureVariable.java │ │ │ ├── FeatureVariableUsageInstance.java │ │ │ ├── Group.java │ │ │ ├── IdKeyMapped.java │ │ │ ├── IdMapped.java │ │ │ ├── Integration.java │ │ │ ├── PollingProjectConfigManager.java │ │ │ ├── ProjectConfig.java │ │ │ ├── ProjectConfigManager.java │ │ │ ├── ProjectConfigUtils.java │ │ │ ├── Rollout.java │ │ │ ├── TrafficAllocation.java │ │ │ ├── Variation.java │ │ │ ├── audience │ │ │ │ ├── AndCondition.java │ │ │ │ ├── AttributeType.java │ │ │ │ ├── Audience.java │ │ │ │ ├── AudienceIdCondition.java │ │ │ │ ├── Condition.java │ │ │ │ ├── EmptyCondition.java │ │ │ │ ├── LeafCondition.java │ │ │ │ ├── NotCondition.java │ │ │ │ ├── NullCondition.java │ │ │ │ ├── OrCondition.java │ │ │ │ ├── TypedAudience.java │ │ │ │ ├── UserAttribute.java │ │ │ │ └── match │ │ │ │ │ ├── DefaultMatchForLegacyAttributes.java │ │ │ │ │ ├── ExactMatch.java │ │ │ │ │ ├── ExistsMatch.java │ │ │ │ │ ├── GEMatch.java │ │ │ │ │ ├── GTMatch.java │ │ │ │ │ ├── LEMatch.java │ │ │ │ │ ├── LTMatch.java │ │ │ │ │ ├── Match.java │ │ │ │ │ ├── MatchRegistry.java │ │ │ │ │ ├── NumberComparator.java │ │ │ │ │ ├── SemanticVersion.java │ │ │ │ │ ├── SemanticVersionEqualsMatch.java │ │ │ │ │ ├── SemanticVersionGEMatch.java │ │ │ │ │ ├── SemanticVersionGTMatch.java │ │ │ │ │ ├── SemanticVersionLEMatch.java │ │ │ │ │ ├── SemanticVersionLTMatch.java │ │ │ │ │ ├── SubstringMatch.java │ │ │ │ │ ├── UnexpectedValueTypeException.java │ │ │ │ │ ├── UnknownMatchTypeException.java │ │ │ │ │ └── UnknownValueTypeException.java │ │ │ └── parser │ │ │ │ ├── AudienceGsonDeserializer.java │ │ │ │ ├── AudienceJacksonDeserializer.java │ │ │ │ ├── ConditionJacksonDeserializer.java │ │ │ │ ├── ConfigParseException.java │ │ │ │ ├── ConfigParser.java │ │ │ │ ├── DatafileGsonDeserializer.java │ │ │ │ ├── DatafileJacksonDeserializer.java │ │ │ │ ├── DefaultConfigParser.java │ │ │ │ ├── ExperimentGsonDeserializer.java │ │ │ │ ├── FeatureFlagGsonDeserializer.java │ │ │ │ ├── GroupGsonDeserializer.java │ │ │ │ ├── GsonConfigParser.java │ │ │ │ ├── GsonHelpers.java │ │ │ │ ├── JacksonConfigParser.java │ │ │ │ ├── JacksonHelpers.java │ │ │ │ ├── JsonConfigParser.java │ │ │ │ ├── JsonHelpers.java │ │ │ │ ├── JsonParseException.java │ │ │ │ ├── JsonSimpleConfigParser.java │ │ │ │ ├── MissingJsonParserException.java │ │ │ │ └── TypedAudienceJacksonDeserializer.java │ │ │ ├── error │ │ │ ├── ErrorHandler.java │ │ │ ├── NoOpErrorHandler.java │ │ │ └── RaiseExceptionErrorHandler.java │ │ │ ├── event │ │ │ ├── BatchEventProcessor.java │ │ │ ├── EventHandler.java │ │ │ ├── EventProcessor.java │ │ │ ├── ForwardingEventProcessor.java │ │ │ ├── LogEvent.java │ │ │ ├── NoopEventHandler.java │ │ │ └── internal │ │ │ │ ├── BaseEvent.java │ │ │ │ ├── BuildVersionInfo.java │ │ │ │ ├── ClientEngineInfo.java │ │ │ │ ├── ConversionEvent.java │ │ │ │ ├── EventFactory.java │ │ │ │ ├── ImpressionEvent.java │ │ │ │ ├── UserContext.java │ │ │ │ ├── UserEvent.java │ │ │ │ ├── UserEventFactory.java │ │ │ │ ├── payload │ │ │ │ ├── Attribute.java │ │ │ │ ├── Decision.java │ │ │ │ ├── DecisionMetadata.java │ │ │ │ ├── Event.java │ │ │ │ ├── EventBatch.java │ │ │ │ ├── Snapshot.java │ │ │ │ └── Visitor.java │ │ │ │ └── serializer │ │ │ │ ├── DefaultJsonSerializer.java │ │ │ │ ├── GsonSerializer.java │ │ │ │ ├── JacksonSerializer.java │ │ │ │ ├── JsonSerializer.java │ │ │ │ ├── JsonSimpleSerializer.java │ │ │ │ ├── SerializationException.java │ │ │ │ └── Serializer.java │ │ │ ├── internal │ │ │ ├── AttributesUtil.java │ │ │ ├── Cache.java │ │ │ ├── ConditionUtils.java │ │ │ ├── ControlAttribute.java │ │ │ ├── DefaultLRUCache.java │ │ │ ├── EventTagUtils.java │ │ │ ├── ExperimentUtils.java │ │ │ ├── InvalidAudienceCondition.java │ │ │ ├── JsonParserProvider.java │ │ │ ├── LoggingConstants.java │ │ │ ├── NotificationRegistry.java │ │ │ ├── PropertyUtils.java │ │ │ ├── ReservedEventKey.java │ │ │ └── SafetyUtils.java │ │ │ ├── notification │ │ │ ├── ActivateNotification.java │ │ │ ├── ActivateNotificationListener.java │ │ │ ├── ActivateNotificationListenerInterface.java │ │ │ ├── DecisionNotification.java │ │ │ ├── FeatureTestSourceInfo.java │ │ │ ├── NotificationCenter.java │ │ │ ├── NotificationHandler.java │ │ │ ├── NotificationListener.java │ │ │ ├── NotificationManager.java │ │ │ ├── RolloutSourceInfo.java │ │ │ ├── SourceInfo.java │ │ │ ├── TrackNotification.java │ │ │ ├── TrackNotificationListener.java │ │ │ ├── TrackNotificationListenerInterface.java │ │ │ └── UpdateConfigNotification.java │ │ │ ├── odp │ │ │ ├── ODPApiManager.java │ │ │ ├── ODPConfig.java │ │ │ ├── ODPEvent.java │ │ │ ├── ODPEventManager.java │ │ │ ├── ODPManager.java │ │ │ ├── ODPSegmentCallback.java │ │ │ ├── ODPSegmentManager.java │ │ │ ├── ODPSegmentOption.java │ │ │ ├── ODPUserKey.java │ │ │ ├── parser │ │ │ │ ├── ResponseJsonParser.java │ │ │ │ ├── ResponseJsonParserFactory.java │ │ │ │ └── impl │ │ │ │ │ ├── GsonParser.java │ │ │ │ │ ├── JacksonParser.java │ │ │ │ │ ├── JsonParser.java │ │ │ │ │ └── JsonSimpleParser.java │ │ │ └── serializer │ │ │ │ ├── ODPJsonSerializer.java │ │ │ │ ├── ODPJsonSerializerFactory.java │ │ │ │ └── impl │ │ │ │ ├── GsonSerializer.java │ │ │ │ ├── JacksonSerializer.java │ │ │ │ ├── JsonSerializer.java │ │ │ │ └── JsonSimpleSerializer.java │ │ │ ├── optimizelyconfig │ │ │ ├── OptimizelyAttribute.java │ │ │ ├── OptimizelyAudience.java │ │ │ ├── OptimizelyConfig.java │ │ │ ├── OptimizelyConfigManager.java │ │ │ ├── OptimizelyConfigService.java │ │ │ ├── OptimizelyEvent.java │ │ │ ├── OptimizelyExperiment.java │ │ │ ├── OptimizelyFeature.java │ │ │ ├── OptimizelyVariable.java │ │ │ └── OptimizelyVariation.java │ │ │ ├── optimizelydecision │ │ │ ├── DecisionMessage.java │ │ │ ├── DecisionReasons.java │ │ │ ├── DecisionResponse.java │ │ │ ├── DefaultDecisionReasons.java │ │ │ ├── OptimizelyDecideOption.java │ │ │ └── OptimizelyDecision.java │ │ │ └── optimizelyjson │ │ │ └── OptimizelyJSON.java │ └── resources │ │ └── .gitignore │ └── test │ ├── java │ └── com │ │ └── optimizely │ │ └── ab │ │ ├── EventHandlerRule.java │ │ ├── OptimizelyBuilderTest.java │ │ ├── OptimizelyDecisionContextTest.java │ │ ├── OptimizelyForcedDecisionTest.java │ │ ├── OptimizelyRule.java │ │ ├── OptimizelyTest.java │ │ ├── OptimizelyUserContextTest.java │ │ ├── bucketing │ │ ├── BucketerTest.java │ │ ├── DecisionServiceTest.java │ │ └── internal │ │ │ └── MurmurHash3Test.java │ │ ├── categories │ │ └── ExhaustiveTest.java │ │ ├── config │ │ ├── AtomicProjectConfigManagerTest.java │ │ ├── DatafileProjectConfigBuilderTest.java │ │ ├── DatafileProjectConfigTest.java │ │ ├── DatafileProjectConfigTestUtils.java │ │ ├── ExperimentTest.java │ │ ├── PollingProjectConfigManagerTest.java │ │ ├── ValidProjectConfigV4.java │ │ ├── VariationTest.java │ │ ├── audience │ │ │ ├── AudienceConditionEvaluationTest.java │ │ │ └── match │ │ │ │ ├── ExactMatchTest.java │ │ │ │ ├── MatchRegistryTest.java │ │ │ │ ├── NumberComparatorTest.java │ │ │ │ ├── SemanticVersionTest.java │ │ │ │ └── SubstringMatchTest.java │ │ └── parser │ │ │ ├── DefaultConfigParserTest.java │ │ │ ├── GsonConfigParserTest.java │ │ │ ├── JacksonConfigParserTest.java │ │ │ ├── JsonConfigParserTest.java │ │ │ ├── JsonHelpersTest.java │ │ │ └── JsonSimpleConfigParserTest.java │ │ ├── error │ │ └── RaiseExceptionErrorHandlerTest.java │ │ ├── event │ │ ├── BatchEventProcessorTest.java │ │ ├── ForwardingEventProcessorTest.java │ │ ├── LogEventTest.java │ │ ├── NoopEventHandlerTest.java │ │ └── internal │ │ │ ├── BaseEventTest.java │ │ │ ├── ClientEngineInfoTest.java │ │ │ ├── ConversionEventTest.java │ │ │ ├── EventFactoryTest.java │ │ │ ├── ImpressionEventTest.java │ │ │ ├── UserEventFactoryTest.java │ │ │ └── serializer │ │ │ ├── GsonSerializerTest.java │ │ │ ├── JacksonSerializerTest.java │ │ │ ├── JsonSerializerTest.java │ │ │ ├── JsonSimpleSerializerTest.java │ │ │ └── SerializerTestUtils.java │ │ ├── internal │ │ ├── DefaultLRUCacheTest.java │ │ ├── ExperimentUtilsTest.java │ │ ├── JsonParserProviderTest.java │ │ ├── LogbackVerifier.java │ │ ├── NotificationRegistryTest.java │ │ ├── PropertyUtilTest.java │ │ └── SafetyUtilsTest.java │ │ ├── notification │ │ ├── ActivateNotificationListenerTest.java │ │ ├── ActivateNotificationTest.java │ │ ├── DecisionNotificationTest.java │ │ ├── FeatureTestSourceInfoTest.java │ │ ├── NotificationCenterTest.java │ │ ├── NotificationManagerTest.java │ │ ├── RolloutSourceInfoTest.java │ │ ├── TestNotification.java │ │ ├── TestNotificationHandler.java │ │ ├── TrackNotificationListenerTest.java │ │ └── TrackNotificationTest.java │ │ ├── odp │ │ ├── ODPEventManagerTest.java │ │ ├── ODPManagerBuilderTest.java │ │ ├── ODPManagerTest.java │ │ ├── ODPSegmentManagerTest.java │ │ ├── parser │ │ │ ├── ResponseJsonParserFactoryTest.java │ │ │ └── ResponseJsonParserTest.java │ │ └── serializer │ │ │ ├── ODPJsonSerializerFactoryTest.java │ │ │ └── ODPJsonSerializerTest.java │ │ ├── optimizelyconfig │ │ ├── OptimizelyAttributeTest.java │ │ ├── OptimizelyConfigServiceTest.java │ │ ├── OptimizelyConfigTest.java │ │ ├── OptimizelyEventTest.java │ │ ├── OptimizelyExperimentTest.java │ │ ├── OptimizelyFeatureTest.java │ │ ├── OptimizelyVariableTest.java │ │ └── OptimizelyVariationTest.java │ │ ├── optimizelydecision │ │ └── OptimizelyDecisionTest.java │ │ ├── optimizelyjson │ │ ├── OptimizelyJSONTest.java │ │ ├── OptimizelyJSONWithGsonParserTest.java │ │ ├── OptimizelyJSONWithJacksonParserTest.java │ │ ├── OptimizelyJSONWithJsonParserTest.java │ │ ├── OptimizelyJSONWithJsonSimpleParserTest.java │ │ └── TestTypes.java │ │ └── testutils │ │ └── OTUtils.java │ └── resources │ ├── config │ ├── decide-project-config.json │ ├── invalid-project-config-v5.json │ ├── no-audience-project-config-v2.json │ ├── no-audience-project-config-v3.json │ ├── null-featureEnabled-config-v4.json │ ├── valid-project-config-v2.json │ ├── valid-project-config-v3.json │ └── valid-project-config-v4.json │ ├── optimizely.properties │ └── serializer │ ├── conversion-session-id.json │ ├── conversion.json │ ├── impression-session-id.json │ └── impression.json ├── core-httpclient-impl ├── README.md ├── build.gradle └── src │ ├── main │ └── java │ │ └── com │ │ └── optimizely │ │ └── ab │ │ ├── HttpClientUtils.java │ │ ├── NamedThreadFactory.java │ │ ├── OptimizelyFactory.java │ │ ├── OptimizelyHttpClient.java │ │ ├── config │ │ └── HttpProjectConfigManager.java │ │ ├── event │ │ └── AsyncEventHandler.java │ │ └── odp │ │ └── DefaultODPApiManager.java │ └── test │ ├── java │ └── com │ │ └── optimizely │ │ └── ab │ │ ├── OptimizelyFactoryTest.java │ │ ├── OptimizelyHttpClientTest.java │ │ ├── config │ │ └── HttpProjectConfigManagerTest.java │ │ ├── event │ │ └── AsyncEventHandlerTest.java │ │ ├── internal │ │ └── LogbackVerifier.java │ │ └── odp │ │ └── DefaultODPApiManagerTest.java │ └── resources │ └── valid-project-config-v4.json ├── docs └── readme.md ├── gradle.properties ├── gradle ├── publish.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── java-quickstart ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── libs │ ├── core-api-2.0.0-SNAPSHOT.jar │ ├── core-api.jar │ ├── core-httpclient-impl-2.0.0-SNAPSHOT.jar │ └── core-httpclient-impl.jar └── src │ └── main │ ├── java │ └── com │ │ └── optimizely │ │ └── Example.java │ └── resources │ └── log4j2.properties ├── resources └── HEADER └── settings.gradle /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # 4 space indentation 7 | [*.{py,java}] 8 | indent_style = space 9 | indent_size = 4 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ENHANCEMENT.yml: -------------------------------------------------------------------------------- 1 | name: ✨Enhancement 2 | description: Create a new ticket for a Enhancement/Tech-initiative for the benefit of the SDK which would be considered for a minor version update. 3 | title: "[ENHANCEMENT] " 4 | labels: ["enhancement"] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: "Description" 10 | description: Briefly describe the enhancement in a few sentences. 11 | placeholder: Short description... 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: benefits 16 | attributes: 17 | label: "Benefits" 18 | description: How would the enhancement benefit to your product or usage? 19 | placeholder: Benefits... 20 | validations: 21 | required: true 22 | - type: textarea 23 | id: detail 24 | attributes: 25 | label: "Detail" 26 | description: How would you like the enhancement to work? Please provide as much detail as possible 27 | placeholder: Detailed description... 28 | validations: 29 | required: false 30 | - type: textarea 31 | id: examples 32 | attributes: 33 | label: "Examples" 34 | description: Are there any examples of this enhancement in other products/services? If so, please provide links or references. 35 | placeholder: Links/References... 36 | validations: 37 | required: false 38 | - type: textarea 39 | id: risks 40 | attributes: 41 | label: "Risks/Downsides" 42 | description: Do you think this enhancement could have any potential downsides or risks? 43 | placeholder: Risks/Downsides... 44 | validations: 45 | required: false 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE-REQUEST.md: -------------------------------------------------------------------------------- 1 | <!-- 2 | Thanks for filing in issue! Are you requesting a new feature? If so, please share your feedback with us on the following link. 3 | --> 4 | ## Feedback requesting a new feature can be shared [here.](https://feedback.optimizely.com/) 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 💡Feature Requests 4 | url: https://feedback.optimizely.com/ 5 | about: Feedback requesting a new feature can be shared here. 6 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | - The "what"; a concise description of each logical change 3 | - Another change 4 | 5 | The "why", or other context. 6 | 7 | ## Test plan 8 | 9 | ## Issues 10 | - "THING-1234" or "Fixes #123" -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Reusable action of building snapshot and publish 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | action: 7 | required: true 8 | type: string 9 | github_tag: 10 | required: true 11 | type: string 12 | secrets: 13 | MAVEN_SIGNING_KEY_BASE64: 14 | required: true 15 | MAVEN_SIGNING_PASSPHRASE: 16 | required: true 17 | MAVEN_CENTRAL_USERNAME: 18 | required: true 19 | MAVEN_CENTRAL_PASSWORD: 20 | required: true 21 | jobs: 22 | run_build: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - name: set up JDK 8 27 | uses: actions/setup-java@v2 28 | with: 29 | java-version: '8' 30 | distribution: 'temurin' 31 | - name: Grant execute permission for gradlew 32 | run: chmod +x gradlew 33 | - name: ${{ inputs.action }} 34 | env: 35 | MAVEN_SIGNING_KEY_BASE64: ${{ secrets.MAVEN_SIGNING_KEY_BASE64 }} 36 | MAVEN_SIGNING_PASSPHRASE: ${{ secrets.MAVEN_SIGNING_PASSPHRASE }} 37 | MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 38 | MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 39 | run: GITHUB_TAG=${{ inputs.github_tag }} ./gradlew ${{ inputs.action }} 40 | -------------------------------------------------------------------------------- /.github/workflows/integration_test.yml: -------------------------------------------------------------------------------- 1 | name: Reusable action of running integration of production suite 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | FULLSTACK_TEST_REPO: 7 | required: false 8 | type: string 9 | secrets: 10 | CI_USER_TOKEN: 11 | required: true 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | # You should create a personal access token and store it in your repository 19 | token: ${{ secrets.CI_USER_TOKEN }} 20 | repository: 'optimizely/ci-helper-tools' 21 | path: 'home/runner/ci-helper-tools' 22 | ref: 'master' 23 | - name: set SDK Branch if PR 24 | env: 25 | HEAD_REF: ${{ github.head_ref }} 26 | if: ${{ github.event_name == 'pull_request' }} 27 | run: | 28 | echo "SDK_BRANCH=$HEAD_REF" >> $GITHUB_ENV 29 | - name: set SDK Branch if not pull request 30 | env: 31 | REF_NAME: ${{ github.ref_name }} 32 | if: ${{ github.event_name != 'pull_request' }} 33 | run: | 34 | echo "SDK_BRANCH=$REF_NAME" >> $GITHUB_ENV 35 | - name: Trigger build 36 | env: 37 | SDK: java 38 | FULLSTACK_TEST_REPO: ${{ inputs.FULLSTACK_TEST_REPO }} 39 | BUILD_NUMBER: ${{ github.run_id }} 40 | TESTAPP_BRANCH: master 41 | GITHUB_TOKEN: ${{ secrets.CI_USER_TOKEN }} 42 | EVENT_TYPE: ${{ github.event_name }} 43 | GITHUB_CONTEXT: ${{ toJson(github) }} 44 | PULL_REQUEST_SLUG: ${{ github.repository }} 45 | UPSTREAM_REPO: ${{ github.repository }} 46 | PULL_REQUEST_SHA: ${{ github.event.pull_request.head.sha }} 47 | PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} 48 | UPSTREAM_SHA: ${{ github.sha }} 49 | EVENT_MESSAGE: ${{ github.event.message }} 50 | HOME: 'home/runner' 51 | run: | 52 | echo "$GITHUB_CONTEXT" 53 | home/runner/ci-helper-tools/trigger-script-with-status-update.sh 54 | -------------------------------------------------------------------------------- /.github/workflows/source_clear_cron.yml: -------------------------------------------------------------------------------- 1 | name: Source clear 2 | 3 | on: 4 | schedule: 5 | # Runs "weekly" 6 | - cron: '0 0 * * 0' 7 | 8 | jobs: 9 | source_clear: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Source clear scan 14 | env: 15 | SRCCLR_API_TOKEN: ${{ secrets.SRCCLR_API_TOKEN }} 16 | run: curl -sSL https://download.sourceclear.com/ci.sh | bash -s – scan 17 | -------------------------------------------------------------------------------- /.github/workflows/ticket_reference_check.yml: -------------------------------------------------------------------------------- 1 | name: Jira ticket reference check 2 | 3 | on: 4 | pull_request: 5 | types: [opened, edited, reopened, synchronize] 6 | 7 | jobs: 8 | 9 | jira_ticket_reference_check: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Check for Jira ticket reference 14 | uses: optimizely/github-action-ticket-reference-checker-public@master 15 | with: 16 | bodyRegex: 'FSSDK-(?<ticketNumber>\d+)' 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.un~ 2 | .gradle 3 | .settings 4 | *.swp 5 | 6 | # intellij config files 7 | *.iml 8 | *.ipr 9 | *.iml 10 | *.iws 11 | .idea 12 | 13 | # eclipse config files 14 | .classpath 15 | .project 16 | 17 | # android studio config files 18 | local.properties 19 | 20 | **/build 21 | bin 22 | out 23 | classes 24 | 25 | .vagrant 26 | .DS_Store 27 | .venv 28 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a comment. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in the repo. 5 | # Unless a later match takes precedence, @global-owner1 and @global-owner2 6 | # will be requested for review when someone opens a pull request. 7 | * @optimizely/fullstack-devs 8 | 9 | # Order is important; the last matching pattern takes the most precedence. 10 | # When someone opens a pull request that only modifies JS files, only @js-owner 11 | # and not the global owner(s) will be requested for a review. 12 | #*.js @js-owner 13 | 14 | # You can also use email addresses if you prefer. They'll be used to look up 15 | # users just like we do for commit author emails. 16 | #docs/* docs@example.com 17 | -------------------------------------------------------------------------------- /core-api/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion 3 | implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: jacksonVersion 4 | implementation group: 'com.google.code.findbugs', name: 'annotations', version: findbugsAnnotationVersion 5 | implementation group: 'com.google.code.findbugs', name: 'jsr305', version: findbugsJsrVersion 6 | testImplementation group: 'junit', name: 'junit', version: junitVersion 7 | testImplementation group: 'ch.qos.logback', name: 'logback-classic', version: logbackVersion 8 | 9 | // an assortment of json parsers 10 | compileOnly group: 'com.google.code.gson', name: 'gson', version: gsonVersion, optional 11 | compileOnly group: 'org.json', name: 'json', version: jsonVersion, optional 12 | compileOnly group: 'com.googlecode.json-simple', name: 'json-simple', version: jsonSimpleVersion, optional 13 | compileOnly group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion, optional 14 | } 15 | 16 | tasks.named('processJmhResources') { 17 | duplicatesStrategy = DuplicatesStrategy.WARN 18 | } 19 | 20 | 21 | test { 22 | useJUnit { 23 | excludeCategories 'com.optimizely.ab.categories.ExhaustiveTest' 24 | } 25 | } 26 | 27 | task exhaustiveTest(type: Test) { 28 | useJUnit { 29 | includeCategories 'com.optimizely.ab.categories.ExhaustiveTest' 30 | } 31 | } 32 | 33 | 34 | task generateVersionFile { 35 | // add the build version information into a file that'll go into the distribution 36 | ext.buildVersion = new File(projectDir, "src/main/resources/optimizely-build-version") 37 | buildVersion.text = version 38 | } 39 | 40 | build.finalizedBy(generateVersionFile) 41 | -------------------------------------------------------------------------------- /core-api/src/jmh/java/com/optimizely/ab/BenchmarkUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab; 18 | 19 | import com.google.common.base.Charsets; 20 | import com.google.common.io.Resources; 21 | 22 | import java.io.IOException; 23 | 24 | public final class BenchmarkUtils { 25 | 26 | private BenchmarkUtils() {} 27 | 28 | public static String getProfilingDatafile(String datafilePath) throws IOException { 29 | return Resources.toString(Resources.getResource(datafilePath), Charsets.UTF_8); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core-api/src/jmh/java/com/optimizely/ab/config/parser/JacksonConfigParserBenchmark.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2019 Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | import com.optimizely.ab.config.ProjectConfig; 20 | import com.optimizely.ab.config.DatafileProjectConfigTestUtils; 21 | import org.openjdk.jmh.annotations.*; 22 | 23 | import java.io.IOException; 24 | import java.util.concurrent.TimeUnit; 25 | 26 | @BenchmarkMode(Mode.AverageTime) 27 | @OutputTimeUnit(TimeUnit.MICROSECONDS) 28 | @Fork(2) 29 | @Warmup(iterations = 10) 30 | @Measurement(iterations = 20) 31 | @State(Scope.Benchmark) 32 | public class JacksonConfigParserBenchmark { 33 | JacksonConfigParser parser; 34 | String jsonV2; 35 | String jsonV3; 36 | String jsonV4; 37 | 38 | @Setup 39 | public void setUp() throws IOException { 40 | parser = new JacksonConfigParser(); 41 | jsonV2 = DatafileProjectConfigTestUtils.validConfigJsonV2(); 42 | jsonV3 = DatafileProjectConfigTestUtils.validConfigJsonV3(); 43 | jsonV4 = DatafileProjectConfigTestUtils.validConfigJsonV4(); 44 | } 45 | 46 | @Benchmark 47 | public ProjectConfig parseV2() throws ConfigParseException { 48 | return parser.parseProjectConfig(jsonV2); 49 | } 50 | 51 | @Benchmark 52 | public ProjectConfig parseV3() throws ConfigParseException { 53 | return parser.parseProjectConfig(jsonV3); 54 | } 55 | 56 | @Benchmark 57 | public ProjectConfig parseV4() throws ConfigParseException { 58 | return parser.parseProjectConfig(jsonV4); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /core-api/src/jmh/resources/benchmark.properties: -------------------------------------------------------------------------------- 1 | datafilePathTemplate=config/profiling-test-data-%d-experiments.json 2 | activateGroupExperimentUserIdPropTemplate=activateGroupExperiment%dExperimentsUserId 3 | activateGroupExperiment10ExperimentsUserId=no 4 | activateGroupExperiment25ExperimentsUserId=test 5 | activateGroupExperiment50ExperimentsUserId=optimizely_user 6 | 7 | activateGroupExperimentAttributesUserIdPropTemplate=activateGroupExperimentAttributes%dExperimentsUserId 8 | activateGroupExperimentAttributes10ExperimentsUserId=test 9 | activateGroupExperimentAttributes25ExperimentsUserId=yes 10 | activateGroupExperimentAttributes50ExperimentsUserId=test 11 | 12 | trackGroupExperimentUserIdPropTemplate=trackGroupExperiment%dExperimentsUserId 13 | trackGroupExperiment10ExperimentsUserId=no 14 | trackGroupExperiment25ExperimentsUserId=optimizely_user 15 | trackGroupExperiment50ExperimentsUserId=optimizely_user 16 | 17 | trackGroupExperimentAttributesUserIdPropTemplate=trackGroupExperimentAttributes%dExperimentsUserId 18 | trackGroupExperimentAttributes10ExperimentsUserId=optimizely_user 19 | trackGroupExperimentAttributes25ExperimentsUserId=yes 20 | trackGroupExperimentAttributes50ExperimentsUserId=test -------------------------------------------------------------------------------- /core-api/src/jmh/resources/logback.xml: -------------------------------------------------------------------------------- 1 | <configuration> 2 | <root level="warn"/> 3 | </configuration> -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/OptimizelyDecisionContext.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2021, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | 22 | public class OptimizelyDecisionContext { 23 | public static final String OPTI_NULL_RULE_KEY = "$opt-null-rule-key"; 24 | public static final String OPTI_KEY_DIVIDER = "-$opt$-"; 25 | 26 | private String flagKey; 27 | private String ruleKey; 28 | 29 | public OptimizelyDecisionContext(@Nonnull String flagKey, @Nullable String ruleKey) { 30 | if (flagKey == null) throw new NullPointerException("FlagKey must not be null, please provide a valid input."); 31 | this.flagKey = flagKey; 32 | this.ruleKey = ruleKey; 33 | } 34 | 35 | public String getFlagKey() { 36 | return flagKey; 37 | } 38 | 39 | public String getRuleKey() { 40 | return ruleKey != null ? ruleKey : OPTI_NULL_RULE_KEY; 41 | } 42 | 43 | public String getKey() { 44 | StringBuilder keyBuilder = new StringBuilder(); 45 | keyBuilder.append(flagKey); 46 | keyBuilder.append(OPTI_KEY_DIVIDER); 47 | keyBuilder.append(getRuleKey()); 48 | return keyBuilder.toString(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/OptimizelyForcedDecision.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2021, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | public class OptimizelyForcedDecision { 22 | private String variationKey; 23 | 24 | public OptimizelyForcedDecision(@Nonnull String variationKey) { 25 | this.variationKey = variationKey; 26 | } 27 | 28 | public String getVariationKey() { 29 | return variationKey; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/OptimizelyRuntimeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab; 18 | 19 | /** 20 | * Base class for all Optimizely Exceptions. 21 | */ 22 | public class OptimizelyRuntimeException extends RuntimeException { 23 | 24 | public OptimizelyRuntimeException() { 25 | } 26 | 27 | public OptimizelyRuntimeException(Exception exception) { 28 | super(exception); 29 | } 30 | 31 | public OptimizelyRuntimeException(String message) { 32 | super(message); 33 | } 34 | 35 | public OptimizelyRuntimeException(String message, Throwable cause) { 36 | super(message, cause); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/UnknownEventTypeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019 Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab; 18 | 19 | import com.optimizely.ab.config.ProjectConfig; 20 | import com.optimizely.ab.config.EventType; 21 | 22 | /** 23 | * Exception thrown when attempting to use/refer to an {@link EventType} that isn't present in the current 24 | * {@link ProjectConfig}. 25 | */ 26 | public class UnknownEventTypeException extends OptimizelyRuntimeException { 27 | 28 | public UnknownEventTypeException(String message) { 29 | super(message); 30 | } 31 | 32 | public UnknownEventTypeException(String message, Throwable cause) { 33 | super(message, cause); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/UnknownExperimentException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019 Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab; 18 | 19 | import com.optimizely.ab.config.ProjectConfig; 20 | import com.optimizely.ab.config.Experiment; 21 | 22 | /** 23 | * Exception thrown when attempting to use/refer to an {@link Experiment} that isn't present in the current 24 | * {@link ProjectConfig}. 25 | * <p> 26 | * This may occur if code changes are made prior to the experiment being setup in the Optimizely application. 27 | */ 28 | public class UnknownExperimentException extends OptimizelyRuntimeException { 29 | 30 | public UnknownExperimentException(String message) { 31 | super(message); 32 | } 33 | 34 | public UnknownExperimentException(String message, Throwable cause) { 35 | super(message, cause); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/annotations/VisibleForTesting.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.annotations; 18 | 19 | /** 20 | * Indicates that the annotated resources is non-private for testing purposes only. 21 | */ 22 | public @interface VisibleForTesting { } 23 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/AtomicProjectConfigManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, 2023, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | import java.util.concurrent.atomic.AtomicReference; 20 | 21 | public class AtomicProjectConfigManager implements ProjectConfigManager { 22 | 23 | private final AtomicReference<ProjectConfig> projectConfigReference = new AtomicReference<>(); 24 | 25 | @Override 26 | public ProjectConfig getConfig() { 27 | return projectConfigReference.get(); 28 | } 29 | 30 | /** 31 | * Access to current cached project configuration. 32 | * 33 | * @return {@link ProjectConfig} 34 | */ 35 | @Override 36 | public ProjectConfig getCachedConfig() { 37 | return projectConfigReference.get(); 38 | } 39 | 40 | @Override 41 | public String getSDKKey() { 42 | return null; 43 | } 44 | 45 | public void setConfig(ProjectConfig projectConfig) { 46 | projectConfigReference.set(projectConfig); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/Attribute.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | import com.fasterxml.jackson.annotation.JsonCreator; 20 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 21 | import com.fasterxml.jackson.annotation.JsonProperty; 22 | 23 | import javax.annotation.concurrent.Immutable; 24 | 25 | /** 26 | * Represents the Optimizely Attribute configuration. 27 | * 28 | * @see <a href="http://developers.optimizely.com/server/reference/index.html#json">Project JSON</a> 29 | */ 30 | @Immutable 31 | @JsonIgnoreProperties(ignoreUnknown = true) 32 | public class Attribute implements IdKeyMapped { 33 | 34 | private final String id; 35 | private final String key; 36 | private final String segmentId; 37 | 38 | public Attribute(String id, String key) { 39 | this(id, key, null); 40 | } 41 | 42 | @JsonCreator 43 | public Attribute(@JsonProperty("id") String id, 44 | @JsonProperty("key") String key, 45 | @JsonProperty("segmentId") String segmentId) { 46 | this.id = id; 47 | this.key = key; 48 | this.segmentId = segmentId; 49 | } 50 | 51 | public String getId() { 52 | return id; 53 | } 54 | 55 | public String getKey() { 56 | return key; 57 | } 58 | 59 | public String getSegmentId() { 60 | return segmentId; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return "Attribute{" + 66 | "id='" + id + '\'' + 67 | ", key='" + key + '\'' + 68 | ", segmentId='" + segmentId + '\'' + 69 | '}'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/FeatureVariableUsageInstance.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | import com.fasterxml.jackson.annotation.JsonCreator; 20 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 21 | import com.fasterxml.jackson.annotation.JsonProperty; 22 | 23 | /** 24 | * Represents the value of a feature variable for a variation 25 | */ 26 | @JsonIgnoreProperties(ignoreUnknown = true) 27 | public class FeatureVariableUsageInstance implements IdMapped { 28 | 29 | private final String id; 30 | private final String value; 31 | 32 | @JsonCreator 33 | public FeatureVariableUsageInstance(@JsonProperty("id") String id, 34 | @JsonProperty("value") String value) { 35 | this.id = id; 36 | this.value = value; 37 | } 38 | 39 | public String getId() { 40 | return id; 41 | } 42 | 43 | public String getValue() { 44 | return value; 45 | } 46 | 47 | @Override 48 | public boolean equals(Object o) { 49 | if (this == o) return true; 50 | if (o == null || getClass() != o.getClass()) return false; 51 | 52 | FeatureVariableUsageInstance that = (FeatureVariableUsageInstance) o; 53 | 54 | return id.equals(that.id) && value.equals(that.value); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | int result = id.hashCode(); 60 | result = 31 * result + value.hashCode(); 61 | return result; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/IdKeyMapped.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | /** 20 | * Represents that an implementing class provides a {@literal key <-> id} mapping. 21 | */ 22 | public interface IdKeyMapped extends IdMapped { 23 | String getKey(); 24 | } 25 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/IdMapped.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | /** 20 | * Base interface to help with templated convenience mappings. 21 | */ 22 | public interface IdMapped { 23 | String getId(); 24 | } 25 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/Integration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | import com.fasterxml.jackson.annotation.JsonCreator; 20 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 21 | import com.fasterxml.jackson.annotation.JsonProperty; 22 | 23 | import javax.annotation.Nonnull; 24 | import javax.annotation.Nullable; 25 | import javax.annotation.concurrent.Immutable; 26 | 27 | /** 28 | * Represents the Optimizely Integration configuration. 29 | * 30 | * @see <a href="http://developers.optimizely.com/server/reference/index.html#json">Project JSON</a> 31 | */ 32 | @Immutable 33 | @JsonIgnoreProperties(ignoreUnknown = true) 34 | public class Integration { 35 | private final String key; 36 | private final String host; 37 | private final String publicKey; 38 | 39 | @JsonCreator 40 | public Integration(@JsonProperty("key") String key, 41 | @JsonProperty("host") String host, 42 | @JsonProperty("publicKey") String publicKey) { 43 | this.key = key; 44 | this.host = host; 45 | this.publicKey = publicKey; 46 | } 47 | 48 | @Nonnull 49 | public String getKey() { 50 | return key; 51 | } 52 | 53 | @Nullable 54 | public String getHost() { return host; } 55 | 56 | @Nullable 57 | public String getPublicKey() { return publicKey; } 58 | 59 | @Override 60 | public String toString() { 61 | return "Integration{" + 62 | "key='" + key + '\'' + 63 | ((this.host != null) ? (", host='" + host + '\'') : "") + 64 | ((this.publicKey != null) ? (", publicKey='" + publicKey + '\'') : "") + 65 | '}'; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/ProjectConfigManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, 2023, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | public interface ProjectConfigManager { 22 | /** 23 | * Implementations of this method should block until a datafile is available. 24 | * 25 | * @return ProjectConfig 26 | */ 27 | ProjectConfig getConfig(); 28 | 29 | /** 30 | * Implementations of this method should not block until a datafile is available, instead return current cached project configuration. 31 | * return null if ProjectConfig is not ready at the moment. 32 | * 33 | * NOTE: To use ODP segments, implementation of this function is required to return current project configuration. 34 | * @return ProjectConfig 35 | */ 36 | @Nullable 37 | ProjectConfig getCachedConfig(); 38 | 39 | /** 40 | * Implementations of this method should return SDK key. If there is no SDKKey then it should return null. 41 | * 42 | * NOTE: To update ODP segments configuration via polling, it is required to return sdkKey. 43 | * @return String 44 | */ 45 | @Nullable 46 | String getSDKKey(); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/Rollout.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | import com.fasterxml.jackson.annotation.JsonCreator; 20 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 21 | import com.fasterxml.jackson.annotation.JsonProperty; 22 | 23 | import javax.annotation.concurrent.Immutable; 24 | import java.util.List; 25 | 26 | /** 27 | * Represents a Optimizely Rollout configuration 28 | * 29 | * @see <a href="http://developers.optimizely.com/server/reference/index.html#json">Project JSON</a> 30 | */ 31 | @Immutable 32 | @JsonIgnoreProperties(ignoreUnknown = true) 33 | public class Rollout implements IdMapped { 34 | 35 | private final String id; 36 | private final List<Experiment> experiments; 37 | 38 | @JsonCreator 39 | public Rollout(@JsonProperty("id") String id, 40 | @JsonProperty("experiments") List<Experiment> experiments) { 41 | this.id = id; 42 | this.experiments = experiments; 43 | } 44 | 45 | @Override 46 | public String getId() { 47 | return id; 48 | } 49 | 50 | public List<Experiment> getExperiments() { 51 | return experiments; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "Rollout{" + 57 | "id='" + id + '\'' + 58 | ", experiments=" + experiments + 59 | '}'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/TrafficAllocation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | import com.fasterxml.jackson.annotation.JsonCreator; 20 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 21 | import com.fasterxml.jackson.annotation.JsonProperty; 22 | 23 | /** 24 | * Represents the Optimizely Traffic Allocation configuration. 25 | * 26 | * @see <a href="http://developers.optimizely.com/server/reference/index.html#json">Project JSON</a> 27 | */ 28 | @JsonIgnoreProperties(ignoreUnknown = true) 29 | public class TrafficAllocation { 30 | 31 | private final String entityId; 32 | private final int endOfRange; 33 | 34 | @JsonCreator 35 | public TrafficAllocation(@JsonProperty("entityId") String entityId, 36 | @JsonProperty("endOfRange") int endOfRange) { 37 | this.entityId = entityId; 38 | this.endOfRange = endOfRange; 39 | } 40 | 41 | public String getEntityId() { 42 | return entityId; 43 | } 44 | 45 | public int getEndOfRange() { 46 | return endOfRange; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "TrafficAllocation{" + 52 | "entityId='" + entityId + '\'' + 53 | ", endOfRange=" + endOfRange + 54 | '}'; 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/AttributeType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience; 18 | 19 | public enum AttributeType { 20 | CUSTOM_ATTRIBUTE("custom_attribute"), 21 | THIRD_PARTY_DIMENSION("third_party_dimension"); 22 | 23 | private final String key; 24 | 25 | AttributeType(String key) { 26 | this.key = key; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return key; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/Condition.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2018, 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience; 18 | 19 | import com.optimizely.ab.OptimizelyUserContext; 20 | import com.optimizely.ab.config.ProjectConfig; 21 | 22 | import javax.annotation.Nullable; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | /** 27 | * Interface implemented by all conditions condition objects to aid in condition evaluation. 28 | */ 29 | public interface Condition<T> { 30 | 31 | @Nullable 32 | Boolean evaluate(ProjectConfig config, OptimizelyUserContext user); 33 | 34 | String toJson(); 35 | 36 | String getOperandOrId(); 37 | 38 | List<Condition> getConditions(); 39 | } 40 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/EmptyCondition.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019, 2022, Optimizely Inc. and contributors 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 | * http://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.config.audience; 17 | 18 | import com.optimizely.ab.OptimizelyUserContext; 19 | import com.optimizely.ab.config.ProjectConfig; 20 | 21 | import javax.annotation.Nullable; 22 | import java.util.Map; 23 | 24 | public class EmptyCondition<T> extends LeafCondition<T> { 25 | @Nullable 26 | @Override 27 | public Boolean evaluate(ProjectConfig config, OptimizelyUserContext user) { 28 | return true; 29 | } 30 | 31 | @Override 32 | public String toJson() { return null; } 33 | 34 | @Override 35 | public String getOperandOrId() { 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/LeafCondition.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.config.audience; 17 | 18 | import java.util.List; 19 | 20 | public abstract class LeafCondition<T> implements Condition<T> { 21 | 22 | @Override 23 | public List<Condition> getConditions() { 24 | return null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/NullCondition.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019, 2022, Optimizely Inc. and contributors 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 | * http://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.config.audience; 17 | 18 | import com.optimizely.ab.OptimizelyUserContext; 19 | import com.optimizely.ab.config.ProjectConfig; 20 | 21 | import javax.annotation.Nullable; 22 | import java.util.Map; 23 | 24 | public class NullCondition<T> extends LeafCondition<T> { 25 | @Nullable 26 | @Override 27 | public Boolean evaluate(ProjectConfig config, OptimizelyUserContext user) { 28 | return null; 29 | } 30 | 31 | @Override 32 | public String toJson() { return null; } 33 | 34 | @Override 35 | public String getOperandOrId() { 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/TypedAudience.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience; 18 | 19 | import com.fasterxml.jackson.annotation.JsonCreator; 20 | import com.fasterxml.jackson.annotation.JsonProperty; 21 | 22 | public class TypedAudience extends Audience { 23 | @JsonCreator 24 | public TypedAudience(@JsonProperty("id") String id, 25 | @JsonProperty("name") String name, 26 | @JsonProperty("conditions") Condition conditions) { 27 | super(id, name, conditions); 28 | } 29 | } -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/DefaultMatchForLegacyAttributes.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * This is a temporary class. It mimics the current behaviour for 23 | * legacy custom attributes. This will be dropped for ExactMatch and the unit tests need to be fixed. 24 | */ 25 | class DefaultMatchForLegacyAttributes implements Match { 26 | @Nullable 27 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnexpectedValueTypeException { 28 | if (!(conditionValue instanceof String)) { 29 | throw new UnexpectedValueTypeException(); 30 | } 31 | if (attributeValue == null) { 32 | return false; 33 | } 34 | return conditionValue.toString().equals(attributeValue.toString()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/ExactMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2020, 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | import static com.optimizely.ab.internal.AttributesUtil.isValidNumber; 22 | 23 | /** 24 | * ExactMatch supports matching Numbers, Strings and Booleans. Numbers are first converted to doubles 25 | * before the comparison is evaluated. See {@link NumberComparator} Strings and Booleans are evaulated 26 | * via the Object equals method. 27 | */ 28 | class ExactMatch implements Match { 29 | @Nullable 30 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnexpectedValueTypeException { 31 | if (attributeValue == null) return null; 32 | 33 | if (isValidNumber(attributeValue)) { 34 | if (isValidNumber(conditionValue)) { 35 | return NumberComparator.compareUnsafe(attributeValue, conditionValue) == 0; 36 | } 37 | return null; 38 | } 39 | 40 | if (!(conditionValue instanceof String || conditionValue instanceof Boolean)) { 41 | throw new UnexpectedValueTypeException(); 42 | } 43 | 44 | if (attributeValue.getClass() != conditionValue.getClass()) { 45 | return null; 46 | } 47 | 48 | return conditionValue.equals(attributeValue); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/ExistsMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * ExistsMatch checks that the attribute value is NOT null. 23 | */ 24 | class ExistsMatch implements Match { 25 | @Nullable 26 | public Boolean eval(Object conditionValue, Object attributeValue) { 27 | return attributeValue != null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/GEMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * GEMatch performs a "greater than or equal to" number comparison via {@link NumberComparator}. 23 | */ 24 | class GEMatch implements Match { 25 | @Nullable 26 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnknownValueTypeException { 27 | return NumberComparator.compare(attributeValue, conditionValue) >= 0; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/GTMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * GTMatch performs a "greater than" number comparison via {@link NumberComparator}. 23 | */ 24 | class GTMatch implements Match { 25 | @Nullable 26 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnknownValueTypeException { 27 | return NumberComparator.compare(attributeValue, conditionValue) > 0; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/LEMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * GEMatch performs a "less than or equal to" number comparison via {@link NumberComparator}. 23 | */ 24 | class LEMatch implements Match { 25 | @Nullable 26 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnknownValueTypeException { 27 | return NumberComparator.compare(attributeValue, conditionValue) <= 0; 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/LTMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * GTMatch performs a "less than" number comparison via {@link NumberComparator}. 23 | */ 24 | class LTMatch implements Match { 25 | @Nullable 26 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnknownValueTypeException { 27 | return NumberComparator.compare(attributeValue, conditionValue) < 0; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/Match.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | public interface Match { 22 | @Nullable 23 | Boolean eval(Object conditionValue, Object attributeValue) throws UnexpectedValueTypeException, UnknownValueTypeException; 24 | } 25 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/NumberComparator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import static com.optimizely.ab.internal.AttributesUtil.isValidNumber; 20 | 21 | /** 22 | * NumberComparator performs a numeric comparison. The input values are assumed to be numbers else 23 | * compare will throw an {@link UnknownValueTypeException}. 24 | */ 25 | public class NumberComparator { 26 | public static int compare(Object o1, Object o2) throws UnknownValueTypeException { 27 | if (!isValidNumber(o1) || !isValidNumber(o2)) { 28 | throw new UnknownValueTypeException(); 29 | } 30 | 31 | return compareUnsafe(o1, o2); 32 | } 33 | 34 | /** 35 | * compareUnsafe is provided to avoid checking the input values are numbers. It's assumed that the inputs 36 | * are known to be Numbers. 37 | */ 38 | static int compareUnsafe(Object o1, Object o2) { 39 | return Double.compare(((Number) o1).doubleValue(), ((Number) o2).doubleValue()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/SemanticVersionEqualsMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * SemanticVersionEqualsMatch performs a equality comparison via {@link SemanticVersion#compare(Object, Object)}. 23 | */ 24 | class SemanticVersionEqualsMatch implements Match { 25 | @Nullable 26 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnexpectedValueTypeException { 27 | if (attributeValue == null) return null; // stay silent (no WARNING) when attribute value is missing or empty. 28 | return SemanticVersion.compare(attributeValue, conditionValue) == 0; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/SemanticVersionGEMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * SemanticVersionGEMatch performs a "greater than or equal to" comparison 23 | * via {@link SemanticVersion#compare(Object, Object)}. 24 | */ 25 | class SemanticVersionGEMatch implements Match { 26 | @Nullable 27 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnexpectedValueTypeException { 28 | if (attributeValue == null) return null; // stay silent (no WARNING) when attribute value is missing or empty. 29 | return SemanticVersion.compare(attributeValue, conditionValue) >= 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/SemanticVersionGTMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * SemanticVersionGTMatch performs a "greater than" comparison via {@link SemanticVersion#compare(Object, Object)}. 23 | */ 24 | class SemanticVersionGTMatch implements Match { 25 | @Nullable 26 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnexpectedValueTypeException { 27 | if (attributeValue == null) return null; // stay silent (no WARNING) when attribute value is missing or empty. 28 | return SemanticVersion.compare(attributeValue, conditionValue) > 0; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/SemanticVersionLEMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * SemanticVersionLEMatch performs a "less than or equal to" comparison 23 | * via {@link SemanticVersion#compare(Object, Object)}. 24 | */ 25 | class SemanticVersionLEMatch implements Match { 26 | @Nullable 27 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnexpectedValueTypeException { 28 | if (attributeValue == null) return null; // stay silent (no WARNING) when attribute value is missing or empty. 29 | return SemanticVersion.compare(attributeValue, conditionValue) <= 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/SemanticVersionLTMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * SemanticVersionLTMatch performs a "less than" comparison via {@link SemanticVersion#compare(Object, Object)}. 23 | */ 24 | class SemanticVersionLTMatch implements Match { 25 | @Nullable 26 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnexpectedValueTypeException { 27 | if (attributeValue == null) return null; // stay silent (no WARNING) when attribute value is missing or empty. 28 | return SemanticVersion.compare(attributeValue, conditionValue) < 0; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/SubstringMatch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import javax.annotation.Nullable; 20 | 21 | /** 22 | * SubstringMatch checks if the attribute value contains the condition value. 23 | * This assumes both the condition and attribute values are provided as Strings. 24 | */ 25 | class SubstringMatch implements Match { 26 | @Nullable 27 | public Boolean eval(Object conditionValue, Object attributeValue) throws UnexpectedValueTypeException { 28 | if (!(conditionValue instanceof String)) { 29 | throw new UnexpectedValueTypeException(); 30 | } 31 | 32 | if (!(attributeValue instanceof String)) { 33 | return null; 34 | } 35 | 36 | try { 37 | return attributeValue.toString().contains(conditionValue.toString()); 38 | } catch (Exception e) { 39 | return null; 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/UnexpectedValueTypeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019-2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.optimizely.ab.config.audience.match; 19 | 20 | /** 21 | * UnexpectedValueTypeException is thrown when the condition value found in the datafile is 22 | * not one of an expected type for this version of the SDK. 23 | */ 24 | public class UnexpectedValueTypeException extends Exception { 25 | private static String message = "has an unsupported condition value. You may need to upgrade to a newer release of the Optimizely SDK."; 26 | 27 | public UnexpectedValueTypeException() { 28 | super(message); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/UnknownMatchTypeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019-2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.optimizely.ab.config.audience.match; 19 | 20 | /** 21 | * UnknownMatchTypeException is thrown when the specified match type cannot be mapped via the MatchRegistry. 22 | */ 23 | public class UnknownMatchTypeException extends Exception { 24 | private static String message = "uses an unknown match type. You may need to upgrade to a newer release of the Optimizely SDK."; 25 | 26 | public UnknownMatchTypeException() { 27 | super(message); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/audience/match/UnknownValueTypeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.optimizely.ab.config.audience.match; 19 | 20 | /** 21 | * UnknownValueTypeException is thrown when the passed in value for a user attribute does 22 | * not map to a known allowable type. 23 | */ 24 | public class UnknownValueTypeException extends Exception { 25 | private static String message = "has an unsupported attribute value."; 26 | 27 | public UnknownValueTypeException() { 28 | super(message); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/AudienceJacksonDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | import com.fasterxml.jackson.core.JsonParser; 20 | import com.fasterxml.jackson.core.ObjectCodec; 21 | import com.fasterxml.jackson.databind.DeserializationContext; 22 | import com.fasterxml.jackson.databind.JsonDeserializer; 23 | import com.fasterxml.jackson.databind.JsonNode; 24 | import com.fasterxml.jackson.databind.ObjectMapper; 25 | import com.optimizely.ab.config.audience.*; 26 | 27 | import java.io.IOException; 28 | 29 | public class AudienceJacksonDeserializer extends JsonDeserializer<Audience> { 30 | private ObjectMapper objectMapper; 31 | 32 | public AudienceJacksonDeserializer() { 33 | this(new ObjectMapper()); 34 | } 35 | 36 | AudienceJacksonDeserializer(ObjectMapper objectMapper) { 37 | this.objectMapper = objectMapper; 38 | } 39 | 40 | @Override 41 | public Audience deserialize(JsonParser parser, DeserializationContext context) throws IOException { 42 | ObjectCodec codec = parser.getCodec(); 43 | JsonNode node = codec.readTree(parser); 44 | 45 | String id = node.get("id").textValue(); 46 | String name = node.get("name").textValue(); 47 | 48 | JsonNode conditionsJson = node.get("conditions"); 49 | conditionsJson = objectMapper.readTree(conditionsJson.textValue()); 50 | 51 | Condition conditions = ConditionJacksonDeserializer.<UserAttribute>parseCondition(UserAttribute.class, objectMapper, conditionsJson); 52 | 53 | return new Audience(id, name, conditions); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/ConfigParseException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | /** 20 | * Wrapper around all types of JSON parser exceptions. 21 | */ 22 | public final class ConfigParseException extends Exception { 23 | public ConfigParseException(String message) { 24 | super(message); 25 | } 26 | 27 | public ConfigParseException(String message, Throwable cause) { 28 | super(message, cause); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/ConfigParser.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017,2021, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | import com.optimizely.ab.config.ProjectConfig; 20 | 21 | import javax.annotation.Nonnull; 22 | 23 | /** 24 | * Config parser wrapper to allow multiple library implementations to be used. 25 | * 26 | * @see GsonConfigParser 27 | * @see JacksonConfigParser 28 | * @see JsonConfigParser 29 | * @see JsonConfigParser 30 | * 31 | * @see <a href="http://developers.optimizely.com/server/reference/index.html#json">Project JSON</a> 32 | */ 33 | public interface ConfigParser { 34 | 35 | /** 36 | * @param json The json to parse 37 | * @return The {@code ProjectConfig} configuration from the provided json 38 | * @throws ConfigParseException when there's an issue parsing the provided project config 39 | */ 40 | ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParseException; 41 | 42 | /** 43 | * OptimizelyJSON parsing 44 | * 45 | * @param src The OptimizelyJSON 46 | * @return The serialized String 47 | * @throws JsonParseException when parsing JSON fails 48 | */ 49 | String toJson(Object src) throws JsonParseException; 50 | <T> T fromJson(String json, Class<T> clazz) throws JsonParseException; 51 | } 52 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/ExperimentGsonDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | import com.google.gson.JsonDeserializationContext; 20 | import com.google.gson.JsonDeserializer; 21 | import com.google.gson.JsonElement; 22 | import com.google.gson.JsonObject; 23 | import com.google.gson.JsonParseException; 24 | 25 | import com.optimizely.ab.config.Experiment; 26 | 27 | import java.lang.reflect.Type; 28 | 29 | final class ExperimentGsonDeserializer implements JsonDeserializer<Experiment> { 30 | 31 | @Override 32 | public Experiment deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 33 | throws JsonParseException { 34 | 35 | JsonObject jsonObject = json.getAsJsonObject(); 36 | 37 | return GsonHelpers.parseExperiment(jsonObject, context); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/FeatureFlagGsonDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | import com.google.gson.JsonDeserializationContext; 20 | import com.google.gson.JsonDeserializer; 21 | import com.google.gson.JsonElement; 22 | import com.google.gson.JsonObject; 23 | import com.google.gson.JsonParseException; 24 | import com.optimizely.ab.config.FeatureFlag; 25 | 26 | import java.lang.reflect.Type; 27 | 28 | public class FeatureFlagGsonDeserializer implements JsonDeserializer<FeatureFlag> { 29 | @Override 30 | public FeatureFlag deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 31 | throws JsonParseException { 32 | 33 | JsonObject jsonObject = json.getAsJsonObject(); 34 | return GsonHelpers.parseFeatureFlag(jsonObject, context); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/GroupGsonDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | import com.google.gson.JsonArray; 20 | import com.google.gson.JsonDeserializationContext; 21 | import com.google.gson.JsonDeserializer; 22 | import com.google.gson.JsonElement; 23 | import com.google.gson.JsonObject; 24 | import com.google.gson.JsonParseException; 25 | 26 | import com.optimizely.ab.config.Experiment; 27 | import com.optimizely.ab.config.Group; 28 | import com.optimizely.ab.config.TrafficAllocation; 29 | 30 | import java.lang.reflect.Type; 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | 34 | public class GroupGsonDeserializer implements JsonDeserializer<Group> { 35 | 36 | @Override 37 | public Group deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 38 | throws JsonParseException { 39 | 40 | JsonObject jsonObject = json.getAsJsonObject(); 41 | 42 | String id = jsonObject.get("id").getAsString(); 43 | String policy = jsonObject.get("policy").getAsString(); 44 | 45 | List<Experiment> experiments = new ArrayList<Experiment>(); 46 | JsonArray experimentsJson = jsonObject.getAsJsonArray("experiments"); 47 | for (Object obj : experimentsJson) { 48 | JsonObject experimentObj = (JsonObject) obj; 49 | experiments.add(GsonHelpers.parseExperiment(experimentObj, id, context)); 50 | } 51 | 52 | List<TrafficAllocation> trafficAllocations = 53 | GsonHelpers.parseTrafficAllocation(jsonObject.getAsJsonArray("trafficAllocation")); 54 | 55 | return new Group(id, policy, experiments, trafficAllocations); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/JacksonHelpers.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | import com.fasterxml.jackson.core.ObjectCodec; 20 | import com.fasterxml.jackson.databind.JsonNode; 21 | 22 | import java.io.IOException; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | final class JacksonHelpers { 27 | private JacksonHelpers() { 28 | } 29 | 30 | static <T> List<T> arrayNodeToList(JsonNode arrayNode, Class<T> itemClass, ObjectCodec codec) throws IOException { 31 | if (arrayNode == null || arrayNode.isNull() || !arrayNode.isArray()) { 32 | return null; 33 | } 34 | 35 | List<T> items = new ArrayList<>(arrayNode.size()); 36 | 37 | for (int i = 0; i < arrayNode.size(); i++) { 38 | JsonNode itemNode = arrayNode.get(i); 39 | if (itemNode.isNull()) { 40 | continue; 41 | } 42 | items.add(codec.treeToValue(itemNode, itemClass)); 43 | } 44 | 45 | return items; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/JsonParseException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | public final class JsonParseException extends Exception { 20 | public JsonParseException(String message) { 21 | super(message); 22 | } 23 | 24 | public JsonParseException(String message, Throwable cause) { 25 | super(message, cause); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/MissingJsonParserException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.parser; 18 | 19 | import com.optimizely.ab.OptimizelyRuntimeException; 20 | 21 | /** 22 | * Exception thrown when no supported JSON parser is found. 23 | */ 24 | public final class MissingJsonParserException extends OptimizelyRuntimeException { 25 | public MissingJsonParserException(String message) { 26 | super(message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/config/parser/TypedAudienceJacksonDeserializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019, Optimizely Inc. and contributors 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 | * http://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.config.parser; 17 | 18 | import com.fasterxml.jackson.core.JsonParser; 19 | import com.fasterxml.jackson.core.ObjectCodec; 20 | import com.fasterxml.jackson.databind.DeserializationContext; 21 | import com.fasterxml.jackson.databind.JsonDeserializer; 22 | import com.fasterxml.jackson.databind.JsonNode; 23 | import com.fasterxml.jackson.databind.ObjectMapper; 24 | import com.optimizely.ab.config.audience.Condition; 25 | import com.optimizely.ab.config.audience.TypedAudience; 26 | import com.optimizely.ab.config.audience.UserAttribute; 27 | 28 | import java.io.IOException; 29 | 30 | public class TypedAudienceJacksonDeserializer extends JsonDeserializer<TypedAudience> { 31 | private ObjectMapper objectMapper; 32 | 33 | public TypedAudienceJacksonDeserializer() { 34 | this(new ObjectMapper()); 35 | } 36 | 37 | TypedAudienceJacksonDeserializer(ObjectMapper objectMapper) { 38 | this.objectMapper = objectMapper; 39 | } 40 | 41 | @Override 42 | public TypedAudience deserialize(JsonParser parser, DeserializationContext context) throws IOException { 43 | ObjectCodec codec = parser.getCodec(); 44 | JsonNode node = codec.readTree(parser); 45 | 46 | String id = node.get("id").textValue(); 47 | String name = node.get("name").textValue(); 48 | 49 | JsonNode conditionsJson = node.get("conditions"); 50 | 51 | Condition conditions = ConditionJacksonDeserializer.<UserAttribute>parseCondition(UserAttribute.class, objectMapper, conditionsJson); 52 | 53 | return new TypedAudience(id, name, conditions); 54 | } 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/error/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.error; 18 | 19 | import com.optimizely.ab.OptimizelyRuntimeException; 20 | 21 | /** 22 | * Implementations are responsible for handling errors. 23 | */ 24 | public interface ErrorHandler { 25 | 26 | <T extends OptimizelyRuntimeException> void handleError(T exception) throws T; 27 | } 28 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/error/NoOpErrorHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.error; 18 | 19 | import com.optimizely.ab.OptimizelyRuntimeException; 20 | 21 | /** 22 | * {@link ErrorHandler} that handles an error silently 23 | */ 24 | public class NoOpErrorHandler implements ErrorHandler { 25 | 26 | @Override 27 | public <T extends OptimizelyRuntimeException> void handleError(T exception) { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/error/RaiseExceptionErrorHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.error; 18 | 19 | import com.optimizely.ab.OptimizelyRuntimeException; 20 | 21 | /** 22 | * {@link ErrorHandler} that handles an error by raising an exception 23 | */ 24 | public class RaiseExceptionErrorHandler implements ErrorHandler { 25 | 26 | @Override 27 | public <T extends OptimizelyRuntimeException> void handleError(T exception) { 28 | throw exception; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/EventHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event; 18 | 19 | /** 20 | * Implementations are responsible for dispatching event's to the Optimizely event end-point. 21 | */ 22 | public interface EventHandler { 23 | void dispatchEvent(LogEvent logEvent) throws Exception; 24 | } 25 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/EventProcessor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event; 18 | 19 | import com.optimizely.ab.event.internal.UserEvent; 20 | import com.optimizely.ab.event.internal.payload.EventBatch; 21 | import com.optimizely.ab.notification.NotificationHandler; 22 | 23 | /** 24 | * EventProcessor interface is used to provide an intermediary processing stage within 25 | * event production. It's assumed that the EventProcessor dispatches events via a provided 26 | * {@link EventHandler}. 27 | */ 28 | public interface EventProcessor { 29 | void process(UserEvent userEvent); 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/ForwardingEventProcessor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event; 18 | 19 | import com.optimizely.ab.event.internal.EventFactory; 20 | import com.optimizely.ab.event.internal.UserEvent; 21 | import com.optimizely.ab.notification.NotificationCenter; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * ForwardingEventProcessor is a basic transformation stage for converting 27 | * the event batch into a LogEvent to be dispatched. 28 | */ 29 | public class ForwardingEventProcessor implements EventProcessor { 30 | 31 | private static final Logger logger = LoggerFactory.getLogger(ForwardingEventProcessor.class); 32 | 33 | private final EventHandler eventHandler; 34 | private final NotificationCenter notificationCenter; 35 | 36 | public ForwardingEventProcessor(EventHandler eventHandler, NotificationCenter notificationCenter) { 37 | this.eventHandler = eventHandler; 38 | this.notificationCenter = notificationCenter; 39 | } 40 | 41 | @Override 42 | public void process(UserEvent userEvent) { 43 | LogEvent logEvent = EventFactory.createLogEvent(userEvent); 44 | 45 | if (notificationCenter != null) { 46 | notificationCenter.send(logEvent); 47 | } 48 | 49 | try { 50 | eventHandler.dispatchEvent(logEvent); 51 | } catch(Exception e) { 52 | logger.error("Error dispatching event: {}", logEvent, e); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/NoopEventHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | import java.util.Map; 23 | 24 | /** 25 | * {@link EventHandler} that logs events but <b>does not</b> perform any dispatching. 26 | */ 27 | public class NoopEventHandler implements EventHandler { 28 | 29 | private static final Logger logger = LoggerFactory.getLogger(NoopEventHandler.class); 30 | 31 | @Override 32 | public void dispatchEvent(LogEvent logEvent) { 33 | logger.debug("Called dispatchEvent with URL: {} and params: {}", logEvent.getEndpointUrl(), 34 | logEvent.getRequestParams()); 35 | } 36 | } -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/internal/BaseEvent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event.internal; 18 | 19 | import java.util.UUID; 20 | 21 | /** 22 | * BaseEvent provides a GUID implementation along with a system timestamp. 23 | */ 24 | public class BaseEvent { 25 | 26 | private final String uuid = UUID.randomUUID().toString(); 27 | private final long timestamp = System.currentTimeMillis(); 28 | 29 | public final String getUUID() { 30 | return uuid; 31 | } 32 | 33 | public final long getTimestamp() { 34 | return timestamp; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/internal/UserEvent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event.internal; 18 | 19 | /** 20 | * UserEvent interface is used to identify events containing a {@link UserContext} 21 | * Examples include: 22 | * <ul> 23 | * <li>{@link ConversionEvent}</li> 24 | * <li>{@link ImpressionEvent}</li> 25 | * </ul> 26 | */ 27 | public interface UserEvent { 28 | UserContext getUserContext(); 29 | String getUUID(); 30 | long getTimestamp(); 31 | } 32 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/internal/serializer/GsonSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event.internal.serializer; 18 | 19 | import com.google.gson.FieldNamingPolicy; 20 | import com.google.gson.Gson; 21 | import com.google.gson.GsonBuilder; 22 | 23 | class GsonSerializer implements Serializer { 24 | 25 | private Gson gson = new GsonBuilder() 26 | .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) 27 | .create(); 28 | 29 | public <T> String serialize(T payload) { 30 | return gson.toJson(payload); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/internal/serializer/JacksonSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event.internal.serializer; 18 | 19 | import com.fasterxml.jackson.annotation.JsonInclude; 20 | import com.fasterxml.jackson.core.JsonProcessingException; 21 | import com.fasterxml.jackson.databind.ObjectMapper; 22 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; 23 | 24 | class JacksonSerializer implements Serializer { 25 | 26 | private ObjectMapper mapper = 27 | new ObjectMapper().setPropertyNamingStrategy( 28 | PropertyNamingStrategy.SNAKE_CASE); 29 | 30 | public <T> String serialize(T payload) { 31 | mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 32 | try { 33 | return mapper.writeValueAsString(payload); 34 | } catch (JsonProcessingException e) { 35 | throw new SerializationException("Unable to serialize payload", e); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/internal/serializer/JsonSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event.internal.serializer; 18 | 19 | import org.json.JSONObject; 20 | 21 | class JsonSerializer implements Serializer { 22 | 23 | public <T> String serialize(T payload) { 24 | JSONObject payloadJsonObject = new JSONObject(payload); 25 | String jsonResponse = payloadJsonObject.toString(); 26 | StringBuilder stringBuilder = new StringBuilder(); 27 | 28 | for (int i = 0; i < jsonResponse.length(); i++) { 29 | Character ch = jsonResponse.charAt(i); 30 | Character nextChar = null; 31 | if (i + 1 < jsonResponse.length()) { 32 | nextChar = jsonResponse.charAt(i + 1); 33 | } 34 | if ((Character.isLetter(ch) || Character.isDigit(ch)) && Character.isUpperCase(ch) && 35 | ((Character.isLetter(nextChar) || Character.isDigit(nextChar)))) { 36 | stringBuilder.append('_'); 37 | stringBuilder.append(Character.toLowerCase(ch)); 38 | } else { 39 | stringBuilder.append(ch); 40 | } 41 | } 42 | 43 | return stringBuilder.toString(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/internal/serializer/SerializationException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event.internal.serializer; 18 | 19 | import com.optimizely.ab.OptimizelyRuntimeException; 20 | 21 | /** 22 | * Wrapper around all types of JSON serialization exceptions. 23 | */ 24 | public class SerializationException extends OptimizelyRuntimeException { 25 | 26 | public SerializationException(String message, Throwable cause) { 27 | super(message, cause); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/event/internal/serializer/Serializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event.internal.serializer; 18 | 19 | public interface Serializer { 20 | <T> String serialize(T payload) throws SerializationException; 21 | } 22 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/internal/Cache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2022, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.internal; 18 | 19 | public interface Cache<T> { 20 | int DEFAULT_MAX_SIZE = 10000; 21 | int DEFAULT_TIMEOUT_SECONDS = 600; 22 | void save(String key, T value); 23 | T lookup(String key); 24 | void reset(); 25 | } 26 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/internal/ControlAttribute.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.internal; 18 | 19 | public enum ControlAttribute { 20 | BOT_FILTERING_ATTRIBUTE("$opt_bot_filtering"), 21 | USER_AGENT_ATTRIBUTE("$opt_user_agent"), 22 | BUCKETING_ATTRIBUTE("$opt_bucketing_id"); 23 | 24 | private final String key; 25 | 26 | ControlAttribute(String key) { 27 | this.key = key; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return key; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/internal/InvalidAudienceCondition.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.internal; 18 | 19 | import com.optimizely.ab.OptimizelyRuntimeException; 20 | 21 | public class InvalidAudienceCondition extends OptimizelyRuntimeException { 22 | 23 | public InvalidAudienceCondition(String message) { 24 | super(message); 25 | } 26 | 27 | public InvalidAudienceCondition(String message, Throwable cause) { 28 | super(message, cause); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/internal/LoggingConstants.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.internal; 18 | 19 | public class LoggingConstants { 20 | public static class LoggingEntityType { 21 | public static final String EXPERIMENT = "experiment"; 22 | public static final String RULE = "rule"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/internal/NotificationRegistry.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2023, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.internal; 18 | 19 | import com.optimizely.ab.notification.NotificationCenter; 20 | 21 | import javax.annotation.Nonnull; 22 | import java.util.Map; 23 | import java.util.concurrent.ConcurrentHashMap; 24 | 25 | public class NotificationRegistry { 26 | private final static Map<String, NotificationCenter> _notificationCenters = new ConcurrentHashMap<>(); 27 | 28 | private NotificationRegistry() 29 | { 30 | } 31 | 32 | public static NotificationCenter getInternalNotificationCenter(@Nonnull String sdkKey) 33 | { 34 | NotificationCenter notificationCenter = null; 35 | if (sdkKey != null) { 36 | if (_notificationCenters.containsKey(sdkKey)) { 37 | notificationCenter = _notificationCenters.get(sdkKey); 38 | } else { 39 | notificationCenter = new NotificationCenter(); 40 | _notificationCenters.put(sdkKey, notificationCenter); 41 | } 42 | } 43 | return notificationCenter; 44 | } 45 | 46 | public static void clearNotificationCenterRegistry(@Nonnull String sdkKey) { 47 | if (sdkKey != null) { 48 | _notificationCenters.remove(sdkKey); 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/internal/ReservedEventKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.internal; 18 | 19 | public enum ReservedEventKey { 20 | REVENUE("revenue"), 21 | VALUE("value"); 22 | 23 | private final String key; 24 | 25 | ReservedEventKey(String key) { 26 | this.key = key; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return key; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/internal/SafetyUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019,2021, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.internal; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | /** 23 | * Collection of utils used to prevent the Optimizely SDK from throwing or crashing the hosting application. 24 | */ 25 | public class SafetyUtils { 26 | 27 | private static final Logger logger = LoggerFactory.getLogger(SafetyUtils.class); 28 | 29 | /** 30 | * Helper method which checks if Object is an instance of AutoCloseable and calls close() on it. 31 | * 32 | * @param obj The object 33 | */ 34 | public static void tryClose(Object obj) { 35 | if (!(obj instanceof AutoCloseable)) { 36 | return; 37 | } 38 | 39 | try { 40 | ((AutoCloseable) obj).close(); 41 | } catch (Exception e) { 42 | logger.warn("Unexpected exception on trying to close {}.", obj); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/notification/ActivateNotificationListenerInterface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.notification; 18 | 19 | import com.optimizely.ab.config.Experiment; 20 | import com.optimizely.ab.config.Variation; 21 | import com.optimizely.ab.event.LogEvent; 22 | 23 | import javax.annotation.Nonnull; 24 | import java.util.Map; 25 | 26 | /** 27 | * ActivateNotificationListenerInterface provides and interface for activate event notification. 28 | * 29 | * @deprecated along with {@link ActivateNotification} and {@link ActivateNotificationListener} 30 | * and users should implement NotificationHandler<DecisionNotification> directly. 31 | */ 32 | @Deprecated 33 | public interface ActivateNotificationListenerInterface { 34 | /** 35 | * onActivate called when an activate was triggered 36 | * 37 | * @param experiment - The experiment object being activated. 38 | * @param userId - The userId passed into activate. 39 | * @param attributes - The filtered attribute list passed into activate 40 | * @param variation - The variation that was returned from activate. 41 | * @param event - The impression event that was triggered. 42 | */ 43 | public void onActivate(@Nonnull Experiment experiment, 44 | @Nonnull String userId, 45 | @Nonnull Map<String, ?> attributes, 46 | @Nonnull Variation variation, 47 | @Nonnull LogEvent event); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/notification/FeatureTestSourceInfo.java: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2019, Optimizely, Inc. and contributors * 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 | * http://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 | 17 | package com.optimizely.ab.notification; 18 | 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | import static com.optimizely.ab.notification.DecisionNotification.ExperimentDecisionNotificationBuilder.EXPERIMENT_KEY; 23 | import static com.optimizely.ab.notification.DecisionNotification.ExperimentDecisionNotificationBuilder.VARIATION_KEY; 24 | 25 | public class FeatureTestSourceInfo implements SourceInfo { 26 | private String experimentKey; 27 | private String variationKey; 28 | 29 | public FeatureTestSourceInfo(String experimentKey, String variationKey) { 30 | this.experimentKey = experimentKey; 31 | this.variationKey = variationKey; 32 | } 33 | 34 | @Override 35 | public Map<String, String> get() { 36 | Map<String, String> sourceInfo = new HashMap<>(); 37 | sourceInfo.put(EXPERIMENT_KEY, experimentKey); 38 | sourceInfo.put(VARIATION_KEY, variationKey); 39 | 40 | return sourceInfo; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/notification/NotificationHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.notification; 18 | 19 | /** 20 | * NotificationHandler is a generic interface Optimizely notification listeners. 21 | * This interface replaces {@link NotificationListener} which didn't provide adequate type safety. 22 | * 23 | * While this class adds generic handler implementations to be created, the domain of supported 24 | * implementations is maintained by the {@link NotificationCenter} 25 | */ 26 | public interface NotificationHandler<T> { 27 | void handle(T message) throws Exception; 28 | } 29 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/notification/NotificationListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.notification; 18 | 19 | /** 20 | * An interface class for Optimizely notification listeners. 21 | * <p> 22 | * We changed this from a abstract class to a interface to support lambdas moving forward in Java 8 and beyond. 23 | * 24 | * @deprecated in favor of the {@link NotificationHandler} interface. 25 | */ 26 | @Deprecated 27 | public interface NotificationListener { 28 | 29 | /** 30 | * This is the base method of notification. Implementation classes such as {@link ActivateNotificationListener} 31 | * will implement this call and provide another method with the correct parameters 32 | * Notify called when a notification is triggered via the {@link com.optimizely.ab.notification.NotificationCenter} 33 | * 34 | * @param args - variable argument list based on the type of notification. 35 | */ 36 | public void notify(Object... args); 37 | } 38 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/notification/RolloutSourceInfo.java: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2019, Optimizely, Inc. and contributors * 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 | * http://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 | 17 | package com.optimizely.ab.notification; 18 | 19 | import java.util.Collections; 20 | import java.util.Map; 21 | 22 | public class RolloutSourceInfo implements SourceInfo { 23 | @Override 24 | public Map<String, String> get() { 25 | return Collections.EMPTY_MAP; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/notification/SourceInfo.java: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2019, Optimizely, Inc. and contributors * 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 | * http://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 | 17 | package com.optimizely.ab.notification; 18 | 19 | import java.util.Map; 20 | 21 | public interface SourceInfo { 22 | Map<String, String> get(); 23 | } 24 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/notification/TrackNotificationListenerInterface.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018-2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.notification; 18 | 19 | import com.optimizely.ab.event.LogEvent; 20 | 21 | import javax.annotation.Nonnull; 22 | import java.util.Map; 23 | 24 | /** 25 | * TrackNotificationListenerInterface provides an interface for track event notification. 26 | * 27 | * @deprecated and users should implement NotificationHandler<TrackNotification> directly. 28 | */ 29 | @Deprecated 30 | public interface TrackNotificationListenerInterface { 31 | /** 32 | * onTrack is called when a track event is triggered 33 | * 34 | * @param eventKey - The event key that was triggered. 35 | * @param userId - user id passed into track. 36 | * @param attributes - filtered attributes list after passed into track 37 | * @param eventTags - event tags if any were passed in. 38 | * @param event - The event being recorded. 39 | */ 40 | public void onTrack(@Nonnull String eventKey, 41 | @Nonnull String userId, 42 | @Nonnull Map<String, ?> attributes, 43 | @Nonnull Map<String, ?> eventTags, 44 | @Nonnull LogEvent event); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/notification/UpdateConfigNotification.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.notification; 18 | 19 | /** 20 | * UpdateConfigNotification signals a change in the current configuration. 21 | */ 22 | public class UpdateConfigNotification { 23 | } 24 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/ODPApiManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022-2023, Optimizely Inc. and contributors 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 | * http://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.odp; 17 | 18 | import java.util.List; 19 | import java.util.Set; 20 | 21 | public interface ODPApiManager { 22 | List<String> fetchQualifiedSegments(String apiKey, String apiEndpoint, String userKey, String userValue, Set<String> segmentsToCheck); 23 | 24 | Integer sendEvents(String apiKey, String apiEndpoint, String eventPayload); 25 | } 26 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/ODPSegmentCallback.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2022, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.odp; 18 | 19 | @FunctionalInterface 20 | public interface ODPSegmentCallback { 21 | void onCompleted(Boolean isFetchSuccessful); 22 | } 23 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/ODPSegmentOption.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2022, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.odp; 18 | 19 | public enum ODPSegmentOption { 20 | 21 | IGNORE_CACHE, 22 | 23 | RESET_CACHE; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/ODPUserKey.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2022-2023, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.odp; 18 | 19 | public enum ODPUserKey { 20 | 21 | VUID("vuid"), 22 | 23 | FS_USER_ID("fs_user_id"), 24 | 25 | FS_USER_ID_ALIAS("fs-user-id"); 26 | 27 | private final String keyString; 28 | 29 | ODPUserKey(String keyString) { 30 | this.keyString = keyString; 31 | } 32 | 33 | public String getKeyString() { 34 | return keyString; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/parser/ResponseJsonParser.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.odp.parser; 17 | 18 | import java.util.List; 19 | 20 | public interface ResponseJsonParser { 21 | public List<String> parseQualifiedSegments(String responseJson); 22 | } 23 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/parser/ResponseJsonParserFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.odp.parser; 17 | 18 | import com.optimizely.ab.internal.JsonParserProvider; 19 | import com.optimizely.ab.odp.parser.impl.GsonParser; 20 | import com.optimizely.ab.odp.parser.impl.JacksonParser; 21 | import com.optimizely.ab.odp.parser.impl.JsonParser; 22 | import com.optimizely.ab.odp.parser.impl.JsonSimpleParser; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | public class ResponseJsonParserFactory { 27 | private static final Logger logger = LoggerFactory.getLogger(ResponseJsonParserFactory.class); 28 | 29 | public static ResponseJsonParser getParser() { 30 | JsonParserProvider parserProvider = JsonParserProvider.getDefaultParser(); 31 | ResponseJsonParser jsonParser = null; 32 | switch (parserProvider) { 33 | case GSON_CONFIG_PARSER: 34 | jsonParser = new GsonParser(); 35 | break; 36 | case JACKSON_CONFIG_PARSER: 37 | jsonParser = new JacksonParser(); 38 | break; 39 | case JSON_CONFIG_PARSER: 40 | jsonParser = new JsonParser(); 41 | break; 42 | case JSON_SIMPLE_CONFIG_PARSER: 43 | jsonParser = new JsonSimpleParser(); 44 | break; 45 | } 46 | logger.debug("Using " + parserProvider.toString() + " parser"); 47 | return jsonParser; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/serializer/ODPJsonSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.odp.serializer; 17 | 18 | import com.optimizely.ab.odp.ODPEvent; 19 | 20 | import java.util.List; 21 | 22 | public interface ODPJsonSerializer { 23 | public String serializeEvents(List<ODPEvent> events); 24 | } 25 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/serializer/ODPJsonSerializerFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.odp.serializer; 17 | 18 | import com.optimizely.ab.internal.JsonParserProvider; 19 | import com.optimizely.ab.odp.serializer.impl.GsonSerializer; 20 | import com.optimizely.ab.odp.serializer.impl.JacksonSerializer; 21 | import com.optimizely.ab.odp.serializer.impl.JsonSerializer; 22 | import com.optimizely.ab.odp.serializer.impl.JsonSimpleSerializer; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | public class ODPJsonSerializerFactory { 27 | private static final Logger logger = LoggerFactory.getLogger(ODPJsonSerializerFactory.class); 28 | 29 | public static ODPJsonSerializer getSerializer() { 30 | JsonParserProvider parserProvider = JsonParserProvider.getDefaultParser(); 31 | ODPJsonSerializer jsonSerializer = null; 32 | switch (parserProvider) { 33 | case GSON_CONFIG_PARSER: 34 | jsonSerializer = new GsonSerializer(); 35 | break; 36 | case JACKSON_CONFIG_PARSER: 37 | jsonSerializer = new JacksonSerializer(); 38 | break; 39 | case JSON_CONFIG_PARSER: 40 | jsonSerializer = new JsonSerializer(); 41 | break; 42 | case JSON_SIMPLE_CONFIG_PARSER: 43 | jsonSerializer = new JsonSimpleSerializer(); 44 | break; 45 | } 46 | logger.info("Using " + parserProvider.toString() + " serializer"); 47 | return jsonSerializer; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/serializer/impl/GsonSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.odp.serializer.impl; 17 | 18 | import com.google.gson.Gson; 19 | import com.google.gson.GsonBuilder; 20 | import com.optimizely.ab.odp.ODPEvent; 21 | import com.optimizely.ab.odp.serializer.ODPJsonSerializer; 22 | 23 | import java.util.List; 24 | 25 | public class GsonSerializer implements ODPJsonSerializer { 26 | @Override 27 | public String serializeEvents(List<ODPEvent> events) { 28 | Gson gson = new GsonBuilder().serializeNulls().create(); 29 | return gson.toJson(events); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/serializer/impl/JacksonSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.odp.serializer.impl; 17 | 18 | import com.fasterxml.jackson.core.JsonProcessingException; 19 | import com.fasterxml.jackson.databind.ObjectMapper; 20 | import com.optimizely.ab.odp.ODPEvent; 21 | import com.optimizely.ab.odp.serializer.ODPJsonSerializer; 22 | 23 | import java.util.List; 24 | 25 | public class JacksonSerializer implements ODPJsonSerializer { 26 | @Override 27 | public String serializeEvents(List<ODPEvent> events) { 28 | ObjectMapper objectMapper = new ObjectMapper(); 29 | try { 30 | return objectMapper.writeValueAsString(events); 31 | } catch (JsonProcessingException e) { 32 | // log error here 33 | } 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/odp/serializer/impl/JsonSimpleSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.odp.serializer.impl; 17 | 18 | import com.optimizely.ab.odp.ODPEvent; 19 | import com.optimizely.ab.odp.serializer.ODPJsonSerializer; 20 | import org.json.simple.JSONArray; 21 | import org.json.simple.JSONObject; 22 | 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | public class JsonSimpleSerializer implements ODPJsonSerializer { 27 | @Override 28 | public String serializeEvents(List<ODPEvent> events) { 29 | JSONArray jsonArray = new JSONArray(); 30 | for (ODPEvent event: events) { 31 | JSONObject eventObject = new JSONObject(); 32 | eventObject.put("type", event.getType()); 33 | eventObject.put("action", event.getAction()); 34 | 35 | if (event.getIdentifiers() != null) { 36 | JSONObject identifiers = new JSONObject(); 37 | for (Map.Entry<String, String> identifier : event.getIdentifiers().entrySet()) { 38 | identifiers.put(identifier.getKey(), identifier.getValue()); 39 | } 40 | eventObject.put("identifiers", identifiers); 41 | } 42 | 43 | if (event.getData() != null) { 44 | JSONObject data = new JSONObject(); 45 | for (Map.Entry<String, Object> dataEntry : event.getData().entrySet()) { 46 | data.put(dataEntry.getKey(), dataEntry.getValue()); 47 | } 48 | eventObject.put("data", data); 49 | } 50 | 51 | jsonArray.add(eventObject); 52 | } 53 | return jsonArray.toJSONString(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/optimizelyconfig/OptimizelyAttribute.java: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2021, Optimizely, Inc. and contributors * 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 | * http://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.optimizelyconfig; 17 | 18 | import com.optimizely.ab.config.IdKeyMapped; 19 | 20 | /** 21 | * Represents the Attribute's map {@link OptimizelyConfig} 22 | */ 23 | public class OptimizelyAttribute implements IdKeyMapped { 24 | 25 | private String id; 26 | private String key; 27 | 28 | public OptimizelyAttribute(String id, 29 | String key) { 30 | this.id = id; 31 | this.key = key; 32 | } 33 | 34 | public String getId() { return id; } 35 | 36 | public String getKey() { return key; } 37 | 38 | @Override 39 | public boolean equals(Object obj) { 40 | if (obj == null || getClass() != obj.getClass()) return false; 41 | if (obj == this) return true; 42 | OptimizelyAttribute optimizelyAttribute = (OptimizelyAttribute) obj; 43 | return id.equals(optimizelyAttribute.getId()) && 44 | key.equals(optimizelyAttribute.getKey()); 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | int hash = id.hashCode(); 50 | hash = 31 * hash + key.hashCode(); 51 | return hash; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/optimizelyconfig/OptimizelyConfigManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.optimizelyconfig; 18 | 19 | public interface OptimizelyConfigManager { 20 | /** 21 | * Implementations of this method should return {@link OptimizelyConfig} 22 | * 23 | * @return {@link OptimizelyConfig} 24 | */ 25 | OptimizelyConfig getOptimizelyConfig(); 26 | } 27 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/optimizelydecision/DecisionMessage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.optimizely.ab.optimizelydecision; 19 | 20 | public enum DecisionMessage { 21 | SDK_NOT_READY("Optimizely SDK not configured properly yet."), 22 | FLAG_KEY_INVALID("No flag was found for key \"%s\"."), 23 | VARIABLE_VALUE_INVALID("Variable value for key \"%s\" is invalid or wrong type."); 24 | 25 | private String format; 26 | 27 | DecisionMessage(String format) { 28 | this.format = format; 29 | } 30 | 31 | public String reason(Object... args){ 32 | return String.format(format, args); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/optimizelydecision/DecisionReasons.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.optimizelydecision; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | public class DecisionReasons { 23 | 24 | protected final List<String> errors = new ArrayList<>(); 25 | protected final List<String> infos = new ArrayList<>(); 26 | 27 | public void addError(String format, Object... args) { 28 | String message = String.format(format, args); 29 | errors.add(message); 30 | } 31 | 32 | public String addInfo(String format, Object... args) { 33 | String message = String.format(format, args); 34 | infos.add(message); 35 | return message; 36 | } 37 | 38 | public void merge(DecisionReasons target) { 39 | errors.addAll(target.errors); 40 | infos.addAll(target.infos); 41 | } 42 | 43 | public List<String> toReport() { 44 | List<String> reasons = new ArrayList<>(errors); 45 | reasons.addAll(infos); 46 | return reasons; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/optimizelydecision/DecisionResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.optimizelydecision; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | 22 | public class DecisionResponse<T> { 23 | private T result; 24 | private DecisionReasons reasons; 25 | 26 | public DecisionResponse(@Nullable T result, @Nonnull DecisionReasons reasons) { 27 | this.result = result; 28 | this.reasons = reasons; 29 | } 30 | 31 | public static <E> DecisionResponse responseNoReasons(@Nullable E result) { 32 | return new DecisionResponse(result, DefaultDecisionReasons.newInstance()); 33 | } 34 | 35 | public static DecisionResponse nullNoReasons() { 36 | return new DecisionResponse(null, DefaultDecisionReasons.newInstance()); 37 | } 38 | 39 | @Nullable 40 | public T getResult() { 41 | return result; 42 | } 43 | 44 | @Nonnull 45 | public DecisionReasons getReasons() { 46 | return reasons; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core-api/src/main/java/com/optimizely/ab/optimizelydecision/OptimizelyDecideOption.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.optimizelydecision; 18 | 19 | public enum OptimizelyDecideOption { 20 | DISABLE_DECISION_EVENT, 21 | ENABLED_FLAGS_ONLY, 22 | IGNORE_USER_PROFILE_SERVICE, 23 | INCLUDE_REASONS, 24 | EXCLUDE_VARIABLES 25 | } 26 | -------------------------------------------------------------------------------- /core-api/src/main/resources/.gitignore: -------------------------------------------------------------------------------- 1 | optimizely-build-version -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/OptimizelyDecisionContextTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2021, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab; 18 | 19 | import org.junit.Test; 20 | import static junit.framework.TestCase.assertEquals; 21 | 22 | public class OptimizelyDecisionContextTest { 23 | 24 | @Test 25 | public void initializeOptimizelyDecisionContextWithFlagKeyAndRuleKey() { 26 | String flagKey = "test-flag-key"; 27 | String ruleKey = "1029384756"; 28 | String expectedKey = flagKey + OptimizelyDecisionContext.OPTI_KEY_DIVIDER + ruleKey; 29 | OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flagKey, ruleKey); 30 | assertEquals(flagKey, optimizelyDecisionContext.getFlagKey()); 31 | assertEquals(ruleKey, optimizelyDecisionContext.getRuleKey()); 32 | assertEquals(expectedKey, optimizelyDecisionContext.getKey()); 33 | } 34 | 35 | @Test 36 | public void initializeOptimizelyDecisionContextWithFlagKey() { 37 | String flagKey = "test-flag-key"; 38 | String expectedKey = flagKey + OptimizelyDecisionContext.OPTI_KEY_DIVIDER + OptimizelyDecisionContext.OPTI_NULL_RULE_KEY; 39 | OptimizelyDecisionContext optimizelyDecisionContext = new OptimizelyDecisionContext(flagKey, null); 40 | assertEquals(flagKey, optimizelyDecisionContext.getFlagKey()); 41 | assertEquals(OptimizelyDecisionContext.OPTI_NULL_RULE_KEY, optimizelyDecisionContext.getRuleKey()); 42 | assertEquals(expectedKey, optimizelyDecisionContext.getKey()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/OptimizelyForcedDecisionTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2021, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab; 18 | 19 | import org.junit.Test; 20 | import static junit.framework.TestCase.assertEquals; 21 | 22 | public class OptimizelyForcedDecisionTest { 23 | 24 | @Test 25 | public void initializeOptimizelyForcedDecision() { 26 | String variationKey = "test-variation-key"; 27 | OptimizelyForcedDecision optimizelyForcedDecision = new OptimizelyForcedDecision(variationKey); 28 | assertEquals(variationKey, optimizelyForcedDecision.getVariationKey()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/categories/ExhaustiveTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.categories; 18 | 19 | /** 20 | * Tests that may be <i>extremely</i> slow because they're exhaustively testing some parameter space. 21 | */ 22 | public interface ExhaustiveTest { 23 | } 24 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/config/AtomicProjectConfigManagerTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | 22 | import static com.optimizely.ab.config.DatafileProjectConfigTestUtils.validConfigJsonV4; 23 | import static org.junit.Assert.*; 24 | 25 | public class AtomicProjectConfigManagerTest { 26 | 27 | private AtomicProjectConfigManager projectConfigManager; 28 | 29 | @Before 30 | public void setUp() { 31 | projectConfigManager = new AtomicProjectConfigManager(); 32 | } 33 | 34 | @Test 35 | public void testGetAndSetConfig() throws Exception { 36 | assertNull(projectConfigManager.getConfig()); 37 | 38 | ProjectConfig projectConfig = new DatafileProjectConfig.Builder().withDatafile(validConfigJsonV4()).build(); 39 | projectConfigManager.setConfig(projectConfig); 40 | assertEquals(projectConfig, projectConfigManager.getConfig()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/config/VariationTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config; 18 | 19 | import org.junit.Test; 20 | 21 | import static org.hamcrest.CoreMatchers.is; 22 | import static org.hamcrest.MatcherAssert.assertThat; 23 | 24 | /** 25 | * Tests for {@link Variation}. 26 | */ 27 | public class VariationTest { 28 | 29 | /** 30 | * Not a grammatical error: verify that {@link Variation#is(String)} is comparing the provided value 31 | * with that given by {@link Variation#getKey()}. 32 | */ 33 | @Test 34 | public void isUsesVariationKey() throws Exception { 35 | Variation variation = new Variation("1234", "key"); 36 | assertThat(variation.is("blah"), is(false)); 37 | 38 | // we shouldn't be comparing the ids 39 | assertThat(variation.is("1234"), is(false)); 40 | 41 | // we *should* be comparing keys 42 | assertThat(variation.is("key"), is(true)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/config/audience/match/SubstringMatchTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.config.audience.match; 18 | 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | 22 | import java.util.Arrays; 23 | import java.util.Collections; 24 | import java.util.List; 25 | 26 | import static org.junit.Assert.*; 27 | 28 | public class SubstringMatchTest { 29 | 30 | private SubstringMatch match; 31 | private static final List<Object> INVALIDS = Collections.unmodifiableList(Arrays.asList(new byte[0], new Object(), null)); 32 | 33 | @Before 34 | public void setUp() { 35 | match = new SubstringMatch(); 36 | } 37 | 38 | @Test 39 | public void testInvalidConditionValues() { 40 | for (Object invalid : INVALIDS) { 41 | try { 42 | match.eval(invalid, "valid"); 43 | fail("should have raised exception"); 44 | } catch (UnexpectedValueTypeException e) { 45 | //pass 46 | } 47 | } 48 | } 49 | 50 | @Test 51 | public void testInvalidAttributesValues() throws UnexpectedValueTypeException { 52 | for (Object invalid : INVALIDS) { 53 | assertNull(match.eval("valid", invalid)); 54 | } 55 | } 56 | 57 | @Test 58 | public void testStringMatch() throws Exception { 59 | assertEquals(Boolean.TRUE, match.eval("", "any")); 60 | assertEquals(Boolean.TRUE, match.eval("same", "same")); 61 | assertEquals(Boolean.TRUE, match.eval("a", "ab")); 62 | assertEquals(Boolean.FALSE, match.eval("ab", "a")); 63 | assertEquals(Boolean.FALSE, match.eval("a", "b")); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/error/RaiseExceptionErrorHandlerTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019 Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.error; 18 | 19 | import com.optimizely.ab.OptimizelyRuntimeException; 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | 23 | public class RaiseExceptionErrorHandlerTest { 24 | 25 | private RaiseExceptionErrorHandler errorHandler; 26 | 27 | @Before 28 | public void setUp() throws Exception { 29 | errorHandler = new RaiseExceptionErrorHandler(); 30 | } 31 | 32 | @Test(expected = OptimizelyRuntimeException.class) 33 | public void handleError() { 34 | errorHandler.handleError(new OptimizelyRuntimeException()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/event/NoopEventHandlerTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017 Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event; 18 | 19 | import ch.qos.logback.classic.Level; 20 | 21 | import com.optimizely.ab.internal.LogbackVerifier; 22 | 23 | import org.junit.Rule; 24 | import org.junit.Test; 25 | 26 | import java.util.Collections; 27 | 28 | import static com.optimizely.ab.event.LogEvent.RequestMethod; 29 | 30 | /** 31 | * Tests for {@link NoopEventHandler} -- mostly for coverage... 32 | */ 33 | public class NoopEventHandlerTest { 34 | 35 | @Rule 36 | public LogbackVerifier logbackVerifier = new LogbackVerifier(); 37 | 38 | @Test 39 | public void dispatchEvent() throws Exception { 40 | NoopEventHandler noopEventHandler = new NoopEventHandler(); 41 | noopEventHandler.dispatchEvent( 42 | new LogEvent(RequestMethod.GET, "blah", Collections.<String, String>emptyMap(), null)); 43 | logbackVerifier.expectMessage(Level.DEBUG, "Called dispatchEvent with URL: blah and params: {}"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/event/internal/BaseEventTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event.internal; 18 | 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | 22 | import static org.junit.Assert.*; 23 | 24 | public class BaseEventTest { 25 | 26 | private BaseEvent baseEvent; 27 | 28 | @Before 29 | public void setUp() { 30 | this.baseEvent = new BaseEvent(); 31 | } 32 | 33 | @Test 34 | public void getUUID() { 35 | assertNotNull(baseEvent.getUUID()); 36 | assertFalse(baseEvent.getUUID().isEmpty()); 37 | } 38 | 39 | @Test 40 | public void getTimestamp() { 41 | assertTrue(baseEvent.getTimestamp() > 0); 42 | } 43 | } -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/event/internal/ClientEngineInfoTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.event.internal; 18 | 19 | import com.optimizely.ab.event.internal.payload.EventBatch; 20 | import org.junit.After; 21 | import org.junit.Test; 22 | 23 | import static org.junit.Assert.*; 24 | 25 | public class ClientEngineInfoTest { 26 | 27 | @After 28 | public void tearDown() throws Exception { 29 | ClientEngineInfo.setClientEngineName(ClientEngineInfo.DEFAULT_NAME); 30 | } 31 | 32 | @Test 33 | public void testSetAndGetClientEngine() { 34 | // default "java-sdk" name 35 | assertEquals("java-sdk", ClientEngineInfo.getClientEngineName()); 36 | 37 | ClientEngineInfo.setClientEngineName(null); 38 | assertEquals("java-sdk", ClientEngineInfo.getClientEngineName()); 39 | 40 | ClientEngineInfo.setClientEngineName(""); 41 | assertEquals("java-sdk", ClientEngineInfo.getClientEngineName()); 42 | 43 | ClientEngineInfo.setClientEngineName("test-name"); 44 | assertEquals("test-name", ClientEngineInfo.getClientEngineName()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/internal/JsonParserProviderTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.internal; 17 | 18 | import org.junit.After; 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import static org.junit.Assert.*; 22 | 23 | public class JsonParserProviderTest { 24 | @Before 25 | @After 26 | public void clearParserSystemProperty() { 27 | PropertyUtils.clear("default_parser"); 28 | } 29 | 30 | @Test 31 | public void getGsonParserProviderWhenNoDefaultIsSet() { 32 | assertEquals(JsonParserProvider.GSON_CONFIG_PARSER, JsonParserProvider.getDefaultParser()); 33 | } 34 | 35 | @Test 36 | public void getCorrectParserProviderWhenValidDefaultIsProvided() { 37 | PropertyUtils.set("default_parser", "JSON_CONFIG_PARSER"); 38 | assertEquals(JsonParserProvider.JSON_CONFIG_PARSER, JsonParserProvider.getDefaultParser()); 39 | } 40 | 41 | @Test 42 | public void getGsonParserWhenProvidedDefaultParserDoesNotExist() { 43 | PropertyUtils.set("default_parser", "GARBAGE_VALUE"); 44 | assertEquals(JsonParserProvider.GSON_CONFIG_PARSER, JsonParserProvider.getDefaultParser()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/internal/PropertyUtilTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.internal; 18 | 19 | import org.junit.After; 20 | import org.junit.Test; 21 | 22 | import static org.junit.Assert.*; 23 | 24 | public class PropertyUtilTest { 25 | 26 | private static final String SHARED_KEY = "test.prop"; 27 | private static final String EXPECTED = "bar"; 28 | 29 | @After 30 | public void tearDown() { 31 | System.setProperty(SHARED_KEY, "INVALID"); 32 | } 33 | 34 | @Test 35 | public void testSystemPropBeforeOptimizelyProp() { 36 | String expected = "foo"; 37 | System.setProperty("optimizely." + SHARED_KEY, expected); 38 | assertEquals(expected, PropertyUtils.get(SHARED_KEY)); 39 | } 40 | 41 | @Test 42 | public void getFromOptimizelyProp() { 43 | assertEquals(EXPECTED, PropertyUtils.get("file.only")); 44 | } 45 | 46 | @Test 47 | public void getFromSystemProp() { 48 | System.setProperty("optimizely.sys.only", EXPECTED); 49 | assertEquals(EXPECTED, PropertyUtils.get("sys.only")); 50 | } 51 | } -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/internal/SafetyUtilsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.internal; 18 | 19 | import org.junit.Test; 20 | 21 | import java.io.Closeable; 22 | import java.io.IOException; 23 | 24 | import static org.junit.Assert.*; 25 | import static org.mockito.Mockito.doThrow; 26 | import static org.mockito.Mockito.mock; 27 | import static org.mockito.Mockito.verify; 28 | 29 | public class SafetyUtilsTest { 30 | 31 | @Test 32 | public void tryCloseAutoCloseable() throws Exception { 33 | AutoCloseable autocloseable = mock(AutoCloseable.class); 34 | SafetyUtils.tryClose(autocloseable); 35 | 36 | verify(autocloseable).close(); 37 | } 38 | 39 | @Test 40 | public void tryCloseCloseable() throws Exception { 41 | Closeable closeable = mock(Closeable.class); 42 | SafetyUtils.tryClose(closeable); 43 | 44 | verify(closeable).close(); 45 | } 46 | 47 | @Test 48 | public void tryCloseNullDoesNotThrow() throws Exception { 49 | SafetyUtils.tryClose(null); 50 | } 51 | 52 | @Test 53 | public void tryCloseExceptionDoesNotThrow() throws Exception { 54 | AutoCloseable autocloseable = mock(AutoCloseable.class); 55 | doThrow(new RuntimeException()).when(autocloseable).close(); 56 | SafetyUtils.tryClose(autocloseable); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/notification/FeatureTestSourceInfoTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.optimizely.ab.notification; 19 | 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | 23 | import java.util.HashMap; 24 | 25 | import static org.junit.Assert.assertEquals; 26 | 27 | public class FeatureTestSourceInfoTest { 28 | 29 | private static final String EXPERIMENT_KEY = "featureTestKey"; 30 | private static final String VARIATION_KEY = "featureTestVariationKey"; 31 | 32 | private FeatureTestSourceInfo featureSourceInfo; 33 | 34 | @Before 35 | public void setUp() { 36 | featureSourceInfo = new FeatureTestSourceInfo(EXPERIMENT_KEY, VARIATION_KEY); 37 | } 38 | 39 | @Test 40 | public void testGet() { 41 | HashMap<String, String> expectedSourceInfo = new HashMap<>(); 42 | expectedSourceInfo.put("experimentKey", EXPERIMENT_KEY); 43 | expectedSourceInfo.put("variationKey", VARIATION_KEY); 44 | 45 | assertEquals(expectedSourceInfo, featureSourceInfo.get()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/notification/RolloutSourceInfoTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package com.optimizely.ab.notification; 19 | 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | 23 | import java.util.Collections; 24 | import java.util.Map; 25 | 26 | import static org.junit.Assert.assertEquals; 27 | 28 | public class RolloutSourceInfoTest { 29 | 30 | private RolloutSourceInfo rolloutSourceInfo; 31 | 32 | @Before 33 | public void setUp() { 34 | rolloutSourceInfo = new RolloutSourceInfo(); 35 | } 36 | 37 | @Test 38 | public void testGet() { 39 | Map<String, String> expectedInfo = Collections.EMPTY_MAP; 40 | assertEquals(expectedInfo, rolloutSourceInfo.get()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/notification/TestNotification.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.notification; 18 | 19 | /** 20 | * TestNotification used for unit testing NotificationCenter and NotificationManager 21 | */ 22 | class TestNotification { 23 | private final String message; 24 | 25 | TestNotification(String message) { 26 | this.message = message; 27 | } 28 | 29 | String getMessage() { 30 | return message; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/notification/TestNotificationHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2019, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.notification; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * TestNotificationHandler used for unit testing NotificationCenter and NotificationManager 24 | */ 25 | class TestNotificationHandler<T> implements NotificationHandler<T> { 26 | private final List<T> messages = new ArrayList<>(); 27 | 28 | @Override 29 | public void handle(T message) { 30 | messages.add(message); 31 | } 32 | 33 | List<T> getMessages() { 34 | return messages; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/odp/parser/ResponseJsonParserFactoryTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2022, Optimizely Inc. and contributors 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 | * http://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.odp.parser; 17 | 18 | import com.optimizely.ab.internal.PropertyUtils; 19 | import com.optimizely.ab.odp.parser.impl.GsonParser; 20 | import com.optimizely.ab.odp.parser.impl.JsonParser; 21 | import org.junit.After; 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | 25 | import static org.junit.Assert.*; 26 | 27 | public class ResponseJsonParserFactoryTest { 28 | @Before 29 | @After 30 | public void clearParserSystemProperty() { 31 | PropertyUtils.clear("default_parser"); 32 | } 33 | 34 | @Test 35 | public void getGsonParserWhenNoDefaultIsSet() { 36 | assertEquals(GsonParser.class, ResponseJsonParserFactory.getParser().getClass()); 37 | } 38 | 39 | @Test 40 | public void getCorrectParserWhenValidDefaultIsProvided() { 41 | PropertyUtils.set("default_parser", "JSON_CONFIG_PARSER"); 42 | assertEquals(JsonParser.class, ResponseJsonParserFactory.getParser().getClass()); 43 | } 44 | 45 | @Test 46 | public void getGsonParserWhenGivenDefaultParserDoesNotExist() { 47 | PropertyUtils.set("default_parser", "GARBAGE_VALUE"); 48 | assertEquals(GsonParser.class, ResponseJsonParserFactory.getParser().getClass()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/optimizelyconfig/OptimizelyAttributeTest.java: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2021, Optimizely, Inc. and contributors * 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 | * http://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.optimizelyconfig; 17 | 18 | import org.junit.Test; 19 | 20 | import static org.junit.Assert.assertEquals; 21 | 22 | public class OptimizelyAttributeTest { 23 | 24 | @Test 25 | public void testOptimizelyAttribute() { 26 | OptimizelyAttribute optimizelyAttribute1 = new OptimizelyAttribute( 27 | "5", 28 | "test_attribute" 29 | ); 30 | OptimizelyAttribute optimizelyAttribute2 = new OptimizelyAttribute( 31 | "5", 32 | "test_attribute" 33 | ); 34 | assertEquals("5", optimizelyAttribute1.getId()); 35 | assertEquals("test_attribute", optimizelyAttribute1.getKey()); 36 | assertEquals(optimizelyAttribute1, optimizelyAttribute2); 37 | assertEquals(optimizelyAttribute1.hashCode(), optimizelyAttribute2.hashCode()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/optimizelyconfig/OptimizelyEventTest.java: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2020-2021, Optimizely, Inc. and contributors * 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 | * http://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.optimizelyconfig; 17 | import org.junit.Test; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static java.util.Arrays.asList; 21 | 22 | public class OptimizelyEventTest { 23 | @Test 24 | public void testOptimizelyEvent() { 25 | OptimizelyEvent optimizelyEvent1 = new OptimizelyEvent( 26 | "5", 27 | "test_event", 28 | asList("123","234","345") 29 | ); 30 | OptimizelyEvent optimizelyEvent2 = new OptimizelyEvent( 31 | "5", 32 | "test_event", 33 | asList("123","234","345") 34 | ); 35 | assertEquals("5", optimizelyEvent1.getId()); 36 | assertEquals("test_event", optimizelyEvent1.getKey()); 37 | assertEquals(optimizelyEvent1, optimizelyEvent2); 38 | assertEquals(optimizelyEvent1.hashCode(), optimizelyEvent2.hashCode()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/optimizelyconfig/OptimizelyVariableTest.java: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright 2020, Optimizely, Inc. and contributors * 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 | * http://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.optimizelyconfig; 17 | 18 | import org.junit.Test; 19 | 20 | import static org.junit.Assert.assertEquals; 21 | 22 | public class OptimizelyVariableTest { 23 | 24 | @Test 25 | public void testOptimizelyVariable() { 26 | OptimizelyVariable optimizelyVariable = new OptimizelyVariable( 27 | "7", 28 | "test_variable_key", 29 | "integer", 30 | "10" 31 | ); 32 | assertEquals("7", optimizelyVariable.getId()); 33 | assertEquals("test_variable_key", optimizelyVariable.getKey()); 34 | assertEquals("integer", optimizelyVariable.getType()); 35 | assertEquals("10", optimizelyVariable.getValue()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/optimizelyjson/TestTypes.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2020, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.optimizelyjson; 18 | 19 | /** 20 | * Test types for parsing JSON strings to Java objects (OptimizelyJSON) 21 | */ 22 | public class TestTypes { 23 | 24 | public static class MD1 { 25 | public String k1; 26 | public boolean k2; 27 | public MD2 k3; 28 | } 29 | 30 | public static class MD2 { 31 | public double kk1; 32 | public MD3 kk2; 33 | } 34 | 35 | public static class MD3 { 36 | public boolean kkk1; 37 | public double kkk2; 38 | public String kkk3; 39 | public Object[] kkk4; 40 | } 41 | 42 | // Invalid parse type 43 | 44 | public static class NotMatchingType { 45 | public String x99; 46 | } 47 | 48 | // Test types for integer parsing tests 49 | 50 | public static class MDN1 { 51 | public int k1; 52 | public double k2; 53 | public MDN2 k3; 54 | } 55 | 56 | public static class MDN2 { 57 | public int kk1; 58 | public double kk2; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /core-api/src/test/java/com/optimizely/ab/testutils/OTUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2022, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab.testutils; 18 | 19 | import com.optimizely.ab.*; 20 | import java.util.Collections; 21 | import java.util.Map; 22 | 23 | public class OTUtils { 24 | public static OptimizelyUserContext user(String userId, Map<String, ?> attributes) { 25 | Optimizely optimizely = new Optimizely.Builder().build(); 26 | return new OptimizelyUserContext(optimizely, userId, attributes); 27 | } 28 | 29 | public static OptimizelyUserContext user(Map<String,?> attributes) { 30 | return user("any-user", attributes); 31 | } 32 | 33 | public static OptimizelyUserContext user() { 34 | return user("any-user", Collections.emptyMap()); 35 | } 36 | } -------------------------------------------------------------------------------- /core-api/src/test/resources/optimizely.properties: -------------------------------------------------------------------------------- 1 | file.only = bar 2 | test.prop = baz 3 | -------------------------------------------------------------------------------- /core-api/src/test/resources/serializer/conversion-session-id.json: -------------------------------------------------------------------------------- 1 | { 2 | "account_id": "3", 3 | "visitors": [ 4 | { 5 | "snapshots": [ 6 | { 7 | "events": [ 8 | { 9 | "revenue": 5000, 10 | "entity_id": "7", 11 | "type": "testevent", 12 | "uuid": "uuid", 13 | "key": "testevent", 14 | "timestamp": 12345 15 | } 16 | ] 17 | } 18 | ], 19 | "attributes": [ 20 | { 21 | "entity_id": "6", 22 | "type": "custom", 23 | "value": "testfeaturevalue", 24 | "key": "testfeature" 25 | } 26 | ], 27 | "visitor_id": "testvisitor", 28 | "session_id": "sessionid" 29 | } 30 | ], 31 | "client_name": "java-sdk", 32 | "client_version": "0.1.1", 33 | "anonymize_ip": true, 34 | "enrich_decisions": true, 35 | "project_id": "1", 36 | "revision": "1" 37 | } -------------------------------------------------------------------------------- /core-api/src/test/resources/serializer/conversion.json: -------------------------------------------------------------------------------- 1 | { 2 | "account_id": "3", 3 | "visitors": [ 4 | { 5 | "snapshots": [ 6 | { 7 | "events": [ 8 | { 9 | "revenue": 5000, 10 | "entity_id": "7", 11 | "type": "testevent", 12 | "uuid": "uuid", 13 | "key": "testevent", 14 | "timestamp": 12345 15 | } 16 | ] 17 | } 18 | ], 19 | "attributes": [ 20 | { 21 | "entity_id": "6", 22 | "type": "custom", 23 | "value": "testfeaturevalue", 24 | "key": "testfeature" 25 | } 26 | ], 27 | "visitor_id": "testvisitor" 28 | } 29 | ], 30 | "client_name": "java-sdk", 31 | "client_version": "0.1.1", 32 | "anonymize_ip": true, 33 | "enrich_decisions": true, 34 | "project_id": "1", 35 | "revision": "1" 36 | } -------------------------------------------------------------------------------- /core-api/src/test/resources/serializer/impression-session-id.json: -------------------------------------------------------------------------------- 1 | { 2 | "account_id": "3", 3 | "visitors": [ 4 | { 5 | "snapshots": [ 6 | { 7 | "decisions": [ 8 | { 9 | "variation_id": "4", 10 | "campaign_id": "2", 11 | "experiment_id": "5", 12 | "is_campaign_holdback": false 13 | } 14 | ], 15 | "events": [ 16 | { 17 | "revenue": 5000, 18 | "entity_id": "7", 19 | "type": "testevent", 20 | "uuid": "uuid", 21 | "key": "testevent", 22 | "timestamp": 12345 23 | } 24 | ] 25 | } 26 | ], 27 | "attributes": [ 28 | { 29 | "entity_id": "6", 30 | "type": "custom", 31 | "value": "testfeaturevalue", 32 | "key": "testfeature" 33 | } 34 | ], 35 | "visitor_id": "testvisitor", 36 | "session_id": "sessionid" 37 | } 38 | ], 39 | "client_name": "java-sdk", 40 | "client_version": "0.1.1", 41 | "anonymize_ip": true, 42 | "enrich_decisions": true, 43 | "project_id": "1", 44 | "revision": "1" 45 | } -------------------------------------------------------------------------------- /core-api/src/test/resources/serializer/impression.json: -------------------------------------------------------------------------------- 1 | { 2 | "account_id": "3", 3 | "visitors": [ 4 | { 5 | "snapshots": [ 6 | { 7 | "decisions": [ 8 | { 9 | "variation_id": "4", 10 | "campaign_id": "2", 11 | "experiment_id": "5", 12 | "is_campaign_holdback": false 13 | } 14 | ], 15 | "events": [ 16 | { 17 | "revenue": 5000, 18 | "entity_id": "7", 19 | "type": "testevent", 20 | "uuid": "uuid", 21 | "key": "testevent", 22 | "timestamp": 12345 23 | } 24 | ] 25 | } 26 | ], 27 | "attributes": [ 28 | { 29 | "entity_id": "6", 30 | "type": "custom", 31 | "value": "testfeaturevalue", 32 | "key": "testfeature" 33 | } 34 | ], 35 | "visitor_id": "testvisitor" 36 | } 37 | ], 38 | "client_name": "java-sdk", 39 | "client_version": "0.1.1", 40 | "anonymize_ip": true, 41 | "enrich_decisions": true, 42 | "project_id": "1", 43 | "revision": "1" 44 | } -------------------------------------------------------------------------------- /core-httpclient-impl/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation project(':core-api') 3 | implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: httpClientVersion 4 | implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion 5 | implementation group: 'com.google.code.findbugs', name: 'annotations', version: findbugsAnnotationVersion 6 | implementation group: 'com.google.code.findbugs', name: 'jsr305', version: findbugsJsrVersion 7 | testImplementation 'org.mock-server:mockserver-netty:5.1.1' 8 | } 9 | 10 | task exhaustiveTest { 11 | dependsOn('test') 12 | } 13 | -------------------------------------------------------------------------------- /core-httpclient-impl/src/main/java/com/optimizely/ab/HttpClientUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016-2017, 2019, 2022-2023, Optimizely and contributors 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.optimizely.ab; 18 | 19 | import org.apache.http.client.config.RequestConfig; 20 | 21 | /** 22 | * Provides defaults and utility methods for using {@link org.apache.http.client.HttpClient}. 23 | */ 24 | public final class HttpClientUtils { 25 | 26 | public static final int CONNECTION_TIMEOUT_MS = 10000; 27 | public static final int CONNECTION_REQUEST_TIMEOUT_MS = 5000; 28 | public static final int SOCKET_TIMEOUT_MS = 10000; 29 | public static final int DEFAULT_VALIDATE_AFTER_INACTIVITY = 1000; 30 | public static final int DEFAULT_MAX_CONNECTIONS = 200; 31 | public static final int DEFAULT_MAX_PER_ROUTE = 20; 32 | private static RequestConfig requestConfigWithTimeout; 33 | 34 | private HttpClientUtils() { 35 | } 36 | 37 | public static final RequestConfig DEFAULT_REQUEST_CONFIG = RequestConfig.custom() 38 | .setConnectTimeout(CONNECTION_TIMEOUT_MS) 39 | .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT_MS) 40 | .setSocketTimeout(SOCKET_TIMEOUT_MS) 41 | .build(); 42 | 43 | public static RequestConfig getDefaultRequestConfigWithTimeout(int timeoutMillis) { 44 | requestConfigWithTimeout = RequestConfig.custom() 45 | .setConnectTimeout(timeoutMillis) 46 | .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT_MS) 47 | .setSocketTimeout(timeoutMillis) 48 | .build(); 49 | return requestConfigWithTimeout; 50 | } 51 | 52 | public static OptimizelyHttpClient getDefaultHttpClient() { 53 | return OptimizelyHttpClient.builder().build(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # Generate Code Documentation 2 | ### Steps 3 | * Checkout **master** branch. 4 | * Open project in **IntelliJ**. 5 | * Go to **Tools -> Generate JavaDoc** 6 | * Make sure **Generate JavaDoc scope -> Custom Scope** is checked. 7 | * Click on three dotted icon to make custom scope. 8 | * Give name **Custom_Docs**. 9 | * Copy and paste following regex: **`!*..internal..*&&!test:*..*&&!lib:*..*`** into **Pattern** and click **OK**. 10 | * Uncheck **Include test sources**. 11 | * Select **Output Directory**. 12 | * Click **OK**. 13 | * This will generate HTML documentation in given **Output Directory**. 14 | * Browse **Output Directory/index.html** in browser. 15 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Maven version 2 | version = 3.1.0-SNAPSHOT 3 | 4 | # Artifact paths 5 | mavenS3Bucket = optimizely-maven 6 | 7 | # Gradle Settings 8 | org.gradle.configureondemand = true 9 | org.gradle.daemon = true 10 | org.gradle.parallel = true 11 | 12 | # Application Packages 13 | gsonVersion = 2.10.1 14 | guavaVersion = 22.0 15 | hamcrestVersion = 1.3 16 | # NOTE: jackson 2.14+ uses Java8 stream apis not supported in android 17 | jacksonVersion = 2.13.5 18 | jsonVersion = 20190722 19 | jsonSimpleVersion = 1.1.1 20 | logbackVersion = 1.2.3 21 | slf4jVersion = 1.7.30 22 | httpClientVersion = 4.5.14 23 | log4jVersion = 2.20.0 24 | 25 | # Style Packages 26 | findbugsAnnotationVersion = 3.0.1 27 | findbugsJsrVersion = 3.0.2 28 | 29 | # Test Packages 30 | junitVersion = 4.13 31 | mockitoVersion = 1.10.19 32 | commonCodecVersion = 1.15 33 | -------------------------------------------------------------------------------- /gradle/publish.gradle: -------------------------------------------------------------------------------- 1 | ext.s3Credentials = { 2 | accessKey System.getenv('AWS_ACCESS_KEY_ID') 3 | secretKey System.getenv('AWS_SECRET_ACCESS_KEY') 4 | } 5 | 6 | subprojects { 7 | // Add a per-project function to include maven artifact publication. 8 | // To enable publication in a sub-project, include 'publishArtifacts()' in its build. 9 | ext.publishArtifacts = { 10 | apply plugin: 'maven-publish' 11 | 12 | publishing { 13 | publications { 14 | mavanJava(MavenPublication) { 15 | from components.java 16 | artifact sourcesJar 17 | artifact javadocJar 18 | pom.withXml { 19 | asNode().children().last() + { 20 | resolveStrategy = Closure.DELEGATE_FIRST 21 | url 'https://github.com/optimizely/java-sdk' 22 | licenses { 23 | license { 24 | name 'The Apache Software License, Version 2.0' 25 | url 'http://www.apache.org/license/LICENSE-2.0.txt' 26 | distribution 'repo' 27 | } 28 | } 29 | developers { 30 | developer { 31 | id 'optimizely' 32 | name 'Optimizely' 33 | email 'developers@optimizely.com' 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | } 41 | 42 | publishing { 43 | repositories { 44 | maven { 45 | url "s3://$mavenS3Bucket" 46 | credentials(AwsCredentials, s3Credentials) 47 | } 48 | } 49 | } 50 | 51 | // publish artifacts as part of the release process 52 | // afterReleaseBuild.dependsOn publish 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/optimizely/java-sdk/746e81530a9224fabcd7f610d81800358e6e34c9/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /java-quickstart/README.md: -------------------------------------------------------------------------------- 1 | Optimizely Java QuickStart 2 | =================== 3 | 4 | This package contains the Java QuickStart app that can be used to test that the Java SDK can communicate with the CDN and Optimizely results. 5 | Simply create a new project with an experiment called "background_experiment" with 2 variations and a conversion event named "sample_conversion". 6 | From there you can test different attributes setups and other Optimizely Java SDK APIs. 7 | This is just a simple example that gets you up and running quickly! 8 | 9 | ## Getting Started 10 | Create an experiment on app.optimizely.com named "background_experiment" with variations "variation_a" and "variation_b" and one conversion event "sample_conversion.". 11 | Use that SDK key in the [`com.optimizely.Example.java`](https://github.com/optimizely/java-sdk/blob/master/java-quickstart/src/main/java/com/optimizely/Example.java) 12 | and you are set to test. 13 | 14 | ### Run Example 15 | 16 | Running `./gradlew runExample` will build and execute [`com.optimizely.Example.java`](https://github.com/optimizely/java-sdk/blob/master/java-quickstart/src/main/java/com/optimizely/Example.java). 17 | -------------------------------------------------------------------------------- /java-quickstart/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | implementation project(':core-api') 5 | implementation project(':core-httpclient-impl') 6 | 7 | implementation group: 'com.google.code.gson', name: 'gson', version: gsonVersion 8 | implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: httpClientVersion 9 | implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: log4jVersion 10 | implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: log4jVersion 11 | implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: log4jVersion 12 | 13 | testImplementation group: 'junit', name: 'junit', version: junitVersion 14 | } 15 | 16 | task runExample(type: JavaExec) { 17 | systemProperties System.properties 18 | 19 | main "com.optimizely.Example" 20 | classpath sourceSets.test.runtimeClasspath 21 | } 22 | -------------------------------------------------------------------------------- /java-quickstart/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/optimizely/java-sdk/746e81530a9224fabcd7f610d81800358e6e34c9/java-quickstart/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /java-quickstart/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip 6 | -------------------------------------------------------------------------------- /java-quickstart/libs/core-api-2.0.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/optimizely/java-sdk/746e81530a9224fabcd7f610d81800358e6e34c9/java-quickstart/libs/core-api-2.0.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /java-quickstart/libs/core-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/optimizely/java-sdk/746e81530a9224fabcd7f610d81800358e6e34c9/java-quickstart/libs/core-api.jar -------------------------------------------------------------------------------- /java-quickstart/libs/core-httpclient-impl-2.0.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/optimizely/java-sdk/746e81530a9224fabcd7f610d81800358e6e34c9/java-quickstart/libs/core-httpclient-impl-2.0.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /java-quickstart/libs/core-httpclient-impl.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/optimizely/java-sdk/746e81530a9224fabcd7f610d81800358e6e34c9/java-quickstart/libs/core-httpclient-impl.jar -------------------------------------------------------------------------------- /java-quickstart/src/main/resources/log4j2.properties: -------------------------------------------------------------------------------- 1 | # Set the root logger level to INFO and its appender to the console 2 | 3 | appender.console.type = Console 4 | appender.console.name = STDOUT 5 | appender.console.layout.type = PatternLayout 6 | appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n 7 | 8 | # Specify the loggers 9 | rootLogger.level = debug 10 | rootLogger.appenderRef.stdout.ref = STDOUT 11 | -------------------------------------------------------------------------------- /resources/HEADER: -------------------------------------------------------------------------------- 1 | Copyright ${year}, Optimizely Inc. and contributors 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ab-sdk' 2 | 3 | include 'core-api' 4 | include 'core-httpclient-impl' 5 | include 'java-quickstart' 6 | 7 | --------------------------------------------------------------------------------