Feature Flags for Java made easy

Related tags

toggle flipping feature
Overview

FF4J - Feature Flipping for Java

Build Status Backers on Open Collective Sponsors on Open Collective Maven Central Coverage Status

Codacy Badge Join the chat at https://gitter.im/ff4j/ff4j License Apache2 SourceSpy Dashboard

FF4j, is an implementation of the Feature Toggle pattern.

🤘 Features

  • Feature Toggle: Enable. and disable features at runtime - no deployments. In your code implement multiple paths protected by dynamic predicates (if/then/else).

  • Role-based Toggling: Enable features not only with flag values but also drive access with roles and groups (Canary Release). Different frameworks supported starting by Spring Security.

  • Strategy-based Toggling: Implement custom predicates (Strategy Pattern) to evaluate if a feature is enabled. Some are provided out of the box: White/Black lists ,Time based, Expression based. Connect external source like a Drools rule engine.

  • AOP-driven Toggling: Keep your code clean and readable: Avoid nested if statements but use annotations. Thanks to Spring AOP target implementation is pick at runtime, and thus driven by feature statuses.

  • Features Monitoring: For each features execution, ff4j evaluates the predicate therefore it's possible to collect and record events, metrics to compute nice dashboards or draw curves for features usage over time.

  • Audit Trail: Each action (create, update, delete, toggles) can be traced and saved in the audit trail for troubleshooting. With permissions management (AuthorizationManager) it's possible to identify users.

  • Web Console: Administrate FF4j (including features and properties) with the web UI. Packaged as a servlet in the library you will expose it in your backend applications. Almost 10 languages available.

  • Wide choice of Databases Our proud: we support 20+ databases technologies to store your features, properties and events. Same business model, multiple implementations. Thanks to extension points it's easy to build your own.

  • Spring Boot Starter Import ff4j-spring-boot-starter dependency in your microservices to get the web console and rest api working immediately. (To be used for the backend app. Now compliant with Spring Boot 2x: 👉 SAMPLES

  • REST Api Operate FF4j through a WEB API. This is the way to go to use ff4j with others languages, specially javascript frontends.(also: leverage on FeatureStoreHttp to avoid microservices to directly connect to the DB.

  • Properties (CMDB) Store not only feature statuses but any property value.. Create properties you can change at runtime . It is integrated with most used frameworks like Spring, Archaius, commons-config or Consul.

  • (Distributed) Cache Evaluating predicates may put pressure on DB (high hit ratio). ff4j provides local and distributed caches to help. (edit feature also evict cache). Leveraging JSR-107 it supports most of cache solutions.

  • Command Line Interface To automate things or because web ports may be blocked (you know, production...) you can work through SSH using our Command Line Interface (cli), our Shell #devOps. It will interact directly with storages.

  • JMX and MBeans Limited set of operations can be performed through JMX. ff4j exposes some Mbeans to read metrics or toggle features from external tools (Nagios...). Not all applications are web based.(batches, shell, standalone...)

More information can be found at ff4j.org or Reference Documentation in the wiki.

🔨 Getting Started

Check the Getting started here

👀 Screenshot

Home Page

Features

Monitoring

👤 Contributors

This project exists thanks to all the people who contribute. [Contribute].

Backers

Thank you to all our backers! 🙏 [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

Issues
  • Auditing not working when using FeatureStoreHttp

    Auditing not working when using FeatureStoreHttp

    Hi,

    In my webapplication (client) I am initializing the ff4j as HttpStore using restAPI like below

    ff4j = new FF4j();
    ff4j.setFeatureStore(new FeatureStoreHttp("http://localhost:9081/api/ff4j","FF4J","XXX")); ff4j.setPropertiesStore(new PropertyStoreHttp("http://localhost:9081/api/ff4j","FF4J","XXX"));

    In my admin console application/rest api springbootstarter project I am using the below config,

      FF4j ff4j = new FF4j();
      ff4j.setFeatureStore(new FeatureStoreSpringJdbc(dataSource));
        ff4j.setPropertiesStore(new PropertyStoreSpringJdbc(dataSource));
        ff4j.setEventRepository(new EventRepositorySpringJdbc(dataSource));
        ff4j.autoCreate(true);
        ff4j.audit(true);
       
      Whenever I hit my application URL it is invoking the API and getting the feature result whether it is enabled or not. But if I go to my admin console I don't see any audit details for that feature.
    

    But if I directly access those features inside admin console app, audit gets inserted/updated.

    Any help would be appreciated.

    bug ready-for-release 
    opened by abuinteam 17
  • FF4j Audit

    FF4j Audit

    Hi,

    I am working on adding audit features for ff4j. I have added the tables as explained in the below link.

    https://github.com/clun/ff4j/blob/master/ff4j-core/src/main/resources/schema-ddl.sql

    Can anybody tell me , how to do audit? I am using FeatureStoreSpringJdbc and enabled the audit.

    Thanks Vinod

    in-progress ready-for-release 
    opened by vinodhvp 15
  • FeatureStoreRedis shouldn't use Redis KEYS command

    FeatureStoreRedis shouldn't use Redis KEYS command

    As mentioned on several places (e.g. https://redis.io/commands/KEYS) you shouldn't ever run KEYS on production instances as it is blocking and potentially very slow.

    ready-for-release 
    opened by kutzi 14
  • FF4J Security problem

    FF4J Security problem

    Hi,

    I enabled spring security (basic user name and password) to access my admin console and rest api. All working good if I access my admin url or rest api in the browser or postman. Security is enabled and working fine.

    But in my application I am using the below configuration,,

    ff4j = new FF4j();
    ff4j.setFeatureStore(new FeatureStoreHttp("http://localhost:9081/api/ff4j","FF4J","XXX")); ff4j.setPropertiesStore(new PropertyStoreHttp("http://localhost:9081/api/ff4j","FF4J","XXX"));

    But I am getting the below error

    javax.servlet.ServletException: java.lang.IllegalArgumentException: Cannot parse json as Feature HTTP Status 401 - Full authentication is required to access this resource

    at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:286)
    at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
    at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:449)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:575)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
    at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1274)
    at [internal classes]
    

    Caused by: java.lang.IllegalArgumentException: Cannot parse json as Feature HTTP Status 401 - Full authentication is required to access this resource

    My username and password are correct

    bug wontfix 
    opened by abuinteam 13
  • Couchbase support

    Couchbase support

    Hi,

    Is there any plan to add couchbase support for feature store? Or if not, would it be too difficult to base something off of the mongo store library?

    Cheers, Jack

    evolution ready-for-release 
    opened by jackpf 12
  • Incompatibility between ff4j-store-mongodb-v3 and Spring boot 2.3.x

    Incompatibility between ff4j-store-mongodb-v3 and Spring boot 2.3.x

    Hello everyone!

    I am working on Spring Boot version migration to 2.3.x but I realized that I am not being able to use ff4j-store-mongodb-v3 and ff4j 1.8.9 because the class FeatureStoreMongo imports MongoClient from package com.mongodb instead com.mongodb.client used by Spring Data new version.

    My pom is:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.progtiago</groupId>
      <artifactId>mp-image</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.3.RELEASE</version>
        <relativePath/>
      </parent>
    
      <properties>
        <java.version>1.8</java.version>
        <spring.cloud.kubernetes.version>1.0.0.RC2</spring.cloud.kubernetes.version>
        <spring-cloud-starter-openfeign.version>2.1.5.RELEASE</spring-cloud-starter-openfeign.version>
        <springfox.swagger.version>2.9.2</springfox.swagger.version>
        <ff4j.version>1.8.9</ff4j.version>
        <commons.io.version>2.6</commons.io.version>
        <commons.net.version>3.6</commons.net.version>
        <commons-lang.version>3.9</commons-lang.version>
        <aws-java-sdk>1.11.517</aws-java-sdk>
        <fixture-factory.version>3.1.0</fixture-factory.version>
        <nal-logging.version>1.7</nal-logging.version>
        <newrelic-api.version>4.11.0</newrelic-api.version>
        <commons-collections4.version>4.2</commons-collections4.version>
        <twelvemonkeys-imageio.version>3.5</twelvemonkeys-imageio.version>
        <imgscalr-lib.version>4.2</imgscalr-lib.version>
        <pitest-plugin.version>1.4.6</pitest-plugin.version>
        <powermock.version>2.0.0</powermock.version>
        <mockito-all.version>1.10.19</mockito-all.version>
        <!-- Container Tests -->
        <testcontainers.version>1.12.4</testcontainers.version>
        <mockserver.version>1.12.0</mockserver.version>
        <mockserver-client-java.version>5.6.1</mockserver-client-java.version>
    
        <!-- Sonar -->
        <sonar.sources>src/main/java</sonar.sources>
        <sonar.tests>src/test/</sonar.tests>
        <sonar.sourceEncoding>UTF-8</sonar.sourceEncoding>
        <sonar.jacoco.reportPath>target/jacoco.exec</sonar.jacoco.reportPath>
        <sonar.java.binaries>target/classes</sonar.java.binaries>
    
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-kubernetes</artifactId>
          <version>${spring.cloud.kubernetes.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-kubernetes-config</artifactId>
          <version>${spring.cloud.kubernetes.version}</version>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <exclusions>
            <exclusion>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
          </exclusions>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-openfeign</artifactId>
          <version>${spring-cloud-starter-openfeign.version}</version>
        </dependency>
    
        <!-- Image Scaling -->
        <dependency>
          <groupId>org.imgscalr</groupId>
          <artifactId>imgscalr-lib</artifactId>
          <version>${imgscalr-lib.version}</version>
        </dependency>
    
        <dependency>
          <groupId>com.twelvemonkeys.imageio</groupId>
          <artifactId>imageio-jpeg</artifactId>
          <version>${twelvemonkeys-imageio.version}</version>
        </dependency>
    
        <!-- Lombok -->
        <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>${lombok.version}</version>
          <scope>provided</scope>
        </dependency>
    
        <!-- Springfox Swagger -->
        <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger2</artifactId>
          <version>${springfox.swagger.version}</version>
        </dependency>
        <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger-ui</artifactId>
          <version>${springfox.swagger.version}</version>
        </dependency>
    
        <!-- Ff4j -->
        <dependency>
          <groupId>org.ff4j</groupId>
          <artifactId>ff4j-core</artifactId>
          <version>${ff4j.version}</version>
        </dependency>
        <dependency>
          <groupId>org.ff4j</groupId>
          <artifactId>ff4j-web</artifactId>
          <version>${ff4j.version}</version>
          <exclusions>
            <exclusion>
              <groupId>org.thymeleaf</groupId>
              <artifactId>thymeleaf</artifactId>
            </exclusion>
          </exclusions>
        </dependency>
        <dependency>
          <groupId>org.ff4j</groupId>
          <artifactId>ff4j-store-mongodb-v3</artifactId>
          <version>${ff4j.version}</version>
        </dependency>
        <dependency>
          <groupId>org.ff4j</groupId>
          <artifactId>ff4j-aop</artifactId>
          <version>${ff4j.version}</version>
        </dependency>
    
        <!-- NewRelic -->
        <dependency>
          <groupId>com.newrelic.agent.java</groupId>
          <artifactId>newrelic-api</artifactId>
          <version>${newrelic-api.version}</version>
        </dependency>
    
        <dependency>
          <groupId>com.fasterxml.jackson.datatype</groupId>
          <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>
    
        <!-- Aws Sdk -->
        <dependency>
          <groupId>com.amazonaws</groupId>
          <artifactId>aws-java-sdk</artifactId>
          <version>${aws-java-sdk}</version>
        </dependency>
    
        <!-- Commons -->
        <dependency>
          <groupId>commons-io</groupId>
          <artifactId>commons-io</artifactId>
          <version>${commons.io.version}</version>
        </dependency>
    
        <dependency>
          <groupId>commons-net</groupId>
          <artifactId>commons-net</artifactId>
          <version>${commons.net.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-collections4</artifactId>
          <version>${commons-collections4.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-lang3</artifactId>
          <version>${commons-lang.version}</version>
        </dependency>
    
        <!-- Jolokia -->
        <dependency>
          <groupId>org.jolokia</groupId>
          <artifactId>jolokia-spring</artifactId>
          <classifier>plugin</classifier>
          <version>${jolokia.version}</version>
        </dependency>
    
        <!-- Test -->
        <dependency>
          <groupId>br.com.six2six</groupId>
          <artifactId>fixture-factory</artifactId>
          <version>${fixture-factory.version}</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>org.powermock</groupId>
          <artifactId>powermock-reflect</artifactId>
          <version>${powermock.version}</version>
          <scope>test</scope>
        </dependency>
    
        <!--  Test container  -->
        <dependency>
          <groupId>org.testcontainers</groupId>
          <artifactId>testcontainers</artifactId>
          <version>${testcontainers.version}</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.mockito</groupId>
          <artifactId>mockito-all</artifactId>
          <version>${mockito-all.version}</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.testcontainers</groupId>
          <artifactId>mockserver</artifactId>
          <version>${mockserver.version}</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.mock-server</groupId>
          <artifactId>mockserver-client-java</artifactId>
          <version>${mockserver-client-java.version}</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
      
      <repositories>
    
      </repositories>
    </project>
    

    My FF4J Config class is:

    package com.progtiago.image.configurations.ff4j;
    
    import com.mongodb.client.MongoClient;
    import com.mongodb.client.MongoDatabase;
    import java.util.Arrays;
    import org.ff4j.FF4j;
    import org.ff4j.core.Feature;
    import org.ff4j.core.FeatureStore;
    import org.ff4j.mongo.store.FeatureStoreMongo;
    import org.ff4j.web.ApiConfig;
    import org.ff4j.web.embedded.ConsoleServlet;
    import org.springframework.boot.web.servlet.ServletRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.mongodb.core.MongoTemplate;
    
    @Configuration
    @ComponentScan(basePackages = "org.ff4j.aop")
    public class FF4JConfiguration {
      private static final String DEFAULT_CONSOLE = "/ff4j-console/*";
      private static final String COLLECTION_NAME = "ff4j-features";
    
      @Bean
      public FF4j getFF4j(final FeatureStore featureStore) {
        final FF4j ff4j = new FF4j();
        ff4j.disableAlterBeanThrowInvocationTargetException();
        ff4j.setFeatureStore(featureStore);
        Arrays.stream(Features.values())
            .filter(feature -> !ff4j.getFeatureStore().exist(feature.getKey()))
            .forEach(feature -> createFeature(ff4j, feature));
        return ff4j;
      }
    
      @Bean
      public ConsoleServlet getFF4jServlet(final FF4j ff4j) {
        final ConsoleServlet ff4jConsoleServlet = new ConsoleServlet();
        ff4jConsoleServlet.setFf4j(ff4j);
        return ff4jConsoleServlet;
      }
    
      @Bean
      public ApiConfig getApiConfig(final FF4j ff4j) {
        final ApiConfig apiConfig = new ApiConfig();
        apiConfig.setAuthenticate(false);
        apiConfig.setAutorize(false);
        apiConfig.setFF4j(ff4j);
        return apiConfig;
      }
    
      @Bean
      public ServletRegistrationBean servletRegistrationBeanToFF4j(final FF4j ff4j) {
        return new ServletRegistrationBean(getFF4jServlet(ff4j), DEFAULT_CONSOLE);
      }
    
      @Bean
      public FeatureStore featureStore(
          final MongoClient mongoClient, final MongoTemplate mongoTemplate) {
        final MongoDatabase mongoDatabase = mongoClient.getDatabase(mongoTemplate.getDb().getName());
        return new FeatureStoreMongo(mongoDatabase, COLLECTION_NAME);
      }
    
      private void createFeature(final FF4j ff4j, final Features feature) {
        final Feature fp = new Feature(feature.getKey(), feature.isDefaultValue());
        fp.setDescription(feature.getDescription());
        fp.setGroup(feature.getGroup());
        ff4j.createFeature(fp);
      }
    }
    

    When I try compile, the error is this:

    ff4j/FF4JConfiguration.java:[60,12] cannot access com.mongodb.MongoClient [ERROR] class file for com.mongodb.MongoClient not found

    It is because, as I have said, the class FeatureStoreMongo imports MongoClient from com.mongodb instead of com.mongodb.client.

    My conclusion is that the ff4j-store-mongodb-v3 is incompatible with Spring Data 2.3.x. I am right or somebody has another opinion?

    Thanks so much!

    Technical Debt evolution ready-for-release 
    opened by progtiago 11
  • Thymeleaf exception with new FF4jDispatcherServlet

    Thymeleaf exception with new FF4jDispatcherServlet

    Hi,

    I'm trying to use the new dispatcher servlet registered as a Spring boot bean, however when trying to access the console via browser, i get the following exception:

    2017-05-25 12:46:53.802 ERROR 38458 --- [io-56789-exec-1] o.s.boot.web.support.ErrorPageFilter     : Forwarding to error page from request [/ff4j-console] due to exception [Exception evaluating OGNL expression: "TITLE" (header:33)]
    
    org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating OGNL expression: "TITLE" (header:33)
    	at org.thymeleaf.standard.expression.OgnlVariableExpressionEvaluator.evaluate(OgnlVariableExpressionEvaluator.java:128) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.standard.expression.VariableExpression.executeVariable(VariableExpression.java:154) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:59) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:103) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.standard.expression.AdditionExpression.executeAddition(AdditionExpression.java:92) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.standard.expression.ComplexExpression.executeComplex(ComplexExpression.java:55) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:107) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:133) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:120) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.standard.processor.attr.AbstractStandardTextChildModifierAttrProcessor.getText(AbstractStandardTextChildModifierAttrProcessor.java:68) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.processor.attr.AbstractTextChildModifierAttrProcessor.getModifiedChildren(AbstractTextChildModifierAttrProcessor.java:59) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.processor.attr.AbstractChildrenModifierAttrProcessor.processAttribute(AbstractChildrenModifierAttrProcessor.java:59) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.processor.attr.AbstractAttrProcessor.doProcess(AbstractAttrProcessor.java:87) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:212) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.Node.applyNextProcessor(Node.java:1017) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.Node.processNode(Node.java:972) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.Node.processNode(Node.java:990) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.dom.Document.process(Document.java:93) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1155) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:955) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	at org.ff4j.web.controller.AbstractController.get(AbstractController.java:187) ~[ff4j-web-1.6.4.jar:1.6.4]
    	at org.ff4j.web.FF4jDispatcherServlet.doGet(FF4jDispatcherServlet.java:65) ~[ff4j-web-1.6.4.jar:1.6.4]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:621) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at com.rentalcars.email.subscription.web.filter.AuthenticationFilter.doFilterInternal(AuthenticationFilter.java:29) ~[AuthenticationFilter.class:na]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) ~[spring-security-web-4.1.3.RELEASE.jar:4.1.3.RELEASE]
    	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:119) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
    	at org.springframework.boot.web.support.ErrorPageFilter.access$000(ErrorPageFilter.java:61) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
    	at org.springframework.boot.web.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:94) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.3.3.RELEASE.jar:4.3.3.RELEASE]
    	at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:112) [spring-boot-1.4.1.RELEASE.jar:1.4.1.RELEASE]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310) [tomcat-embed-core-7.0.47.jar:7.0.47]
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_101]
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_101]
    	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_101]
    Caused by: java.lang.RuntimeException: MemberAccess implementation must be provided!
    	at ognl.OgnlContext.<init>(OgnlContext.java:136) ~[ognl-3.2.2.jar:na]
    	at ognl.Ognl.addDefaultContext(Ognl.java:322) ~[ognl-3.2.2.jar:na]
    	at ognl.Ognl.addDefaultContext(Ognl.java:252) ~[ognl-3.2.2.jar:na]
    	at ognl.Ognl.getValue(Ognl.java:484) ~[ognl-3.2.2.jar:na]
    	at ognl.Ognl.getValue(Ognl.java:455) ~[ognl-3.2.2.jar:na]
    	at org.thymeleaf.standard.expression.OgnlVariableExpressionEvaluator.evaluate(OgnlVariableExpressionEvaluator.java:114) ~[thymeleaf-2.1.5.RELEASE.jar:2.1.5.RELEASE]
    	... 94 common frames omitted
    

    I have the following dependencies:

    <dependency>
        <groupId>org.ff4j</groupId>
        <artifactId>ff4j-core</artifactId>
        <version>1.6.4</version>
    </dependency>
    <dependency>
        <groupId>org.ff4j</groupId>
        <artifactId>ff4j-web</artifactId>
        <version>1.6.4</version>
    </dependency>
    <dependency>
        <groupId>org.unbescape</groupId>
        <artifactId>unbescape</artifactId>
        <version>1.1.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>ognl</groupId>
        <artifactId>ognl</artifactId>
        <version>3.2.2</version>
    </dependency>
    

    And have the servlet registered like so:

    @Bean
    @ConditionalOnMissingBean
    public FF4jDispatcherServlet getFF4jServlet(FF4j ff4j) {
        FF4jDispatcherServlet ff4jDispatcherServlet = new FF4jDispatcherServlet();
        ff4jDispatcherServlet.setFf4j(ff4j);
        return ff4jDispatcherServlet;
    }
    
    @Bean
    public ServletRegistrationBean servletRegistrationBean(FF4jServlet ff4jServlet) {
        return new ServletRegistrationBean(ff4jServlet, "/ff4j-console");
    }
    

    Is there something I'm missing?

    Cheers

    answered question 
    opened by jackpf 11
  • `EnableFF4J` vs. auto-configuration

    `EnableFF4J` vs. auto-configuration

    I had a quick look to the new Spring Boot auto-configuration and found an issue. The current code is mixing two totally different concepts: on one hand there is this @EnableFF4J annotation that should be added to the application to enable support. On the other hand it imports a @Configuration that pretends to be an auto-configuration but isn't.

    Auto-configuration classes are loaded in a particular way in Spring Boot. Typically, if you use @ConditionalOnMissingBean, we make sure that all the user's config has been parsed first so that we have a chance to properly detect if a bean of a certain type is present. Since the current code is a "simple" configuration, you have no guarantee that it is the case right now.

    Is it reasonable to enable FF4J automatically if it is present on the classpah? (I would assume so). Then remove the @EnableFF4J annotation altogether and switch the current class to auto-configuration. If that's not reasonable, remove the @ConditionalOnMissingBean annotation. I can help or provide a PR if that makes things easier.

    ready-for-release 
    opened by snicoll 10
  •  Incompatibility with version 4 of MongoDB

    Incompatibility with version 4 of MongoDB

    Hello guys, how are you?

    So, I found an error when I try to persist ff4j in version 4 on mongodb. When I use ff4j-store-mongodb-v3:1.8.10 on my project with mongodb-driver-sync:4.0.5, the application failed to start.

    ***************************
    APPLICATION FAILED TO START
    ***************************
    Description:
    An attempt was made to call a method that does not exist. The attempt was made from the following location:
        org.ff4j.mongo.store.FeatureStoreMongo.create(FeatureStoreMongo.java:227)
    The following method did not exist:
        'void com.mongodb.client.MongoCollection.insertOne(java.lang.Object)'
    The method's class, com.mongodb.client.MongoCollection, is available from the following locations:
        jar:file:/home/danielwisky/.m2/repository/org/mongodb/mongodb-driver-sync/4.0.5/mongodb-driver-sync-4.0.5.jar!/com/mongodb/client/MongoCollection.class
    The class hierarchy was loaded from the following locations:
        com.mongodb.client.MongoCollection: file:/home/danielwisky/.m2/repository/org/mongodb/mongodb-driver-sync/4.0.5/mongodb-driver-sync-4.0.5.jar
    Action:
    Correct the classpath of your application so that it contains a single, compatible version of com.mongodb.client.MongoCollection
    Disconnected from the target VM, address: '127.0.0.1:33507', transport: 'socket'
    Process finished with exit code 1
    

    I managed to fix this error compiling the project ff4j-store-mongodb-v3 with version 4.x from mongodb-driver.

    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongodb-driver-sync</artifactId>
        <version>4.0.5</version><!--$NO-MVN-MAN-VER$-->
        <scope>provided</scope> <!-- provided to NOT FIX the version -->
    </dependency>
    

    I'd like your opinion about this fix. I don't know if this change may be done in the same project, ff4j-store-mongodb-v3, or we could create a new one, ff4j-store-mongodb-v4. What dou you guys think about it?

    I can help with this changes, if you guys want it.

    Thank you, very much.

    ready-for-release 
    opened by danielwisky 10
  • Is it possible to connect via some kind of SDK

    Is it possible to connect via some kind of SDK

    I am trying to establish a microservices environment with almost 100 microservices using ff4j for my enterprise. I am planning to use PostgreSQL as feature storage. I am planning to have only single management console application.

    As far as I see, all microservices HAVE TO connect to the same PostgreSQL database to read features.

    "Connecting the same database" breaks the microservices architecture. Is there any better way to do that? Should all my services connect to management service via REST API that ff4j already provides? Any better way?

    answered question 
    opened by ealparslan 9
  • Enquiry :  Is it possible to use this library for values required at application startup for a plain java application

    Enquiry : Is it possible to use this library for values required at application startup for a plain java application

    Hello Team,

    I am exploring this library to be used for a Toggling feature use case. Is it possible to use this with a plain java application to store values required at the application start up.

    opened by anilkumarmalipatil 1
  • Admin console - styling

    Admin console - styling

    Hi everybody,

    is is possible to change the styling of the administration console through some config properties, especially the font and colors?

    If not, it would be nice to have at least a basic styling ability.

    Cheery, Matti

    opened by mojo2012 2
  • Push Notification to server on property update

    Push Notification to server on property update

    Do we have any feature in ff4j where value update notification can be pushed to the application server as I am doing cache on the backend also to save network call?

    opened by bhuvnesh91 1
  • Postgre Started for Spring Boot 2 is throwing bad grammer error

    Postgre Started for Spring Boot 2 is throwing bad grammer error

    PreparedStatementCallback; bad SQL grammar [SELECT COUNT(FEAT_UID) FROM FF4J_FEATURES WHERE FEAT_UID = ?]; nested exception is org.postgresql.util.PSQLException: ERROR: relation "ff4j_features" does not exist Position: 29

    Using posgre vesrion 12.7 with spring boot 2.. any ideas?

    opened by agenttuy 3
  • Support for clients in other languages?

    Support for clients in other languages?

    Is there support for .Net or Node.js clients? If not would there be interest in pull requests to support those?

    opened by checketts 3
  • server side caching for feature store using FeatureCacheProviderEhCache

    server side caching for feature store using FeatureCacheProviderEhCache

    I am using ff4j-spring-boot-starter with f4j-store-springjdbc to setup my ff4j server. All my other microservices use the endpoints given by ff4j to access this feature store and the response is returned in JSON.

    Since the data does not change that often and we are trying to save unnecessary database calls, I am trying to cache my feature store on the server. Also, if the feature flag DB is down (for refresh/maintenance) we still want the other services to successfully start-up using these values from the cache.

    We imported ff4j-store-ehcache in our pom.xml

            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.1.RELEASE</version>
        </parent>
    
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Hoxton.RC2</spring-cloud.version>
            <ff4j.version>1.8.7</ff4j.version>
            <odbc.version>19.6.0.0.0</odbc.version>
        </properties>
        <dependency>
                <groupId>org.ff4j</groupId>
                <artifactId>ff4j-spring-boot-starter</artifactId>
                <version>${ff4j.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.ff4j</groupId>
                <artifactId>ff4j-store-springjdbc</artifactId>
                <version>${ff4j.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.ff4j</groupId>
                <artifactId>ff4j-web</artifactId>
                <version>${ff4j.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.ff4j</groupId>
                <artifactId>ff4j-store-ehcache</artifactId>
                <version>${ff4j.version}</version>
            </dependency>
    		<dependency>
    			<groupId>org.ff4j</groupId>
    			<artifactId>ff4j-webapi-jersey2x</artifactId>
    			<version>1.8.11</version>
    		</dependency>
            <!-- FF4J dependencies - end -->
    

    Our FeatureCacheProviderEhCache implementation looks like this in FF4jConfig.java looks like this.

    @ConditionalOnClass({​​​​ ConsoleServlet.class, FF4jDispatcherServlet.class }​​​​)
    public class Ff4jConfig extends SpringBootServletInitializer {​​​​
    
        @Autowired
        private DataSource dataSource;
    
        @Bean
        public ServletRegistrationBean<FF4jDispatcherServlet> ff4jDispatcherServletRegistrationBean(
                FF4jDispatcherServlet ff4jDispatcherServlet) {​​​​
            ServletRegistrationBean<FF4jDispatcherServlet> bean = new ServletRegistrationBean<FF4jDispatcherServlet>(
                    ff4jDispatcherServlet, "/web-console/*");
            bean.setName("ff4j-console");
            bean.setLoadOnStartup(1);
            return bean;
        }​​​​
    
        @Bean
        @ConditionalOnMissingBean
        public FF4jDispatcherServlet getFF4jDispatcherServlet() {​​​​
            FF4jDispatcherServlet ff4jConsoleServlet = new FF4jDispatcherServlet();
            ff4jConsoleServlet.setFf4j(getFF4j());
            return ff4jConsoleServlet;
        }​​​​
    
        @Bean
        public FF4j getFF4j() {​​​​
            FF4j ff4j = new FF4j();
            FF4JCacheManager cacheManager = new FeatureCacheProviderEhCache();
            ff4j.setPropertiesStore(new PropertyStoreSpringJdbc(dataSource));
            ff4j.setFeatureStore(new FeatureStoreSpringJdbc(dataSource));
            ff4j.setEventRepository(new EventRepositorySpringJdbc(dataSource));
            ff4j.cache(cacheManager);
            
    
            // Enable audit mode
            ff4j.audit(true);
    
            return ff4j;
        }​​​​
    
    }​​​​
    

    WebConsole reflects the database changes as soon as they are commit and it does not seem like the cache is being hit or that the cache is storing any of the data in it.

    I want to be able to use this cache without going to database for every single lookup.

    We also tried using InMemoryCacheManager as an alternate to FeatureCacheProviderEhCache, but same results. We do see the clear cache button on our web-console in both the implementations.

    Also, is there a better way for me to test if my api calls are actually getting data from cache and not from db, without having to shutdown the db?

    opened by tushitj 0
  • Do not create session in web console

    Do not create session in web console

    I think that forcing session creation here is unnecessary. When combined with spring secruity, session creation in some cases it will render all links with ;jsessionid=... and spring will reject those links as security breach (The request was rejected because the URL contained a potentially malicious String ";")

    You can obtain servletContext by request.getServletContext() call

    https://github.com/ff4j/ff4j/blob/a31cb8caf8b8c4874fcd6bb64893f4f50919af3c/ff4j-web/src/main/java/org/ff4j/web/controller/AbstractController.java#L159 https://github.com/ff4j/ff4j/blob/a31cb8caf8b8c4874fcd6bb64893f4f50919af3c/ff4j-web/src/main/java/org/ff4j/web/controller/AbstractController.java#L204

    opened by bjab 0
  • Unable to use ff4j web console in quarkus application: Caused by: java.lang.ClassNotFoundException: org.acme.MyFF4jProvider

    Unable to use ff4j web console in quarkus application: Caused by: java.lang.ClassNotFoundException: org.acme.MyFF4jProvider

    If I try to use ff4j web console in a quarkus application, I get following Exception on startup of the FF4jDispatcherServlet that the class of my FF4jProvider is not known:

    Caused by: java.lang.ClassNotFoundException: org.acme.MyFF4jProvider
            at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
            at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
            at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
            at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:428)
            at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:378)
            at java.base/java.lang.Class.forName0(Native Method)
            at java.base/java.lang.Class.forName(Class.java:315)
            at org.ff4j.web.FF4jServlet.initializeFF4J(FF4jServlet.java:152)
            ... 29 more
    

    The reason is this line: https://github.com/ff4j/ff4j/blob/f3c07b49deabd04caef8b0f3a491ab3ae514ca36/ff4j-web/src/main/java/org/ff4j/web/FF4jServlet.java#L152

    As described here: "Class.forName() without a CL is often problematic."

    Please change this line to use the current classlaoder: Class<?> c = Thread.currentThread().getContextClassLoader().loadClass(className);

    opened by franden 4
  • Unable to use FF4jProvider for web console as documented here: https://github.com/ff4j/ff4j/wiki/Web-Concepts#web-console

    Unable to use FF4jProvider for web console as documented here: https://github.com/ff4j/ff4j/wiki/Web-Concepts#web-console

    I am trying to use ff4j web console in our project. therefore I checked documentation and some examples (https://github.com/ff4j/ff4j-samples/tree/master/webapp-jetty/ff4j-sample-web), but unfortunately I get an exception if the FF4jDispatcherServlet tries to get Instance of my FF4jProvider.

    Caused by: java.lang.NoSuchMethodException: org.ff4j.sample.SimpleFF4jProvider.getInstance()
        at java.lang.Class.getMethod (Class.java:2108)
        at org.ff4j.web.FF4jServlet.initializeFF4J (FF4jServlet.java:153)
        at org.ff4j.web.FF4jServlet.init (FF4jServlet.java:112)
    ...
    

    The cause of this issue is this commit: https://github.com/ff4j/ff4j/commit/d9584eb7aa14b50dbcdf6826e5587e4e87915ede#diff-ae79b5b13181ccd929d0b086cf0b4b5e6a6fff8c9987908186e1dafc076f4b65

    This line must be fixed: https://github.com/ff4j/ff4j/blob/f3c07b49deabd04caef8b0f3a491ab3ae514ca36/ff4j-web/src/main/java/org/ff4j/web/FF4jServlet.java#L153

    opened by franden 0
Releases(1.8.11)
  • 1.8.7(Jun 28, 2020)

  • 1.8.6(May 10, 2020)

    Fixes:

    • Delegate isAllowed to AuthorizationManager (#386)
    • Remove event duplication in AOP (#409)
    • Fix Redis repositories keys and audit (#399)
    • Fix Date Picker in Web Console (#338)

    Evolutions

    • Adding Audit for MongoDB and AWS DocumentDB (#359)
    • Support security for Apache Shiro (#393)
    • (beta) Allow inheritance in Flipping Execution Context (#354)
    • Adding Arabic language in the console
    • Fixing encoding issues in the console

    Working Sample Codes

    Source code(tar.gz)
    Source code(zip)
  • 1.8.5(May 2, 2020)

    Release Note:

     - Fixed FF4j version null leading to invalid REST API
     - Move Web Console to Thymeleaf3 (templates, modals, resolver) - full compliant Spring Boot 2
     - Integration of latest DB in docs (arrango, aws, dynamo, couchdb)
     - Reimplementation of store-elastic compliant with Elastic 6+
     - Provide dashboard for kibana
     - Fixing AOP issue
     - Fixing language issues and minor UI improvements
    
    Source code(tar.gz)
    Source code(zip)
  • 1.7.1(Jan 24, 2018)

    #285 AlterBean is not required anymore, will do nothing and return null #286 Enable external classLoader for FlippingStrategy #284 Fixed with 286

    Source code(tar.gz)
    Source code(zip)
  • 1.7(Dec 4, 2017)

    Evolutions #265 New FeatureStores and PropertyStores : Couchbase

    Bug Fixes #238 : ff4j_audit table column size issue #239 : FlippingStrategy implementations as static nested classes can't be instantiated #241 : Dependency Apache Standard Taglibs 1.1.2 - Arbitrary code execution #249 : Elastic store retrives only 10 feature max even where there are more than 10 features #250 : SpringFox docket group name is default - causing conflicts with other modules #255 : JdbcFeatureStore update() executes commits regardless of autocommit #262 : SQL exception when updating feature with JdbcFeature store #264 : FF4J Security problem #271 : Ordering Exception Handler in SpringBoot #267 : Auditing not working when using FeatureStoreHttp #268 : Feature auto create not working using jsp tag library - multiple issues

    Source code(tar.gz)
    Source code(zip)
  • 1.6.5(Jun 24, 2017)

    Release Note:

    Bug Fix:

    • #232 - Upgrade Spring/LogBack
    • #230 - Remove semi colon in request
    • #225 - Jdbc FeatureStore with new commits
    • #229 - @Property is not autowired anytime

    News :

    • New Store HBASE
    • New store Consul
    • New Store Ignite
    • New constructor in MongoDB
    • Enhancements to enable the jhipster-generator-ff4j
    Source code(tar.gz)
    Source code(zip)
  • 1.6.4(Apr 30, 2017)

    This release provides bug fixing for webConsole, cache management and evolutions for redis stores and Spring JDBC Stores.

    IMPORTANT: BREAKING CHANGES in Redis stores, please be sure to execute the migration script before updating the library.

    Evolutions:

    #177 : (PR #222 [email protected])

    • As the KEYS operations in Redis is slow (full scan in O(n) ) we had to create a new key named FF4J_FEATURE_MAP that stands as a dictionary to access others. To init this new key please execute the following SCRIPT
    • Provides the implementation of EventRepository to store audit in REDIS.

    #217 : Provides the implementation of EventRepository to store audit in any RDBMS with Spring JDBC.

    Bugs and fixes

    #199 : Correction in web console when editing custom properties of a Feature.

    #218 : Solve issues when clearing cache if audit is enabled

    #221 : Invalid UI images in some cases (changing cache manager from In-Memory to InMemory)

    #223 : Is backing store failed the cache is immediately cleared where it shouldn'the

    Source code(tar.gz)
    Source code(zip)
  • 1.6(Oct 23, 2016)

    Big release with great evolutions. It should be the last released to support Java1.6. We will now move to FF4J 2.x with Java8.

    Evolutions: #116 : Brand new stores Cassandra (features, properties, events) #116 : Brand new stores Elastic (features, properties) #118 : Brand new nice and clean console, see demo.ff4j.org #119 : Brand new stores for properties with Archaius and CommonsConfiguration, ff4j may become a UI for Archaius (and Eureka soon) #75 : Enable a worker to update your local cache periodically (and then never invoke underlying database) #159 : You can now create schemas from console and through the API (create tables)

    Bugs and fixes #102 : Simplify AOP flipping with an Method Interceptor, should resolve problems related to cglib proxies or ASM #158 : Correct exception catching in spring-boot #155 : Remove unnecessary synchronized and get back with heavy performance #133 : Correct ex web console (ko in 1.5.1) and make it ok with JDK1.6+.. but is deprecated now #153 : Related to #102 #131 : Use the feature advisor class name in logs

    Source code(tar.gz)
    Source code(zip)
  • 1.5(Apr 26, 2016)

    Release Notes

    New :

    • Spring Boot Support with starter and services (by @paul58914080)
    • Command line Interface to toggle features through SSH (ops oriented)
    • #111 : Metrics console in core?
    • #104 : DataBase Schema Configuration
    • #99 : Add support for AUTH in ff4j-store-redis
    • #89 : Embedded administration console - check return codes
    • #76 : Implement Audit trail for Changes to feature flags

    Fixed Issues:

    • #103 : Alter bean don't return my exception (by @FelipeAdorno)

    Other changes

    • Renaming Annotation to @FF4jProperty and @FF4JFeature for autowiring
    Source code(tar.gz)
    Source code(zip)
  • 1.3.2(Aug 25, 2015)

Simple API, Complex Emails (JavaMail smtp wrapper)

Simple Java Mail Simple Java Mail is the simplest to use lightweight mailing library for Java, while being able to send complex emails including CLI s

Benny Bottema 857 Jun 9, 2021
Feature Flags for Java made easy

✨ ✨ ✨ FF4J - Feature Flipping for Java ✨ ✨ ✨ FF4j, is an implementation of the Feature Toggle pattern. ?? Features Feature Toggle: Enable. and disable

FF4j 934 Jun 16, 2021
Detect uses of legacy Java APIs

Modernizer Maven Plugin Modernizer Maven Plugin detects uses of legacy APIs which modern Java versions supersede. These modern APIs are often more per

Andrew Gaul 242 Jun 7, 2021
Ultra-fast SQL-like queries on Java collections

CQEngine - Collection Query Engine CQEngine – Collection Query Engine – is a high-performance Java collection which can be searched with SQL-like quer

Niall Gallagher 1.3k Jun 13, 2021
Sketchware Pro's sources, in Java.

Sketchware Pro This is for everyone who wants to contribute to Sketchware Pro's development. There are few things that must be taken into consideratio

Javkhlan K. 58 Jun 12, 2021
The easiest way to integrate Maven into your project!

Maven Wrapper Ongoing Migration to Apache Maven The project codebase has been accepted to be included in the upstream Apache Maven project itself. Cur

null 1.5k Jun 15, 2021
Make Slack and Facebook Bots in Java.

JBot Make bots in Java. JBot is a java framework (inspired by Howdyai's Botkit) to make Slack and Facebook bots in minutes. It provides all the boiler

Ram 1.2k Jun 4, 2021
Modern Java - A Guide to Java 8

Modern Java - A Guide to Java 8 This article was originally posted on my blog. You should also read my Java 11 Tutorial (including new language and AP

Benjamin Winterberg 14.8k Jun 16, 2021
Support alternative markup for Apache Maven POM files

Overview Polyglot for Maven is a set of extensions for Maven 3.3.1+ that allows the POM model to be written in dialects other than XML. Several of the

null 766 Jun 8, 2021
A lightweight staff chat plugin for BungeeCord and Spigot.

A lightweight staff chat plugin for BungeeCord and Spigot with 2-way Discord chat support and many other great features.

null 3 Jun 2, 2021
An open source, modular alternative of sketchware. Create your own app in android using block programming like scratch!

OpenBlocks An open source, modular alternative of sketchware. Create your own app in android using block programming like scratch! What is OpenBlocks?

OpenBlocks 28 May 14, 2021
FizzBuzz Enterprise Edition is a no-nonsense implementation of FizzBuzz made by serious businessmen for serious business purposes.

FizzBuzzEnterpriseEdition Enterprise software marks a special high-grade class of software that makes careful use of relevant software architecture de

null 14.6k Jun 10, 2021
A lightweight, simple FTP server. Pure Java, no dependencies.

MinimalFTP A lightweight, simple FTP server. Pure Java, no libraries. Features Although it's named "minimal", it supports a bunch of features: 100% Ja

Guilherme Chaguri 100 May 31, 2021
The open-source Java obfuscation tool working with Ant and Gradle by yWorks - the diagramming experts

yGuard yGuard is an open-source Java obfuscation tool. With yGuard it is easy as pie ( ?? ) to configure obfuscation through an extensive ant task. yG

yWorks GmbH 141 Jun 3, 2021