diff --git a/README.md b/README.md index edc15d6..b5f214e 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,17 @@ # featurevisor-example-java -A simple Java application that uses Featurevisor Java SDK. +A small Java application showing how to use the [Featurevisor Java SDK](https://github.com/featurevisor/featurevisor-java). -Learn more about Featurevisor: https://featurevisor.com +Learn more about Featurevisor [here](https://featurevisor.com). -## Installation +It fetches a production datafile, creates a Featurevisor instance with customer context, then evaluates a flag, a variation, feature variables, and global variables. -Clone the repository, and install the dependencies: +## GitHub Packages access -## Setup `settings.xml` - -Create a new file at `~/.m2/settings.xml` with the following content: +The SDK is published through GitHub Packages. Create `~/.m2/settings.xml` with credentials that have the `read:packages` scope: ```xml - - - + github @@ -26,32 +19,39 @@ Create a new file at `~/.m2/settings.xml` with the following content: YOUR_GITHUB_TOKEN - ``` -You can generate a new GitHub token here with `read:packages` scope: https://github.com/settings/tokens +Keep this file outside the repository. -This file is meant to not be committed to the repository, as `.gitignore` is configured to ignore it. +## Run the example -## Install dependencies - -``` -$ mvn install +```sh +mvn clean compile +mvn exec:java -Dexec.mainClass="com.example.App" ``` -## Compile +The application evaluates `commerce_platform`, `checkout_experience`, `max_items`, `payment_methods`, `serviceEndpoints`, and `supportContact` from this datafile: -``` -$ mvn clean compile +```text +https://featurevisor-example-cloudflare.pages.dev/production/featurevisor-sdk-v3.json ``` -## Usage +Expected output: -``` -$ mvn exec:java -Dexec.mainClass="com.example.App" +```text +Commerce platform enabled: true +Checkout variation: express +Maximum checkout items: 25 +Payment methods: [card, wallet] +Service endpoint: https://api.eu.example.com (timeout: 1200 ms, retries: 4) +Support contact: support-nl@example.com ``` +Change the context in `App.java` to see how Featurevisor selects different rules, variations, and global variable overrides. + ## Featurevisor project -Uses this Featurevisor project to fetch the configuration from: https://github.com/featurevisor/featurevisor-example-cloudflare +The datafile is generated by the [Featurevisor Cloudflare example](https://github.com/featurevisor/featurevisor-example-cloudflare). + +Learn more in the [Featurevisor Java SDK documentation](https://featurevisor.com/docs/sdks/java/). diff --git a/pom.xml b/pom.xml index 853e5c7..6bca807 100644 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,7 @@ 11 11 + 11 UTF-8 @@ -31,12 +32,7 @@ com.featurevisor featurevisor-java - 3.0.0 - - - com.fasterxml.jackson.core - jackson-databind - 2.15.2 + 4.0.0 @@ -47,8 +43,7 @@ maven-compiler-plugin 3.11.0 - 11 - 11 + 11 diff --git a/src/main/java/com/example/App.java b/src/main/java/com/example/App.java index 12e8d16..db52c41 100644 --- a/src/main/java/com/example/App.java +++ b/src/main/java/com/example/App.java @@ -1,44 +1,86 @@ package com.example; import com.featurevisor.sdk.Featurevisor; +import com.featurevisor.sdk.FeaturevisorLogLevel; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.List; +import java.util.Map; public class App { - public static void main(String[] args) { + private static final String DATAFILE_URL = + "https://featurevisor-example-cloudflare.pages.dev/production/featurevisor-sdk-v3.json"; + + public static void main(String[] args) throws Exception { + String datafile = fetchDatafile(); + Map context = Map.of( + "userId", "customer-123", + "country", "nl", + "locale", "nl-NL", + "accountPlan", "pro" + ); + + Featurevisor f = Featurevisor.createFeaturevisor( + new Featurevisor.FeaturevisorOptions() + .datafileString(datafile) + .context(context) + .logLevel(FeaturevisorLogLevel.ERROR) + ); + try { - // Fetch JSON content from the Featurevisor datafile URL - String jsonContent = fetchJsonFromUrl("https://featurevisor-example-cloudflare.pages.dev/production/featurevisor-tag-all.json"); - System.out.println("Fetched JSON content"); - - // Create Featurevisor SDK instance with the datafile content - Featurevisor instance = Featurevisor.createFeaturevisor( - new Featurevisor.FeaturevisorOptions().datafileString(jsonContent)); - - // evaluate feature - boolean isFeatureEnabled = instance.isEnabled("my_feature"); - System.out.println("Feature is enabled: " + isFeatureEnabled); - } catch (Exception e) { - System.err.println("Error: " + e.getMessage()); - e.printStackTrace(); + boolean commerceEnabled = f.isEnabled("commerce_platform"); + String checkoutVariation = f.getVariation("checkout_experience"); + Integer maxItems = f.getVariableInteger("checkout_experience", "max_items"); + List paymentMethods = f.getVariableArray( + "checkout_experience", + "payment_methods" + ); + Map endpoints = f.getVariableObject("serviceEndpoints"); + String supportContact = f.getVariableString("supportContact"); + + System.out.println("Commerce platform enabled: " + commerceEnabled); + System.out.println("Checkout variation: " + valueOrUnavailable(checkoutVariation)); + System.out.println("Maximum checkout items: " + valueOrUnavailable(maxItems)); + System.out.println("Payment methods: " + paymentMethods); + System.out.printf( + "Service endpoint: %s (timeout: %s ms, retries: %s)%n", + endpoints.get("baseUrl"), + endpoints.get("timeoutMs"), + endpoints.get("retries") + ); + System.out.println("Support contact: " + valueOrUnavailable(supportContact)); + } finally { + f.close(); } } - private static String fetchJsonFromUrl(String url) throws Exception { - HttpClient client = HttpClient.newHttpClient(); + private static String fetchDatafile() throws Exception { + HttpClient client = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .build(); HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(url)) + .uri(URI.create(DATAFILE_URL)) + .timeout(Duration.ofSeconds(10)) + .header("Accept", "application/json") .build(); + HttpResponse response = client.send( + request, + HttpResponse.BodyHandlers.ofString() + ); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - - if (response.statusCode() != 200) { - throw new RuntimeException("Failed to fetch JSON: HTTP " + response.statusCode()); + if (response.statusCode() < 200 || response.statusCode() >= 300) { + throw new IllegalStateException( + "Datafile request failed with HTTP " + response.statusCode() + ); } - return response.body(); } + + private static Object valueOrUnavailable(Object value) { + return value == null ? "unavailable" : value; + } }