Skip to content

Commit

Permalink
feat: add flagd provider implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
toddbaert committed Aug 17, 2022
1 parent ad1940d commit d07e4e4
Show file tree
Hide file tree
Showing 12 changed files with 1,041 additions and 243 deletions.
8 changes: 8 additions & 0 deletions checkstyle-suppressions.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0"?>

<!DOCTYPE suppressions PUBLIC "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" "https://checkstyle.org/dtds/suppressions_1_2.dtd">

<suppressions>
<!-- don't check style of generated sources (GRPC bindings) -->
<suppress files="[\\/]generated-sources[\\/]" checks="[a-zA-Z0-9]*" />
</suppressions>
399 changes: 208 additions & 191 deletions checkstyle.xml

Large diffs are not rendered by default.

337 changes: 337 additions & 0 deletions eclipse-java-google-style.xml.bak

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
import dev.openfeature.javasdk.NoOpProvider;
import dev.openfeature.javasdk.OpenFeatureAPI;

/**
/**
* A placeholder.
*/
public class OpenTelemetryHook {
/**

/**
* Create a new OpenTelemetryHook instance.
*/
public OpenTelemetryHook() {
private OpenTelemetryHook() {
}

/**
* A test method...
* @return {boolean}
/**
* A test.
*
* @return boolean
*/
public static boolean test() {
OpenFeatureAPI.getInstance().setProvider(new NoOpProvider());
Expand Down
27 changes: 20 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
<version>0.0.3</version>
</dependency>

<!-- provided -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>

<!-- test -->
<dependency>
<groupId>org.mockito</groupId>
Expand Down Expand Up @@ -121,13 +129,13 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>8.31</version>
<version>10.3.2</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
Expand All @@ -138,7 +146,9 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<excludeRoots>${basedir}/target/generated-sources/</excludeRoots>
</configuration>
<executions>
<execution>
<id>run-pmd</id>
Expand Down Expand Up @@ -223,21 +233,24 @@
<version>3.4.0</version>
<configuration>
<failOnWarnings>true</failOnWarnings>
<excludePackageNames>dev.openfeature.flagd.grpc</excludePackageNames>
</configuration>
<executions>
<execution>
<id>vet-javadoc</id>
<phase>validate</phase>
<id>attach-javadocs</id>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
<execution>
<id>attach-javadocs</id>
<id>vet-javadoc</id>
<phase>verify</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>

</executions>
</plugin>
<!-- end source & javadoc -->
Expand All @@ -250,7 +263,7 @@
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<phase>install</phase>
<goals>
<goal>sign</goal>
</goals>
Expand Down
55 changes: 55 additions & 0 deletions providers/flagd/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,61 @@

<dependencies>
<!-- we inherent dev.openfeature.javasdk and the test dependencies from the parent pom -->

<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.48.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.48.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.48.1</version>
</dependency>
<dependency>
<!-- necessary for Java 9+ -->
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>

<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.21.1:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.48.1:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -1,29 +1,185 @@
package dev.openfeature.contrib.providers.flagd;

import dev.openfeature.javasdk.Client;
import dev.openfeature.javasdk.NoOpProvider;
import dev.openfeature.javasdk.OpenFeatureAPI;
import java.util.HashMap;
import java.util.Map;

/**
* A placeholder.
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.NotImplementedException;

import com.google.protobuf.Struct;
import com.google.protobuf.Value;

import dev.openfeature.javasdk.EvaluationContext;
import dev.openfeature.javasdk.FeatureProvider;
import dev.openfeature.javasdk.FlagEvaluationOptions;
import dev.openfeature.javasdk.Metadata;
import dev.openfeature.javasdk.ProviderEvaluation;
import dev.openfeature.javasdk.Reason;
import io.grpc.ManagedChannelBuilder;
import lombok.extern.slf4j.Slf4j;
import dev.openfeature.flagd.grpc.Schema.ResolveBooleanRequest;
import dev.openfeature.flagd.grpc.Schema.ResolveBooleanResponse;
import dev.openfeature.flagd.grpc.Schema.ResolveFloatRequest;
import dev.openfeature.flagd.grpc.Schema.ResolveFloatResponse;
import dev.openfeature.flagd.grpc.Schema.ResolveIntRequest;
import dev.openfeature.flagd.grpc.Schema.ResolveIntResponse;
import dev.openfeature.flagd.grpc.Schema.ResolveStringRequest;
import dev.openfeature.flagd.grpc.Schema.ResolveStringResponse;
import dev.openfeature.flagd.grpc.ServiceGrpc;
import dev.openfeature.flagd.grpc.ServiceGrpc.ServiceBlockingStub;

/**
* OpenFeature provider for flagd.
*/
public class FlagdProvider {
@Slf4j
public class FlagdProvider implements FeatureProvider {

private ServiceBlockingStub serviceStub;
static final String PROVIDER_NAME = "flagD Provider";

/**
/**
* Create a new FlagdProvider instance.
*
* @param protocol transport protocol, "http" or "https"
* @param host flagd host, defaults to localhost
* @param port flagd port, defaults to 8013
*/
public FlagdProvider(String protocol, String host, int port) {

this("https".equalsIgnoreCase(protocol)
? ServiceGrpc.newBlockingStub(ManagedChannelBuilder.forAddress(host, port)
.useTransportSecurity()
.build()) :
ServiceGrpc.newBlockingStub(ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.build()));
}

/**
* Create a new FlagdProvider instance.
*/
public FlagdProvider() {
this("http", "localhost", 8013);
}

/**
* A test method...
*
* @return {boolean}
/**
* Create a new FlagdProvider instance.
*
* @param serviceStub service stub instance to use
*/
public static boolean test() {
OpenFeatureAPI.getInstance().setProvider(new NoOpProvider());
Client client = OpenFeatureAPI.getInstance().getClient();
return client.getBooleanValue("test", true);
public FlagdProvider(ServiceBlockingStub serviceStub) {
this.serviceStub = serviceStub;
}

@Override
public Metadata getMetadata() {
return new Metadata() {
@Override
public String getName() {
return PROVIDER_NAME;
}
};
}

@Override
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue,
EvaluationContext ctx, FlagEvaluationOptions options) {

ResolveBooleanRequest request = ResolveBooleanRequest.newBuilder()
.setFlagKey(key)
.setContext(this.convertContext(ctx))
.build();
ResolveBooleanResponse r = this.serviceStub.resolveBoolean(request);
return ProviderEvaluation.<Boolean>builder()
.value(r.getValue())
.variant(r.getVariant())
.reason(this.mapReason(r.getReason()))
.build();
}

@Override
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue,
EvaluationContext ctx, FlagEvaluationOptions options) {
ResolveStringRequest request = ResolveStringRequest.newBuilder()
.setFlagKey(key)
.setContext(this.convertContext(ctx)).build();
ResolveStringResponse r = this.serviceStub.resolveString(request);
return ProviderEvaluation.<String>builder().value(r.getValue())
.variant(r.getVariant())
.reason(this.mapReason(r.getReason()))
.build();
}

@Override
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue,
EvaluationContext ctx, FlagEvaluationOptions options) {
ResolveFloatRequest request = ResolveFloatRequest.newBuilder()
.setFlagKey(key)
.setContext(this.convertContext(ctx))
.build();
ResolveFloatResponse r = this.serviceStub.resolveFloat(request);
return ProviderEvaluation.<Double>builder()
.value(r.getValue())
.variant(r.getVariant())
.reason(this.mapReason(r.getReason()))
.build();
}

@Override
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue,
EvaluationContext ctx, FlagEvaluationOptions options) {
ResolveIntRequest request = ResolveIntRequest.newBuilder()
.setFlagKey(key)
.setContext(this.convertContext(ctx))
.build();
ResolveIntResponse r = this.serviceStub.resolveInt(request);
return ProviderEvaluation.<Integer>builder()
.value((int) r.getValue())
.variant(r.getVariant())
.reason(this.mapReason(r.getReason()))
.build();
}

@Override
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue,
EvaluationContext ctx, FlagEvaluationOptions options) {
throw new NotImplementedException();
}

// Map FlagD reasons to Java SDK reasons.
private Reason mapReason(String flagDreason) {
if (!EnumUtils.isValidEnum(Reason.class, flagDreason)) {
// until we have "STATIC" in the spec and SDK, we map STATIC to DEFAULT
if ("STATIC".equals(flagDreason)) {
return Reason.DEFAULT;
} else {
return Reason.UNKNOWN;
}
} else {
return Reason.valueOf(flagDreason);
}
}

private Struct convertContext(EvaluationContext ctx) {
// TODO: structure attributes?
Map<String, Boolean> booleanAttributes = ctx.getBooleanAttributes();
Map<String, String> stringAttributes = ctx.getStringAttributes();
Map<String, Integer> intAttributes = ctx.getIntegerAttributes();
Map<String, Value> values = new HashMap<>();
booleanAttributes.keySet().stream().forEach((String key) -> values.put(key, Value
.newBuilder()
.setBoolValue(booleanAttributes.get(key))
.build()));
stringAttributes.keySet().stream().forEach((String key) -> values.put(key,
Value.newBuilder().setStringValue(stringAttributes
.get(key))
.build()));
intAttributes.keySet().stream().forEach((String key) -> values.put(key, Value
.newBuilder().setNumberValue(intAttributes.get(key))
.build()));
return Struct.newBuilder()
.putAllFields(values)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.openfeature.contrib.providers.flagd;

/**
* The commication style to yus.
*/
enum Service {
HTTP,
GRPC
}
Loading

0 comments on commit d07e4e4

Please sign in to comment.