



1. Run DEMO on my laptop



A live demo is running at (it can take up to 30s to start, heroku start the demo only on-demand). The following steps will help you build this sample. A live demo is running at https://ff4j-demo.herokuapp.com/. The following steps will help you build this sample.

1.a - Using DOCKER

If you already have Docker install on your machine you can simply run the demo with the command below, it should start at http://localhost:8080. 🤘 docker run -p 8080:8080 ff4j/ff4j-sample-springboot2x:1.8.5



1.b - Using MAVEN

The source code of this demo is available on youtube at

The source code of this demo is available on youtube at https://github.com/ff4j/ff4j-samples/tree/master/spring-boot-2x/ff4j-sample-springboot2x let's clone and run the sample. It should (also) start at http://localhost:8080. You can now start to copy paste or retro engineering, this is sometimes the fastest way right. git clone https://github.com/ff4j/ff4j-samples.git cd spring-boot-2x/ff4j-sample-springboot2x mvn spring-boot:run

This is what it look likes



2. Build the project step-by-step

FF4j can be used in any java application (including Android). 90% of the code is working with JDK1.6+ but it is now recommended to use at JDK8+. The single dependency you have to specified in

pom.xml

is. Tt contains an in-memory implementation for each store. On top of it, you add extra dependenciesto define which database technology to use.

FeatureStore, PropertyStore and EventRepository

don't have to use the same storage technology.



As FF4j provides REST-API and a web console we may want to create a web application to get the most of this tutorial. We will use Spring-Boot but the same steps could be adapted for application.

You can create your project in multiple ways using your IDE or a maven archetype. For this tutorial we will use the website https://start.spring.io/ entering some package name, project name and adding the Spring WEB module and then click GENERATE to download the app.

This is what it look likes



pom.xml file and add the following dependencies.

<dependency> <groupId>org.ff4j</groupId> <artifactId>ff4j-spring-boot-starter</artifactId> <version>${ff4j.version}</version> </dependency> <dependency> <groupId>org.ff4j</groupId> <artifactId>ff4j-web</artifactId> <scope>test</scope> <version>${ff4j.version}</version> </dependency> Unzip, import the project in your favorite IDE, open yourfile and add the following dependencies.



You will define the property ff4j.version to match the current version -- <properties> <ff4j.version>...</ff4j.version> </properties> You will define the propertyto match the current version



2.c - Define FF4j Object

With the Spring framework we use the annotations @Configuration and @Bean to define our FF4j object. FeatureStore, PropertyStore and EventRepository are all initialized with in-memory implementations by default.At the FF4j level exist some flags to enable features like audit or feature autocreation (default behaviour is throwing FeatureNotFoundException)

import org.ff4j.FF4j; import org.ff4j.audit.repository.InMemoryEventRepository; import org.ff4j.property.store.InMemoryPropertyStore; import org.ff4j.store.InMemoryFeatureStore; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FF4jConfig { @Bean public FF4j getFF4j() { FF4j ff4j = new FF4j(); /* * Implementation of each store. Here this is boiler plate as if nothing * is specified the inmemory is used. Those are really the one that will * change depending on your technology. */ ff4j.setFeatureStore(new InMemoryFeatureStore()); ff4j.setPropertiesStore(new InMemoryPropertyStore()); ff4j.setEventRepository(new InMemoryEventRepository()); // Enabling audit and monitoring, default value is false ff4j.audit(true); // When evaluting not existing features, ff4j will create then but disabled ff4j.autoCreate(true); // To define RBAC access, the application must have a logged user //ff4j.setAuthManager(...); // To define a cacher layer to relax the DB, multiple implementations //ff4j.cache([a cache Manager]); return ff4j; } }



2.d - Expose the Web Console

Exposing the web console is only relevant for backend applications (probably centralized) and not in each component using ff4j. Even you secure with user/password, there is not point to open that breach. That been said, let's do it.

The servlet to expose is

org.ff4j.web.FF4jDispatcherServlet

. In Spring Boot application you do not use the

web.xml

file (yet here is a sample ) but rather define the proper bean and annotate with

@Configuration

. Using SpringMVC we extends the

SpringBootServletInitializer

@Configuration // Enable the REST API documentation @EnableFF4jSwagger // The class should be on classpath : FF4jDispatcherServlet @ConditionalOnClass({FF4jDispatcherServlet.class}) // Setup FF4j first, not is required @AutoConfigureAfter(FF4jConfig.class) public class FF4jWebConsoleConfiguration extends SpringBootServletInitializer { @Bean @ConditionalOnMissingBean public FF4jDispatcherServlet defineFF4jServlet(FF4j ff4j) { FF4jDispatcherServlet ff4jConsoleServlet = new FF4jDispatcherServlet(); ff4jConsoleServlet.setFf4j(ff4j); return ff4jConsoleServlet; } @Bean @SuppressWarnings({"rawtypes","unchecked"}) public ServletRegistrationBean registerFF4jServlet(FF4jDispatcherServlet ff4jDispatcherServlet) { return new ServletRegistrationBean(ff4jDispatcherServlet, "/ff4j-web-console/*"); } }

That's it you should now be able to start the application and having the web console responsing at

/ff4j-web-console/

and the rest api responding at

/api/ff4j



2.e - Define a sample controller

With the previous steps you do have a working sample but no features or properties to play with. In the demo we added a rest controller mapped to root path /. In the one we define 3 features (showWebConsoleURL, showRestApiURL, showUserName) and 1 property (username).

@RestController @RequestMapping("/") public class HomeController { private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class); private static final String FEATURE_SHOW_WEBCONSOLE = "showWebConsoleURL"; private static final String FEATURE_SHOW_REST_API = "showRestApiURL"; private static final String FEATURE_SHOW_USERNAME = "showUserName"; private static final String PROPERTY_USERNAME = "username"; @Autowired public FF4j ff4j; @PostConstruct public void populateDummyFeatureForMySample() { if (!ff4j.exist(FEATURE_SHOW_WEBCONSOLE)) { ff4j.createFeature(new Feature(FEATURE_SHOW_WEBCONSOLE, true)); } if (!ff4j.exist(FEATURE_SHOW_REST_API)) { ff4j.createFeature(new Feature(FEATURE_SHOW_REST_API, true)); } if (!ff4j.exist(FEATURE_SHOW_USERNAME)) { ff4j.createFeature(new Feature(FEATURE_SHOW_USERNAME, true)); } if (!ff4j.getPropertiesStore().existProperty(PROPERTY_USERNAME)) { ff4j.createProperty(new PropertyString(PROPERTY_USERNAME, "cedrick")); } LOGGER.info(" + Features and properties have been created for the sample."); }

@RequestMapping(value = "/", method = RequestMethod.GET, produces = "text/html") public String get() { LOGGER.info(" + Rendering home page..."); StringBuilder htmlPage = new StringBuilder("<html><body><ul>"); htmlPage.append("<h2>This is home page.</h2>"); htmlPage.append("<p>Displaying the links below is driven by features in FF4j." + "If you disable the feature " + "the link will disapear (but the servlet will still response, " + "this is just a trick to illustrate " + "response in the UI)</p>"); htmlPage.append("<p><b>List of resources for you :" + "</b><br/><ul>"); if (ff4j.check(FEATURE_SHOW_WEBCONSOLE)) { htmlPage.append("<li> To access the To access the <b>REST API</b> " + "please go to <a href=\"./api/ff4j\" target=\"_blank\">ff4j-rest-api </a>"); } if (ff4j.check(FEATURE_SHOW_USERNAME)) { if (ff4j.getPropertiesStore().existProperty(PROPERTY_USERNAME)) { htmlPage.append("<li> " + PROPERTY_USERNAME + " value is "); htmlPage.append("<span style=\"color:blue;font-weight:bold\">"); htmlPage.append(ff4j.getPropertiesStore().readProperty(PROPERTY_USERNAME).asString()); htmlPage.append("</span>"); } else { htmlPage.append("<li> " + PROPERTY_USERNAME + " does not exist."); } } htmlPage.append("</ul></body></html>"); return htmlPage.toString(); }

Then we display a text on screen based on the value of the flag. We that simply displaying the home page will trigger the features and we would have to events in the monitoring screen. This is also a good way to provide URL to the web console and the rest API:Congratulations you are done with this getting started. You can now move to a set of SAMPLES or jump into the reference guide, which is our wiki on github.