Feature Flags for Java made easy

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]

Comments
  • 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

    ready-for-release in-progress 
    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!

    evolution ready-for-release Technical Debt 
    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

    question answered 
    opened by jackpf 11
  •  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
  • `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
  • 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?

    question answered 
    opened by ealparslan 9
  • [Suggestion] Implement Simple WebSecurity for ff4j-console using springboot

    [Suggestion] Implement Simple WebSecurity for ff4j-console using springboot

    After having a look at the documentation and doing some investigation with Spring Security I was able to come up with a very simple Authentication pattern for the WebUI. It consists of the following:

    1- Add the following dependency to the pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    

    2- Add the following annotation to your SpringApplication:

    @SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
    

    3- Add this configuration Bean to your project

    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.factory.PasswordEncoderFactories;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @Configuration
    @EnableWebSecurity
    public class BasicConfiguration extends WebSecurityConfigurerAdapter {
    
    	@Override
    	protected void configure(AuthenticationManagerBuilder auth)
    			throws Exception {
    		PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
    		auth
    				.inMemoryAuthentication()
    				.withUser("admin")
    				.password(encoder.encode("klapaucius"))
    				.roles("ADMIN");
    	}
    
    	@Override
    	protected void configure(HttpSecurity http) throws Exception {
    		http
    				.authorizeRequests()
    				.anyRequest()
    				.authenticated()
    				.and()
    				.httpBasic();
    	}
    }
    

    And pronto! If you want to access the http://localhost:8080/ff4j-console URL to manage the toggles you will be required to login using the credentials set in the BasicConfiguration class.

    For the sake of versioning, these are the dependencies in the pom.xml.

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/>
    </parent>
    ...
    <dependency>
        <groupId>org.ff4j</groupId>
        <artifactId>ff4j-spring-boot-starter</artifactId>
        <version>1.8</version>
    </dependency>
    <dependency>
        <groupId>org.ff4j</groupId>
        <artifactId>ff4j-web</artifactId>
        <version>1.8</version>
    </dependency>
    

    It is not great but at least allows one to secure the gui with minimal configuration efforts and to not fiddle a lot around.

    Yes, one should never commit a password in a codebase, but this at least gives some guidance on how to extend it further, by e.g. customizing the AuthenticationManagerBuilder and adding a third-party storage for a credentials.

    If it is useful, adding this to the documentation or a sample might help.

    Disclaimer: If did not test if this affects clients fetching the toggles via REST. Also, would be nice to have the logged in user flushed to the ff4j_event table if you are using the Audit feature. This way one would know which user handle made a given change. Of course, this would imply in changes to the embedded ff4j.

    duplicate evolution in-progress 
    opened by neillfontes-sl 9
  • [Snyk] Upgrade com.fasterxml.jackson.core:jackson-annotations from 2.14.0 to 2.14.1

    [Snyk] Upgrade com.fasterxml.jackson.core:jackson-annotations from 2.14.0 to 2.14.1

    Snyk has created this PR to upgrade com.fasterxml.jackson.core:jackson-annotations from 2.14.0 to 2.14.1.

    :information_source: Keep your dependencies up-to-date. This makes it easier to fix existing vulnerabilities and to more quickly identify and fix newly disclosed vulnerabilities when they affect your project.


    • The recommended version is 1 version ahead of your current version.
    • The recommended version was released a month ago, on 2022-11-21.

    Note: You are seeing this because you or someone else with access to this repository has authorized Snyk to open upgrade PRs.

    For more information:

    🧐 View latest project report

    🛠 Adjust upgrade PR settings

    🔕 Ignore this dependency or unsubscribe from future upgrade PRs

    opened by snyk-bot 0
  • [Snyk] Upgrade com.fasterxml.jackson.datatype:jackson-datatype-joda from 2.14.0 to 2.14.1

    [Snyk] Upgrade com.fasterxml.jackson.datatype:jackson-datatype-joda from 2.14.0 to 2.14.1

    Snyk has created this PR to upgrade com.fasterxml.jackson.datatype:jackson-datatype-joda from 2.14.0 to 2.14.1.

    :information_source: Keep your dependencies up-to-date. This makes it easier to fix existing vulnerabilities and to more quickly identify and fix newly disclosed vulnerabilities when they affect your project.


    • The recommended version is 1 version ahead of your current version.
    • The recommended version was released a month ago, on 2022-11-22.

    Note: You are seeing this because you or someone else with access to this repository has authorized Snyk to open upgrade PRs.

    For more information:

    🧐 View latest project report

    🛠 Adjust upgrade PR settings

    🔕 Ignore this dependency or unsubscribe from future upgrade PRs

    opened by snyk-bot 0
  • [Snyk] Upgrade javax.servlet:javax.servlet-api from 3.0.1 to 3.1.0

    [Snyk] Upgrade javax.servlet:javax.servlet-api from 3.0.1 to 3.1.0

    Snyk has created this PR to upgrade javax.servlet:javax.servlet-api from 3.0.1 to 3.1.0.

    :information_source: Keep your dependencies up-to-date. This makes it easier to fix existing vulnerabilities and to more quickly identify and fix newly disclosed vulnerabilities when they affect your project.


    • The recommended version is 10 versions ahead of your current version.
    • The recommended version was released 10 years ago, on 2013-04-25.

    Note: You are seeing this because you or someone else with access to this repository has authorized Snyk to open upgrade PRs.

    For more information:

    🧐 View latest project report

    🛠 Adjust upgrade PR settings

    🔕 Ignore this dependency or unsubscribe from future upgrade PRs

    opened by snyk-bot 0
  • SQL queries executing in a loop when reading all features using JdbcFeatureStore

    SQL queries executing in a loop when reading all features using JdbcFeatureStore

    When calling readAll() method of JdbcFeatureStore the following code executes a new query to get custom properties for each feature:

    // Read custom properties for each feature
    for (Feature f : mapFP.values()) {
        ps = sqlConn.prepareStatement(getQueryBuilder().getFeatureProperties());
        ps.setString(1, f.getUid());
        rs = ps.executeQuery();
        while (rs.next()) {
            f.addProperty(JDBC_PROPERTY_MAPPER.map(rs));
        }
        closeResultSet(rs);
        rs = null;
        closeStatement(ps);
        ps = null;
    }
    

    Therefore if we have 50 features there will be 50+ SQL queries executed, and depending on latency it can be very slow.

    Ideally, custom properties retrieval should be done in a single query using a join.

    evolution 
    opened by AndLvovSky 1
  • Custom Properties with fixed values cannot be edited via drop down in UI

    Custom Properties with fixed values cannot be edited via drop down in UI

    A property with fixed values show a drop-down in the edit dialog. A similar property that is part of a feature does not show such a drop-down.

    Since the export does not include the custom properties, I add the SQL-insert statements for my setup INSERT INTOFF4J_FEATURES(FEAT_UID,ENABLE,DESCRIPTION,STRATEGY,EXPRESSION,GROUPNAME`) VALUES ('Sprint 11 Values',1,'Some Values Specific for Sprint 11',NULL,NULL,'Sprint 11');

    INSERT INTO FF4J_CUSTOM_PROPERTIES (PROPERTY_ID,CLAZZ,CURRENTVALUE,FIXEDVALUES,DESCRIPTION,FEAT_UID) VALUES ('EmailMode','com.foo.emailservice.ff4j.EmailModeProperty','DIRECT','DIRECT, VIA_TOPIC, NO_EMAIL','The different modes in which the Email-Service can deliver mail','Sprint 11 Values');

    INSERT INTO FF4J_PPROPERTIES (PROPERTY_ID,CLAZZ,CURRENTVALUE,FIXEDVALUES,DESCRIPTION) VALUES ('emailmode','com.foo.emailservice.ff4j.EmailModeProperty','VIA_TOPIC','VIA_TOPIC, DIRECT, NO_EMAIL','The different modes in which the Email-Service can deliver mail'); `

    The custom property shows up in the feature edit dialog FF4J-FeaturesEmailMode

    editing the property does not show the fixed values, although no changes can be made with other values editpropertyoffeature

    compare this with a similar (standalone) property, where the dialog shows the fixed values propertywithfixedvalues

    This is version 1.8.12

    bug 
    opened by marcgemis 4
Releases(1.9)
  • 1.9(Dec 20, 2022)

    This is the release version 1.9 of FF4j

    Release notes:

    • Fix CVE-2022-44262 as describe with #624 and #646
    • Fix #611 - Requiring DynamoDB configuration to be set via properties
    • Fix #548 - Issue with Spring Boot 2.6.4 and Thymeleaf 3.0.15
    • Fix #570 - Vulnerabilities with "old" console
    • Fix #531 - Removing confirmation bloc on the user interface
    • Fix #520 - Update bootstrap version
    • Numerous (dozens) updates of versions dependencies
    Source code(tar.gz)
    Source code(zip)
  • 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(May 1, 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 by@shridharns)

    • 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)

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 18.4k Dec 31, 2022
An easy to use Hindi keyboard Android app

AasaanHindi-Keyboard-app An easy to use Hindi keyboard Android app. Easy and fast Hindi typing.

Ankit Kumar 1 Jan 20, 2022
Lightweight and easy-to-use SkinChangerAPI for Bukkit plugin

Lightweight and easy-to-use SkinChangerAPI for Bukkit plugin

Gabriel MERCIER 6 Jul 1, 2022
lobster is an easy-to-use Discord bot to play music in any voice channel

lobster is an easy-to-use Discord bot to play music in any voice channel

lundy 6 Apr 8, 2022
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 16.1k Jan 5, 2023
icecream-java is a Java port of the icecream library for Python.

icecream-java is a Java port of the icecream library for Python.

Akshay Thakare 20 Apr 7, 2022
JPassport works like Java Native Access (JNA) but uses the Foreign Linker API instead of JNI. Similar to JNA, you declare a Java interface that is bound to the external C library using method names.

JPassport works like Java Native Access (JNA) but uses the Foreign Linker API instead of JNI. Similar to JNA, you declare a Java interface t

null 28 Dec 30, 2022
There are two versions of assignments(Java or C++) for the CS143-Compiler course, this repo is my Java-version solution.

Intro There are two versions of assignments(Java or C++) for the CS143-Compiler course, this repo is my Java-version solution. Course resources: This

F4DE 3 Dec 15, 2022
From Java To Kotlin - Your Cheat Sheet For Java To Kotlin

From Java To Kotlin From Java To Kotlin - Your Cheat Sheet For Java To Kotlin 中文支持 Português Español Print to Console Java System.out.print("Amit Shek

MindOrks 5.8k Dec 29, 2022
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.6k Dec 30, 2022
Design patterns implemented in Java

Design patterns implemented in Java Read in different language : CN, KR, FR, TR, AR Introduction Design patterns are the best formalized practices a p

Ilkka Seppälä 79k Dec 31, 2022
A Java to iOS Objective-C translation tool and runtime.

J2ObjC: Java to Objective-C Translator and Runtime Project site: https://j2objc.org J2ObjC blog: https://j2objc.blogspot.com Questions and discussion:

Google 5.9k Dec 29, 2022
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 Dec 18, 2022
An in-memory file system for Java 7+

Jimfs Jimfs is an in-memory file system for Java 7 and above, implementing the java.nio.file abstract file system APIs. Getting started The latest rel

Google 2.2k Jan 3, 2023
API gateway for REST and SOAP written in Java.

Membrane Service Proxy Reverse HTTP proxy (framework) written in Java, that can be used as an API gateway as a security proxy for HTTP based integrati

predic8 GmbH 389 Dec 31, 2022
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 131 Jan 5, 2023
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 325 Dec 12, 2022
A lightweight command processing pipeline ❍ ⇢ ❍ ⇢ ❍ for your Java awesome app.

PipelinR PipelinR is a lightweight command processing pipeline ❍ ⇢ ❍ ⇢ ❍ for your awesome Java app. PipelinR has been battle-proven on production, as

Eduards Sizovs 288 Jan 8, 2023
An extensible Java framework for building XML and non-XML streaming applications

Smooks Framework This is the Git source code repository for the Smooks Project. Build Status Building Pre-requisites JDK 8 Apache Maven 3.2.x Maven gi

Smooks Framework 353 Dec 1, 2022