A Feature Toggle example

Here we go with our demo application. This time, we're going to build a simple and small REpresentational State Transfer (REST)  service to compute, on demand, a concrete Nth position of Fibonacci's sequence. We will keep track of enabled/disabled features using a file. For simplicity, we will use Spring Boot as our framework of choice and Thymeleaf as a template engine. This is also included in the Spring Boot dependency. Find more information about Spring Boot and related projects at http://projects.spring.io/spring-boot/. Also, you can visit http://www.thymeleaf.org/ to read more about the template engine.

This is how the build.gradle file looks:

apply plugin: 'java' 
apply plugin: 'application' 
 
sourceCompatibility = 1.8 
version = '1.0' 
mainClassName = "com.packtpublishing.tddjava.ch09.Application" 
 
repositories { 
    mavenLocal() 
    mavenCentral() 
} 
 
dependencies { 
    compile group: 'org.springframework.boot', 
            name: 'spring-boot-starter-thymeleaf', 
            version: '1.2.4.RELEASE' 
 
    testCompile group: 'junit', 
    name: 'junit', 
    version: '4.12' 
} 

Note that application plugin is present because we want to run the application using the Gradle command run. Here is the application's main class:

@SpringBootApplication 
public class Application { 
    public static void main(String[] args) { 
        SpringApplication.run(Application.class, args); 
    } 
} 

We will create the properties file. This time, we are going to use YAML Ain't Markup Language (YAML) format, as it is very comprehensive and concise. Add a file called application.yml in the src/main/resources folder, with the following content:

features: 
    fibonacci: 
        restEnabled: false 

Spring offers a way to load this kind of property file automatically. Currently, there are only two restrictions: the name must be application.yml and/or the file should be included in the application's class path.

This is our implementation of the feature's config file:

@Configuration 
@EnableConfigurationProperties 
@ConfigurationProperties(prefix = "features.fibonacci") 
public class FibonacciFeatureConfig { 
    private boolean restEnabled; 
 
    public boolean isRestEnabled() { 
        return restEnabled; 
    } 
 
    public void setRestEnabled(boolean restEnabled) { 
        this.restEnabled = restEnabled; 
    } 
} 

This is the fibonacci service class. This time, the computation operation will always return -1, just to simulate a partially done feature:

@Service("fibonacci") 
public class FibonacciService { 
 
    public int getNthNumber(int n) { 
        return -1; 
    } 
} 

We also need a wrapper to hold the computed values:

public class FibonacciNumber { 
    private final int number, value; 
 
    public FibonacciNumber(int number, int value) { 
        this.number = number; 
        this.value = value; 
    } 
 
    public int getNumber() { 
        return number; 
    } 
 
    public int getValue() { 
        return value; 
    } 
} 

This is the FibonacciRESTController class, responsible for handling the fibonacci service queries:

@RestController 
public class FibonacciRestController { 
    @Autowired 
    FibonacciFeatureConfig fibonacciFeatureConfig; 
 
    @Autowired 
    @Qualifier("fibonacci") 
    private FibonacciService fibonacciProvider; 
 
    @RequestMapping(value = "/fibonacci", method = GET) 
    public FibonacciNumber fibonacci( 
            @RequestParam( 
                    value = "number", 
                    defaultValue = "0") int number) { 
        if (fibonacciFeatureConfig.isRestEnabled()) { 
            int fibonacciValue = fibonacciProvider 
                    .getNthNumber(number); 
            return new FibonacciNumber(number, fibonacciValue); 
        } else throw new UnsupportedOperationException(); 
    } 
 
    @ExceptionHandler(UnsupportedOperationException.class) 
    public void unsupportedException(HttpServletResponse response) 
            throws IOException { 
        response.sendError( 
                HttpStatus.SERVICE_UNAVAILABLE.value(), 
                "This feature is currently unavailable" 
        ); 
    } 
 
    @ExceptionHandler(Exception.class) 
    public void handleGenericException( 
            HttpServletResponse response, 
            Exception e) throws IOException { 
        String msg = "There was an error processing " + 
                "your request: " + e.getMessage(); 
        response.sendError( 
                HttpStatus.BAD_REQUEST.value(), 
                msg 
        ); 
    } 
} 

Note that the fibonacci method is checking whether the fibonacci service should be enabled or disabled, throwing an UnsupportedOperationException for convenience in the last case. There are also two error-handling functions; the first one is for processing UnsupportedOperationException and the second is for generic exceptions handling.

Now that all the components have been set, all we need to do is execute Gradle's
run command:

    $> gradle run
  

The command will launch a process that will eventually set a server up on the following address: http://localhost:8080. This can be observed in the console output:

    ...
    2015-06-19 03:44:54.157  INFO 3886 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
    2015-06-19 03:44:54.160  INFO 3886 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
    2015-06-19 03:44:54.319  INFO 3886 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
    2015-06-19 03:44:54.495  INFO 3886 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
    2015-06-19 03:44:54.649  INFO 3886 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
    2015-06-19 03:44:54.654  INFO 3886 --- [           main] c.p.tddjava.ch09.Application             : Started Application in 6.916 seconds (JVM running for 8.558)
    > Building 75% > :run
  

Once the application has started, we can perform a query using a regular browser. The URL of the query is http://localhost:8080/fibonacci?number=7.

This gives us the following output:

As you can see, the error received corresponds to the error sent by the REST API when the feature is disabled. Otherwise, the return should be -1.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.20.20