Javav1.2.1Backend

Java SDK

Server-side feature flags for Java 11+ with built-in circuit breaker, zero external dependencies, caching, and SSE streaming support.

🛡️

Circuit Breaker

Auto-recovery

📦

Zero Dependencies

Uses java.net.http

💾

Caching

Persistent cache

SSE Support

Real-time updates

Installation

Maven (pom.xml)
<dependency>
    <groupId>io.rollgate</groupId>
    <artifactId>rollgate-sdk</artifactId>
    <version>1.2.1</version>
</dependency>
Gradle (build.gradle)
implementation 'io.rollgate:rollgate-sdk:1.2.1'

Quick Start

Application.java
import io.rollgate.RollgateClient;
import io.rollgate.RollgateConfig;
import java.time.Duration;

// Initialize once at startup
RollgateClient client = new RollgateClient(
    RollgateConfig.builder()
        .apiKey(System.getenv("ROLLGATE_API_KEY"))
        .baseUrl("https://api.rollgate.io")
        .refreshInterval(Duration.ofSeconds(30))
        .build()
);

// Initialize and start polling
client.init();

// Check flags
boolean enabled = client.isEnabled("my-feature", false);

// Identify user
client.identify(UserContext.builder()
    .id("user-123")
    .email("[email protected]")
    .attribute("plan", "pro")
    .build());

// Cleanup on shutdown
client.close();

Configuration

Configuration uses the builder pattern via RollgateConfig.builder().

OptionTypeDefaultDescription
apiKeyStringrequiredServer API key (rg_server_...)
baseUrlString'https://api.rollgate.io'API base URL
refreshIntervalDurationDuration.ofSeconds(30)Polling interval, Duration.ZERO to disable
enableStreamingbooleanfalseUse SSE for real-time updates (opt-in)
timeoutDurationDuration.ofSeconds(5)HTTP request timeout
Full configuration example
RollgateConfig config = RollgateConfig.builder()
    .apiKey(System.getenv("ROLLGATE_API_KEY"))
    .baseUrl("https://api.rollgate.io")
    .refreshInterval(Duration.ofSeconds(30))
    .enableStreaming(false)
    .timeout(Duration.ofSeconds(5))
    .build();

RollgateClient client = new RollgateClient(config);

Methods

init()

Initialize the client and fetch flags from the server. Must be called before evaluating any flags.

client.init();

close()

Shut down the client, stop polling/streaming, and release resources.

client.close();

isEnabled(key, defaultValue)

Check if a boolean flag is enabled. Returns the flag value or the default.

boolean showFeature = client.isEnabled("new-feature", false);

if (showFeature) {
    // New feature code
}

getValue(key, defaultValue)

Get a flag value of any type. Returns an Object that can be cast to the expected type.

Object value = client.getValue("feature-config", null);

getString(key, defaultValue)

Type-safe helper for string flags.

String buttonColor = client.getString("cta-color", "blue");
String variant = client.getString("checkout-variant", "control");

getNumber(key, defaultValue)

Type-safe helper for number flags.

double pageSize = client.getNumber("results-per-page", 20);
double timeout = client.getNumber("api-timeout-ms", 5000);

getJSON<T>(key, defaultValue, clazz)

Type-safe helper for JSON flags. Deserializes the flag value into the specified class.

public class FeatureConfig {
    public boolean enabled;
    public int maxItems;
    public List<String> allowedRoles;
}

FeatureConfig config = client.getJSON("feature-config",
    new FeatureConfig(), FeatureConfig.class);

if (config.enabled && config.allowedRoles.contains(user.getRole())) {
    // Feature logic
}

getAllFlags()

Get all flags as a Map<String, Object>.

Map<String, Object> flags = client.getAllFlags();
// {"feature-a": true, "feature-b": false}

identify(userContext)

Set user context for targeting rules. Re-fetches flags with the new context.

client.identify(UserContext.builder()
    .id("user-123")
    .email("[email protected]")
    .attribute("plan", "enterprise")      // For "plan in pro,enterprise" rules
    .attribute("country", "US")           // For "country equals US" rules
    .attribute("company", "Acme Inc")     // For "company contains Acme" rules
    .attribute("app_version", "2.1.0")    // For "app_version semver_gt 2.0.0" rules
    .build());

refresh()

Force refresh flags from the server.

client.refresh();

Circuit Breaker

The SDK includes a circuit breaker that protects your app when Rollgate is unavailable. When open, it uses cached flag values.

// Get current state
String state = client.getCircuitState();
// "closed" | "open" | "half-open"

// Force reset (use with caution)
client.resetCircuit();

Spring Boot Integration

Integrate Rollgate as a Spring Bean for dependency injection across your application.

RollgateConfiguration.java
import io.rollgate.RollgateClient;
import io.rollgate.RollgateConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PreDestroy;
import java.time.Duration;

@Configuration
public class RollgateConfiguration {

    @Value("${rollgate.api-key}")
    private String apiKey;

    @Value("${rollgate.base-url:https://api.rollgate.io}")
    private String baseUrl;

    private RollgateClient client;

    @Bean
    public RollgateClient rollgateClient() {
        client = new RollgateClient(
            RollgateConfig.builder()
                .apiKey(apiKey)
                .baseUrl(baseUrl)
                .refreshInterval(Duration.ofSeconds(30))
                .build()
        );
        client.init();
        return client;
    }

    @PreDestroy
    public void cleanup() {
        if (client != null) {
            client.close();
        }
    }
}
FeatureService.java
import io.rollgate.RollgateClient;
import org.springframework.stereotype.Service;

@Service
public class FeatureService {

    private final RollgateClient rollgate;

    public FeatureService(RollgateClient rollgate) {
        this.rollgate = rollgate;
    }

    public boolean isFeatureEnabled(String featureKey) {
        return rollgate.isEnabled(featureKey, false);
    }
}
application.yml
rollgate:
  api-key: ${ROLLGATE_API_KEY}
  base-url: https://api.rollgate.io

Error Handling & Graceful Degradation

The SDK is designed to never throw exceptions during flag evaluation. If Rollgate is unavailable, flags return their default values. Use these patterns for production-grade reliability:

Graceful degradation
// Default values ensure your app works even without Rollgate
boolean showNewFeature = client.isEnabled("new-feature", false);
// Returns false if: flag doesn't exist, API down, circuit open

// Monitor degraded state
String circuitState = client.getCircuitState();
boolean isHealthy = "closed".equals(circuitState);

Initialization Error Handling

try {
    client.init();
    Map<String, Object> flags = client.getAllFlags();
    System.out.println("Rollgate initialized with " + flags.size() + " flags");
} catch (Exception e) {
    // Log but don't crash - SDK will use defaults
    System.err.println("Rollgate init failed: " + e.getMessage());
    System.err.println("Continuing with default flag values");
}

// Application starts regardless of Rollgate status

Feature-Critical Flags

For flags that control critical features, add explicit fallback logic:

public boolean shouldEnablePayments() {
    // Critical feature: payments
    boolean flagValue = client.isEnabled("payments-enabled", true); // Default: enabled
    String circuitState = client.getCircuitState();

    if ("open".equals(circuitState)) {
        // Circuit is open, we're using cached values
        // For payments, always enable as fail-safe
        System.err.println("Circuit open, enabling payments as fail-safe");
        return true;
    }

    return flagValue;
}