Over a million developers have joined DZone.

First Iteration — A Command-Line Application: Part 4

The fourth part in a series on test-driven development with Java web apps and web services.

· Java Zone

Microservices! They are everywhere, or at least, the term is. When should you use a microservice architecture? What factors should be considered when making that decision? Do the benefits outweigh the costs? Why is everyone so excited about them, anyway?  Brought to you in partnership with IBM.

Continue With Test-Driven Development

We are on our way to developing and exploring various technologies of web applications and web services, but we begin with a simple program that turns into a resuable component. Read the previous section here!

Add Key JUnit Test

Now it is time to add one of the very important, defining tests, that will compel us to dive in do some real software work in analysis, design, implementation, and we'll have to deal with concurrency.

Here is the test:

@Test
public void testQueueRequestAndRunNoStop() {

    calculator.deleteAllPendingRequests();

    double dimension = 0.000;
    calculator.queueCalculationRequest(ShapeName.CIRCLE, CalcType.CALC_AREA, dimension);
    dimension = 0.001;
    calculator.queueCalculationRequest(ShapeName.CIRCLE, CalcType.CALC_AREA, dimension);
    dimension = 0.002;
    calculator.queueCalculationRequest(ShapeName.CIRCLE, CalcType.CALC_AREA, dimension);

    dimension = 0.000;
    calculator.queueCalculationRequest(ShapeName.SQUARE, CalcType.CALC_AREA, dimension);
    dimension = 0.001;
    calculator.queueCalculationRequest(ShapeName.CIRCLE, CalcType.CALC_VOLUME, dimension);
    dimension = 0.002;
    calculator.queueCalculationRequest(ShapeName.SPHERE, CalcType.CALC_AREA, dimension);


    List<CalculationRequest> requests = calculator.getAllPendingRequests();
    assertNotNull(requests);
    assertEquals(6,requests.size());

    int numRun = calculator.runAllPendingRequestsNoStopOnError();
    assertEquals(6,numRun);

    requests = calculator.getAllPendingRequests();
    assertNotNull(requests);
    assertEquals(0,requests.size());

    List<CalculationResult> results = calculator.getAllCalculationResults();
    assertNotNull(results);
    assertEquals(6,results.size());

    calculator.deleteAllResults();
    results = calculator.getAllCalculationResults();
    assertNotNull(results);
    assertEquals(0,results.size());
}


Review All Code Changes So Far

Go to https://github.com/elicorrales/shape-calc-1/tree/master/shape-calc/src/main/java/com/eli/calc/shape. There you can view all code that we have written to this point. If you open the project POM, I added "slf4j" (logging).

Cycle: Run Test - Modify Code

I just now tried running the JUnitTest.  The console showed:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".

SLF4J: Defaulting to no-operation (NOP) logger implementation

SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

Going to that URL yields the following tidbit:

Failed to load class org.slf4j.impl.StaticLoggerBinder

This warning message is reported when the org.slf4j.impl.StaticLoggerBinder class could not be loaded into memory. This happens when no appropriate SLF4J binding could be found on the class path. Placing one (and only one) of slf4j-nop.jarslf4j-simple.jarslf4j-log4j12.jarslf4j-jdk14.jar or logback-classic.jar on the class path should solve the problem.

Let's go with the logback-classic.jar.

Some research at the https://mvnrepository.com/ yields this is the dependency we need:

<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-classic</artifactId>

<version>1.1.7</version>

</dependency>

Plop that in the POM and run the test again. This time we get past the previous error, and Spring seems to be pretty busy in the console... but all the tests fail.

At the end of the console output, we find this:

00:00:16.473 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata -

Processing injected element of bean 'shapeCalculatorServiceImpl':

AutowiredFieldElement for private java.util.concurrent.ExecutorService

com.eli.calc.shape.service.impl.ShapeCalculatorServiceImpl.executor

00:00:16.474 [main] WARN org.springframework.context.annotation.AnnotationConfigApplicationContext -

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.

UnsatisfiedDependencyException: Error creating bean with name 'shapeCalculatorServiceImpl':

Unsatisfied dependency expressed through field 'executor':

No qualifying bean of type [java.util.concurrent.ExecutorService] found for dependency

[java.util.concurrent.ExecutorService]:

expected at least 1 bean which qualifies as autowire candidate for this dependency.

Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)};

nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:

No qualifying bean of type [java.util.concurrent.ExecutorService] found for dependency

[java.util.concurrent.ExecutorService]: expected at least 1 bean which qualifies as autowire candidate for this dependency.

Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

00:00:16.475 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory -

Destroying singletons ......blah , blah, blah..

Go find the ShapeCalculatorServiceImpl in GitHub, https://github.com/elicorrales/shape-calc-1/blob/master/shape-calc/src/main/java/com/eli/calc/shape/service/impl/ShapeCalculatorServiceImpl.java, and you will notice, right after private static logger initialization, I added an  @Autowired ExecutorService executor;.

The problem is we have not defined/created any <bean> (or @Bean) for Spring's component-scanning to match with the executor's type.

I am not really going to go into much of an explanation on concurrency — there are plenty of great articles on that topic already.  Essentially, I wanted some sort of pool of managed threads that would do some work for me. (Like run calculations).   That's what the "executor" buys us.

So how do we solve the above issue?  One way is to go to our AppConfig class (that doesn't have much in it at the moment). You can find it here: https://github.com/elicorrales/shape-calc-1/blob/master/shape-calc/src/main/java/com/eli/calc/shape/config/AppConfig.java

We will add a bean to this class.  That means Spring will NOT have to scan for it.

@Bean
ExecutorService getExecutor() {

    return Executors.newFixedThreadPool(32);
}

We run the JUnitTest, and this time it does autowire the executor inside our calculator implementation class.

We could also have done the above like so:

@Bean
ExecutorService getExecutorService() {

    return Executors.newFixedThreadPool(32);
}

If you run the test with the above snippet, instead of the first one, it will also work. Does the name of the operation not matter? How about running the test with both snippets as part of the AppConfig class?

Here is the result when we do:

00:32:46.150 [main] WARN org.springframework.context.annotation.AnnotationConfigApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'shapeCalculatorServiceImpl': Unsatisfied dependency expressed through field 'executor':

No qualifying bean of type [java.util.concurrent.ExecutorService] is defined:

expected single matching bean but found 2:

getExecutorService , getExecutor;

nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [java.util.concurrent.ExecutorService] is defined: expected single matching bean but found 2: getExecutorService,getExecutor

So, apparently, Spring is checking the return type to match it to the one to be @Autowired.

How about if we for some reason needed those two beans defined anway?

We can do this:

@Bean
ExecutorService getExecutor() {

    return Executors.newFixedThreadPool(32);
}

@Bean(name="executor")
ExecutorService getExecutorService() {

    return Executors.newFixedThreadPool(32);
}

Running the test again, we see this:

00:38:11.135 [main] DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'shapeCalculatorServiceImpl' to bean named 'executor'

So Spring can load by type, or it can load by name.

Before we leave this topic of loading the executor, notice that we have hard-coded "32" threads for the executor. 

Let's change that hard-coded value, and have it be loaded as a property from a file called "application.properties".

Image title

Inside the application.properties, enter this: executor.threadpool.size=32 

Now, open AppConfig and add stuff:

@Configuration
@ComponentScan(basePackages="com.eli.calc.shape")
@PropertySource("classpath:application.properties")
public class AppConfig {

    @Autowired
    private Environment environment; // to have access to application.properties


    @Bean(name="executor")
    ExecutorService getExecutor() {

        return Executors.newFixedThreadPool(
            Integer.parseInt(environment.getProperty("executor.threadpool.size"))
        );
    }

What is new?

  •  @PropertySource("classpath:application.properties") 

  •  @Autowired private Environment environment; // to have access to application.properties 

  •  Integer.parseInt(environment.getProperty("executor.threadpool.size")) 

The Environment is something Spring already knows about. We told it where, what source, and in what file to find some properties and add those to the Environment. Finally, we used the Environment to grab the value of a specific property, the one we put inside  application.properties.

When we run the test, we see this:

00:43:48.665 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating instance of bean 'executor'

00:43:48.665 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appConfig'

00:43:48.666 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'executor.threadpool.size' in [class path resource [application.properties]] with type [String] and value '32'

00:43:48.667 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Eagerly caching bean 'executor' to allow for resolving potential circular references

00:43:48.670 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Finished creating instance of bean 'executor'

Review All Code Changes So Far

Finally, all the JUnit tests pass. You can view all the latest code at https://github.com/elicorrales/shape-calc-4b/tree/master/shape-calc .

Stay tuned for the next article!

Discover how the Watson team is further developing SDKs in Java, Node.js, Python, iOS, and Android to access these services and make programming easy. Brought to you in partnership with IBM.

Topics:
java 8 ,junit ,test driven development ,ooad ,oop ,concurrency

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}