Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

Spring Boot

Spring Boot is changing the world of Java development with Spring. It is taking away much of the pain that was involved with configuring applications. This is great when you are trying to create what they do by default. They create executable jars by default. What do you have to do if you need to create a WAR file to run on a Tomcat by someone else.

POM file

Let’s start with our project’s pom.xml file. Here we need to define the standard Spring Boot parent starter and also include include the Spring Boot Web starter. The Spring Boot Web starter also includes the Spring Boot Tomcat starter. In our case, we do not want it packaged inside our war because our war file will be deployed on a Tomcat server directly. We don’t have to roll our own. To change this behavior, we include the Spring Boot tomcat starter explicitly and set it’s scope to provided. We also must specify the packaging of our project to be a war.

<?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.javaninja.springboot</groupId>
    <artifactId>springboot-web</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

Java Config

Normally the Java Configuration contains a main method because that is how the program will be launched. In this case, we do not need a main method and instead we need to provide a configure method to go along with the SpringBootServletInitializer that we extend.

package com.javaninja.springboot.web;


import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;


@SpringBootApplication
public class WebApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebApplication.class);
    }
}

Example Controller

That is all of the configuration that we need to make this work as a normal Spring MVC controller. To test our functionality, we need a very simple controller, such as the following,.

package com.javaninja.springboot.web;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class ExampleController {

    private Logger log = LoggerFactory.getLogger(getClass());

    @GetMapping("/example/boolean")
    public Boolean exampleBoolean() {
        log.info("Eureka!");
        return true;
    }
}

Test the controller

Let’s create a very simple test using the Spring Boot Test starter. This brings in Junit and MockMvc among other useful APIs.

package com.javaninja.springboot.web;


import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.assertj.core.api.Assertions.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


/**
 * @author norris.shelton
 */
@RunWith(SpringRunner.class)
@WebMvcTest(ExampleController.class)
public class TestExampleController {

    @Autowired
    private MockMvc mvc;

    @Test
    public void testExampleBoolean() {
        try {
            mvc.perform(get("/example/boolean")
                            .accept(MediaType.APPLICATION_JSON))
               .andExpect(status().isOk())
               .andExpect(content().string("true"));
        } catch (Exception e) {
            fail(e.toString());
        }
    }
}

The test run perfectly and produces the following logging and a nice pretty green bar.

2017-07-10 18:36:06.218  INFO 7499 --- [           main] c.j.springboot.web.ExampleController     : Eureka!

July 11th, 2017

Posted In: Maven, MockMVC, Spring, Spring Boot, Spring MVC, Test Driven Development, Unit Tests

Tags: , ,

Leave a Comment

Working with Spring Data JPA repositories is easy if you use them the way they are intended to be used. One way that they don’t like to be used is with two different databases with the objects in the same directories. In a previous blog titled Spring Data JPA with multiple entity managers, I showed how to have multiple EntityManagers work with Spring Data JPA. As part of that, we had to annotate each method that used the repository with @Transactional. I didn’t like this and I was searching for a way to make it better.

I tried to filter the jpa:repositories with a regex, but that wouldn’t work.

I next tried filtering by annotation and it worked like a charm. Here is how I did it.

Create annotations

The annotations are very simple and there isn’t Spring specific about them. I created @ReadOnly and @ReadWrite annotations.

package com.javaninja.adw.spring;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * Annotation used to indicate that this should be picked up as a ReadOnly database operation, specifically for
 * Spring Data JPA repositories.
 * @author norrisshelton
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ReadOnly {

} 
package com.javaninja.adw.spring;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * Annotation used to indicate that this should be picked up as a ReadWrite database operation, specifically for
 * Spring Data JPA repositories.
 * @author norrisshelton
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ReadWrite {

} 

Annotate the repositories

I annotated the Read-only repository with @ReadOnly and annotated my Read-Write repository with @ReadWrite.

package com.javaninja.adw.example;


import com.javaninja.adw.spring.ReadOnly;

import org.springframework.data.jpa.repository.JpaRepository;


/**
 * Read-only Spring Data JPA Repository for Example objects.
 * @author norrisshelton
 */
@ReadOnly
public interface RoExampleRepository extends JpaRepository<ExampleEntity, Integer> {

    ExampleEntity findByAffiliateId(int affiliateId);
}
package com.javaninja.adw.example;


import com.javaninja.adw.spring.ReadWrite;

import org.springframework.data.jpa.repository.JpaRepository;


/**
 * Read-write Spring Data JPA Repository for Example objects.
 * @author norrisshelton
 */
@ReadWrite
public interface RwExampleRepository extends JpaRepository<ExampleEntity, Long> {

}

Repository declaration

Once I have that, I can move onto the Spring context configuration. I could then modify my jpa:repositories declaration to look like:

<jpa:repositories base-package="com.javaninja.adw"
                  entity-manager-factory-ref="roEntityManagerFactory"
                  transaction-manager-ref="roTransactionManager">
    <repository:include-filter type="annotation" expression="com.javaninja.adw.spring.ReadOnly"/>
</jpa:repositories>
<jpa:repositories base-package="com.javaninja.adw"
                  entity-manager-factory-ref="rwEntityManagerFactory"
                  transaction-manager-ref="rwTransactionManager">
    <repository:include-filter type="annotation" expression="com.javaninja.adw.spring.ReadWrite"/>
</jpa:repositories>

What does it look like when used

Once those changes are done, using it is as easy as any other usage. No more @Transactional annotations.

package com.javaninja.adw.example;


import com.javaninja.adw.ExampleModel;

import org.springframework.stereotype.Service;


/**
 * @author norris.shelton
 */
@Service
public class ExampleService {

    private final RoExampleRepository roExampleRepository;

    public ExampleService(RoExampleRepository roExampleRepository) {
        this.roExampleRepository = roExampleRepository;
    }

    /**
     * Gets an example model object.
     * @return populated example model
     */
    public ExampleModel getExampleModel(int affiliateId) {
        ExampleEntity exampleEntity = roExampleRepository.findByAffiliateId(affiliateId);
        ExampleModel exampleModel = new ExampleModel();
        exampleModel.setExampleProperty(exampleEntity.getName());
        return exampleModel;
    }
}

The rest of the Spring Context

The rest of the Spring Context configuration looks the same. There is two of anything. To prevent confusion, I pre-pended ro or rw to all of my objects.

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<util:properties id="jpaProperties">
    <!--<prop key="hibernate.show_sql">false</prop>-->
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
</util:properties>
<bean id="rwEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
      p:dataSource-ref="rwAdwDataSource"
      p:packagesToScan="com.javaninja.adw"
      p:persistenceUnitName="rwPersistenceUnit"
      p:jpaVendorAdapter-ref="jpaVendorAdapter"
      p:jpaProperties-ref="jpaProperties"/>
<bean id="roEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
      p:dataSource-ref="roAdwDataSource"
      p:packagesToScan="com.javaninja.adw"
      p:persistenceUnitName="roPersistenceUnit"
      p:jpaVendorAdapter-ref="jpaVendorAdapter"
      p:jpaProperties-ref="jpaProperties"/>
<!--
    Transaction-related configuration
-->
<tx:annotation-driven/>
<bean id="rwTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="rwEntityManagerFactory"/>
    <qualifier value="rw"/>
</bean>
<bean id="roTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="roEntityManagerFactory"/>
    <qualifier value="ro"/>
</bean>

May 3rd, 2017

Posted In: Java, java ninja, Javaninja, Spring, Spring Data, Spring Data JPA

Leave a Comment

We are using -D system parameters to define our connection pool values. They were defined in a Tomcat setenv file in the bin directory.

export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-JDBC=jdbc:mysql://192.168.0.1/javaninja?zeroDateTimeBehavior=convertToNull"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO--- USER=javaninja"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-PASS=javaninja"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-INITIAL-SIZE=1"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-MIN-IDLE=1"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-MAX-IDLE=1"
export CATALINA_OPTS="$CATALINA_OPTS -DPROXY-RO-MAX-TOTAL=15"

The parameters appeared to be read correctly, as evidenced by the Tomcat log.

14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-JDBC=jdbc:mysql://192.168.0.1/javaninja?zeroDateTimeBehavior=convertToNull
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO--- USER=javaninja
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-PASS=javaninja
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-INITIAL-SIZE=1
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-MIN-IDLE=1
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-MAX-IDLE=1
14-Dec-2016 09:23:41.499 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -DPROXY-RO-MAX-TOTAL=15

This did not work. We would get weird messages about the value not being in range. This was due to one of the values having noAccessToProcedureBodies=true. The JDBC driver expected yes, no, true or false Unfortunately, what it was receiving was true\n. I have no idea where the newline was coming from. I deleted the end of the line and typed the characters myself, but they were still there.

The solution was to trim all of the values of control characters. Apache StringUtils is my preferred tool for that; however, it is a static class and Spring doesn’t like that. To get over that, I instantiated a copy of it.

<bean id="stringUtils" class="org.apache.commons.lang3.StringUtils"/>

Once I had a StringUtils bean, I used it to trim the values by

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"
      p:driverClassName="com.mysql.jdbc.Driver"
      p:url="#{stringUtils.trim(systemProperties['PROXY-RO-JDBC'])}"
      p:username="#{stringUtils.trim(systemProperties['PROXY-RO--- USER'])}"
      p:password="#{stringUtils.trim(systemProperties['PROXY-RO-PASS'])}"
      p:initialSize="#{stringUtils.trim(systemProperties['PROXY-RO-INITIAL-SIZE'])}"
      p:maxTotal="#{stringUtils.trim(systemProperties['PROXY-RO-MAX-TOTAL'])}"
      p:maxIdle="#{stringUtils.trim(systemProperties['PROXY-RO-MAX-IDLE'])}"
      p:minIdle="#{stringUtils.trim(systemProperties['PROXY-RO-MIN-IDLE'])}"
      p:testOnBorrow="false"
      p:timeBetweenEvictionRunsMillis="60000"
      p:testWhileIdle="true"/>

December 14th, 2016

Posted In: Java, java ninja, Javaninja, Spring

Leave a Comment

In the previous blog entry titled Turning Spring MVC exceptions into status codes with messages, I mapped exceptions into HTTP status codes.

Test Controller

In this blog we will test those and verify that everything is working correctly. I started with a test controller that I would use to generate the exceptions and the message. I created controller methods that would generate consistent results:

  • ResourceException with an HTTP 400 and a message
  • ResourceException with an HTTP 404 and a message
  • RuntimeException without any developer customization
  • Exception with a message

I wanted to ensure that I had consistent behavior and I was able to pull information from the exception that would be relevant to the client/consumer, but I also wanted to ensure that I never returned a stacktrace to the outside world.

package com.javaninja.cam.spring;


import com.javaninja.cam.dto.Prospect;
import com.javaninja.cam.exception.ResourceException;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {

    @RequestMapping(value = "/test/resourceException400")
    public Prospect getResourceException400() {
        throw new ResourceException(HttpStatus.BAD_REQUEST, "Test Bad Request Exception message");
    }

    @RequestMapping(value = "/test/resourceException404")
    public Prospect getResourceException404() {
        throw new ResourceException(HttpStatus.NOT_FOUND, "Test Not Found Exception message");
    }

    @RequestMapping(value = "/test/runtimeException")
    public int getRuntimeException() {
        return Integer.parseInt("x");
    }

    @RequestMapping(value = "/test/exception")
    public int getException() throws Exception {
        throw new Exception("Test Exception message");
    }
}

Junit Test Class

Once that was written, it was fairly easy to test the results. I used MockMVC with Spring Test to implement my test class. As part of this test, I wanted to ensure that the custom ResourceException that I created was handled correctly. I also wanted to ensure that I could handle RuntimeExceptions that happened during regular program execution could be handled. The last thing I wanted to verify was that developer created and thrown exceptions could be handled and that the message that they were created with was outputted correctly. I checked the HTTP status and the content for each type of exception.

package com.javaninja.cam.spring;


import com.javaninja.cam.JunitTestUtility;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import static org.junit.Assert.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


/**
 * @author norris.shelton
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-test.xml")
@WebAppConfiguration
public class TestCamControllerAdvice {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    /**
     * Needed because we have some legacy code that intereactes directly with the context.  This is NOT normal and 
     * will be removed as the project is modernized. 
     * @throws Exception
     */
    @BeforeClass
    public static void createMockContext() throws Exception {
        JunitTestUtility.setup();
    }

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    /**
     * Tests the custom ResourceException and verifies that it returns a HTTP 400 with the expected message.
     */
    @Test
    public void testResourceException400() {
        try {
            mockMvc.perform(get("/test/resourceException400"))
                   .andExpect(status().isBadRequest())
                   .andExpect(content().string("Test Bad Request Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests the custom ResourceException and verifies that it returns a HTTP 404 with the expected message.
     */
    @Test
    public void testResourceException404() {
        try {
            mockMvc.perform(get("/test/resourceException404"))
                   .andExpect(status().isNotFound())
                   .andExpect(content().string("Test Not Found Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests that a RuntimeException is received and that it returns the expected message.
     */
    @Test
    public void testRuntimeException() {
        try {
            mockMvc.perform(get("/test/runtimeException"))
                   .andExpect(status().isInternalServerError())
                   .andExpect(content().string("java.lang.NumberFormatException: For input string: \"x\""))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }

    /**
     * Tests that an Exception is received and that it returns the expected message.
     */
    @Test
    public void testException() {
        try {
            mockMvc.perform(get("/test/exception"))
                   .andExpect(status().isInternalServerError())
                   .andExpect(content().string("Test Exception message"))
                   .andDo(print());
        } catch (Exception e) {
            fail(e.toString());
        }
    }
}

MockMVC Print Output

For readability, I also displayed the full MockMVC print output. The output makes it very clear that I received the anticipated information and nothing else. The example output is below:

com.javaninja.cam.spring.TestCamControllerAdvice

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/exception
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public int com.twinspires.cam.spring.TestController.getException() throws java.lang.Exception

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = java.lang.Exception

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 500
    Error message = null
          Headers = {Content-Type=, Content-Length=[22]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/resourceException400
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public com.javaninja.cam.dto.Prospect com.javaninja.cam.spring.TestController.getResourceException400()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = com.javaninja.cam.exception.ResourceException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = {Content-Type=, Content-Length=[34]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Bad Request Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/resourceException404
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public com.javaninja.cam.dto.Prospect com.javaninja.cam.spring.TestController.getResourceException404()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = com.javaninja.cam.exception.ResourceException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = {Content-Type=, Content-Length=[32]}
     Content type = text/plain;charset=ISO-8859-1
             Body = Test Not Found Exception message
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /test/runtimeException
       Parameters = {}
          Headers = {}

Handler:
             Type = com.javaninja.cam.spring.TestController
           Method = public int com.javaninja.cam.spring.TestController.getRuntimeException()

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = java.lang.NumberFormatException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 500
    Error message = null
          Headers = {Content-Type=, Content-Length=[54]}
     Content type = text/plain;charset=ISO-8859-1
             Body = java.lang.NumberFormatException: For input string: "x"
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

Process finished with exit code 0

There you have it. A full Junit/MockMVC test harness that can be used to determine if a SpringMVC controller is returning the correct information when you are trying to map Exceptions into HTTP status codes, along with messages that can be returned with the client consumer.

November 16th, 2016

Posted In: Java, java ninja, Javaninja, JUnit, MockMVC, Spring, Spring MVC, Test Driven Development

Leave a Comment

In the original blog entry, Throwing exceptions with messages from a SpringMVC controller I set up a system to allow exceptions that would be thrown to cause an HTTP status code to be sent to the consumer with a message.

I needed to expand upon that to handle all of the exceptions that my Spring MVC controllers could encounter. To accomplish that, I created a class and annotated it with @ControllerAdvice. This allowed me to create a ExceptionHandlers for all of my controllers in one place.

I created three mappings because I wanted to handle the three types of exceptions a little differently than the others.

  • ResourceException – allows me to set a HTTP status and a message
  • RuntimeException – these are not typically created by developers I need to grab all of the information that I can. That is why I used the toString. That contains the name of the exception and the system specified message.
  • Exception – these are checked exceptions and are created by developers within their code. The expectation is that they put a meaningful message in the message property.

This was fairly easy to accomplish by having three different exception mappings. Within each exception mapping, I set the values in the ResponseEntity to display the appropriate HTTP status with a message in the content.

package com.javaninja.cam.spring;


import com.javaninja.cam.exception.ResourceException;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;


/**
 * Exception handler advice class for all SpringMVC controllers.
 * @author norrisshelton
 * @see ControllerAdvice
 */
@ControllerAdvice
public class CamControllerAdvice {

    /**
     * Returns whatever HTTP status was set within the ResourceException.  Uses the message that was set when
     * the ResourceException was created.
     * @param e SpringMVC controller exception.
     * @return http response entity
     * @see ExceptionHandler
     */
    @ExceptionHandler(ResourceException.class)
    public ResponseEntity handleResourceException(ResourceException e) {
        return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
    }

    /**
     * Sets the HTTP status as INTERNAL_SERVER_ERROR (500).  Uses the toString of the exception because
     * RuntimeExceptions don't always have enough usable information in the message property.
     * @param e SpringMVC controller exception.
     * @return http response entity
     * @see ExceptionHandler
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity handleRuntimeException(RuntimeException e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.toString());
    }

    /**
     * Sets the HTTP status as INTERNAL_SERVER_ERROR (500).  Uses the message property under the assumption that the
     * developer that created the exception set a meaningful explanation in the message property.
     * @param e SpringMVC controller exception.
     * @return http response entity
     * @see ExceptionHandler
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity handleException(Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
    }
}

November 16th, 2016

Posted In: Java, java ninja, Javaninja, Spring, Spring MVC

One Comment

The SpringFramework has a RestTemplate object that can be used to HTTP-based network calls. It doesn’t timeout by default, but there is functionality that can be configured. A RequestFactory must be created, then it needs to be wired into the RestTemplate.

The readTimeout and the connectionTimeout are both expressed in milliseconds.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd>
 
    <bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"
          p:readTimeout="250"
          p:connectTimeout="250"/>
 
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"
          c:requestFactory-ref="requestFactory"/>
</beans>

Once you have the RequestFactory configured, then the RestTemplate will begin to throw SocketTimeoutException and ConnectTimeoutException, depending on the problem. This is normally handled by catching RestClientException. This RuntimeException wraps all exceptions that are throws by the RestTemplate.

String response = null;
try {
    response = restTemplate.getForObject(url, String.class);
} catch (RestClientException e) {
    createOrderResponse.setStatus("failure");
    logger.error("Unable to get the PayNearMe barcode URL", e);
    //FIXME do something with the exception
    //throw e;
}

Catching the RestClientException is usually enough, because you only want to know that there is a problem. However, if you need to know the specific problem, you can test the RootCause for the specific type of exception.

String response = null;
try {
    response = restTemplate.getForObject(url, String.class);
} catch (RestClientException e) {
    createOrderResponse.setStatus("failure");
    if (e.getRootCause() instanceof SocketTimeoutException) {
        logger.error("SocketTimeoutException", e);
    } else if (e.getRootCause() instanceof ConnectTimeoutException) {
        logger.error("ConnectTimeoutException", e);
    } else {
        logger.error("Some other exception", e);
    }
    //FIXME do something with the exception
    //throw e;
}

September 13th, 2016

Posted In: Java, java ninja, Javaninja, Spring

Leave a Comment

I like to use SpringMVC for my JSON controllers. I do not prefer to return HTTP status codes other than 200, but sometimes you don’t have a choice. I was working on a project where the service would return the requested resource when it is available. If the resource is not found, then it is supposed to return an HTTP status of 404 with a messages. I thought this would be included right out of the box, but it wasn’t.

What Spring MVC offers and why it didn’t work

With Spring MVC, you have the ability to define an exception and have that exception return a specified HTTP status code when it reaches the controllers. Here is what an exception class would look like:

package com.twinspires.brisdataapi.bdsserver.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
 * @author norris.shelton
 */
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class NotFoundException  extends RuntimeException {
    /**
     * Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
     *                method.
     */
    public NotFoundException(String message) {
        super(message);
    }
}

This does provide a way to specify a message, but it doesn’t get displayed when a message is returned by the controllers. Ugh.

This would provide a good start, but I would need an exception handler to get the message. Unfortunately, all of the examples of the exception handlers show a method per exception.

Doing the least to make it work

This details the changes that I needed to make to allow the service to function correctly. I wanted to create as few classes as possible.

Define an exception

I created an exception that extends RuntimeException. I didn’t add a @ResponseStatus because I didn’t want to have to make an exception for each status code. I created a constructor that takes an HTTP status code and a message. This allows me to have one exception that I can reuse in all of my controllers and always return the correct status and message.

package com.twinspires.brisdataapi.bdsserver.exceptions;

import org.springframework.http.HttpStatus;

/**
 * @author norris.shelton
 */
@SuppressWarnings("ClassWithoutNoArgConstructor")
public class BdsServiceException extends RuntimeException {

    private HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    /**
     * Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
     *                method.
     */
    public BdsServiceException(HttpStatus httpStatus, String message) {
        super(message);
        this.httpStatus = httpStatus;
    }
}

Define SpringMVC exception handler

Now that I have an exception that has all of the information that I want returned to the caller of my service, I need to define an exception handler. It is the same type of exception handler that you normally see, except it returns a ResponseEntity. With the ResponseEntity, I can return the retrieve the correct status code and message from the exception and return them to the caller.

package com.twinspires.brisdataapi.bdsserver.spring;

import com.twinspires.brisdataapi.bdsserver.exceptions.BdsServiceException;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class ExceptionHandlerAdvice { 
 
    @ExceptionHandler(BdsServiceException.class)
    public ResponseEntity handleException(BdsServiceException e) {
        // log exception 
        return ResponseEntity.status(e.getHttpStatus()).body(e.getMessage());
    }         
} 

Putting it to use

All that is left is throwing the exception. I threw the exception with the desired HTTP status code and the message.

            throw new ResourceException(HttpStatus.NOT_FOUND, "We were unable to find the specified resource.");

June 22nd, 2016

Posted In: Java, java ninja, Javaninja, Spring, Spring MVC

Leave a Comment

Accessing properties via Spring is very easy. To read a properties file is very easy. This reads the given properties file from the file system and places the values in a map named rabbitConfiguration. It takes advantage of SpEl to get a system property and use that to resolve the file name.

<util:properties id="rabbitConfiguration" location="file:#{systemProperties.APP_CONFIG}/funding.properties"/>

My problems started when I tried to use the values from the properties file that contained periods. I tried to use them like:

    <bean id="rabbitConnectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory"
          c:hostname="#{rabbitConfiguration.vipre.host}"
          c:port="#{rabbitConfiguration.vipre.port}"
          p:username="#{rabbitConfiguration.vipre.user}"
          p:password="#{rabbitConfiguration.vipre.password}"/>

Spring did not like it. It thought that vipre was my property and host was something to be accessed off of it like an object. This is the exception that was thrown.

Caused by: org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 20): Property or field 'vipre' cannot be found on object of type 'java.util.Properties' - maybe not public?
	at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:164)
	at org.springframework.beans.factory.support.AbstractBeanFactory.evaluateBeanDefinitionString(AbstractBeanFactory.java:1365)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.doEvaluate(BeanDefinitionValueResolver.java:255)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.evaluate(BeanDefinitionValueResolver.java:228)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:204)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:648)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:140)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1137)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1040)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
	... 109 common frames omitted
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 20): Property or field 'vipre' cannot be found on object of type 'java.util.Properties' - maybe not public?
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:224)
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:94)
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:81)
	at org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:57)
	at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:87)
	at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:120)
	at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:242)
	at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:161)
	... 124 common frames omitted

I searched and searched around the internet trying to find a way to work around. I tried single-quotes, back-slashes, double-quotes, double-quotes and single-quotes together. Nothing seemed to work, then it hit me. To get around this, I approached the properties access via the array/bracket syntax (#{rabbitConfiguration[‘vipre.port’]}

    <bean id="rabbitConnectionFactory" class="org.springframework.amqp.rabbit.connection.CachingConnectionFactory"
          c:hostname="#{rabbitConfiguration['vipre.host']}"
          c:port="#{rabbitConfiguration['vipre.port']}"
          p:username="#{rabbitConfiguration['vipre.user']}"
          p:password="#{rabbitConfiguration['vipre.password']}"/>

May 31st, 2016

Posted In: Java, java ninja, Javaninja, SpEl, Spring

Leave a Comment

Spring provides the SimpleNamingContextBuilder to handle cases where the code that is tested needs a JNDI environment entry.

Steps to using a Spring SimpleNamingContextBuilder

Using the Spring SimpleNamingContextBuilder is fairly easy. There are basically three steps:

  1. Instantiate the variable
  2. Bind objects to their JNDI keys in the context builder (repeat as necessary)
  3. Activate the context builder

Full Example Utility

In my case, I only had to bind one thing, the full path to a file.

Here is the utility class that I built to hold the code.

package com.twinspires.cam;

import org.springframework.mock.jndi.SimpleNamingContextBuilder;

import javax.naming.NamingException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;

import static org.junit.Assert.fail;

/**
 * @author norris.shelton
 */
public class JunitTestUtility {

    /**
     * Performs environmental setup for Cam tests.
     * @throws NamingException if unable to activate the builder
     * @throws URISyntaxException if unable to find the properties file by a classloader
     */
    public static void setup() throws NamingException, URISyntaxException {
            String camPropertiesFile = "cam-test.properties";
        URL url = JunitTestUtility.class.getClassLoader().getResource(camPropertiesFile);
        if (url != null) {
            Path path = Paths.get(url.toURI());
            if (path != null) {
                SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
                builder.bind("cam.config.path", path.toString());
                builder.activate();
            }
        } else {
            fail("Unable to find cam-test.properties in src/test/resources");
        }
    }
}

How to reuse in a Junit test class

Once that is done, it is quite easy to reuse it. In my case, all of the test classes for a project needed that.

    @BeforeClass
    public static void setup() throws Exception {
        JunitTestUtility.setup();
    }

May 24th, 2016

Posted In: Java, java ninja, Javaninja, JUnit, Spring, TDD

Leave a Comment

Creating a thread pool within a web application is usually frowned upon. Why is that?

  • If you create your thread pool within the web application context, your pool will be competing for threads with your web application.
  • Another problem with creating your thread pool within the web application context is that you don’t know what assumptions the web container makes about what is available in the thread. It could be storing information related to security, etc on the thread.
  • Another problem with creating threads within the web application context is that those threads will respond to the web application shutdown. This may be counter to what you want to happen. Those threads may need to run to completion, regardless of the desire to shutdown the web application context.

Creating our Spring thread worker

Now that we know what not to do and why, let’s start with the right way to do this. The first thing is that we need to implement a bean to perform our work. There a couple of things that will need to be different from other generic beans.

  • The beans should be scope Prototype. Spring beans default to Singleton scope. That means that there is one bean per Spring container. When you are making worker threads, they should be scoped as prototype. That means that a new bean is created whenever one is requested.
  • The class should implement the Runnable interface. This dictates that a run method must be implemented. This method is called when the thread is started as a separately executing thread.

Here is an example thread worker. It is scoped Prototype and implements Runnable. It doesn’t do much, but waits a random amount of time to simulate asynchronous work. I added a field with a custom value and a little logging so we can see the workings of the threads via the logs.

package com.javaninja.spring.webmvc.threads;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.UUID;

/**
 * This class performs the work that is needed in the thread pool.
 * @author norris.shelton
 */
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ThreadWorker implements Runnable {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private String uniqueInfo;

    private List<String> data = new LinkedList<>();


    public void setUniqueInfo(String uniqueInfo) {
        this.uniqueInfo = uniqueInfo;
    }

    public List<String> getData() {
        return data;
    }


    /**
     * When an object implementing interface {@code Runnable} is used to create a thread, starting the thread
     * causes the object's {@code run} method to be called in that separately executing thread.
     * <p>
     * The general contract of the method {@code run} is that it may take any action whatsoever.
     * @see Thread#run()
     */
    @Override
    public void run() {
        logger.info("Started runner {}", uniqueInfo);

        try {
            int milliseconds = new Random().nextInt(10000);
            logger.info("{} sleeping for {} ms", uniqueInfo, milliseconds);
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            logger.error("Trouble with thread", e);
        }

        // simulating having results
        for (int i = 0; i < 5; i++) {
            data.add(UUID.randomUUID().toString());
        }

        logger.info("Runner {} finishing data={}", uniqueInfo, data);
    }

    /**
     * Returns a string representation of the object. In general, the {@code toString} method returns a string that
     * "textually represents" this object. The result should be a concise but informative representation that is easy
     * for a person to read. It is recommended that all subclasses override this method.
     * <p>
     * The {@code toString} method for class {@code Object} returns a string consisting of the name of the class of
     * which the object is an instance, the at-sign character `{@code @}', and the unsigned hexadecimal representation
     * of the hash code of the object. In other words, this method returns a string equal to the value of: <blockquote>
     * <pre>
     * getClass().getName() + '@' + Integer.toHexString(hashCode())
     * </pre> </blockquote>
     * @return a string representation of the object.
     */
    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this);
    }
}

Defining our Spring thread pool

Spring provides the ThreadPoolTaskExecutor class that takes out most of the difficulty. It provides some customization that proves to be extremely useful. Some of the settings are below:

  • corePoolSize – This is minimum pool size. The default value is 1.
  • maxPoolSize – This is the maximum pool size. the default is Integer.MAX_VALUE.
  • waitForTasksToCompleteOnShutdown – Should the pool wait for tasks to complete when the Spring container is shutdown. The default value is false.
  • awaitTerminationSeconds – How long should the Spring container wait for the pool to finish its tasks when the Spring container is told to shut down.

An example is below:

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
          p:corePoolSize="5"
          p:maxPoolSize="5"
          p:waitForTasksToCompleteOnShutdown="true"
          p:awaitTerminationSeconds="20"/>

Using a pool with fixed workers

Our first example will have a fixed number of worker threads. This is the simplest way to do it if you know you will always have a specific number of thread workers. The first thing to do to use the pool is get a reference to the TaskExecutor. Then inject the number of workers that we will need. Remember that these workers are all scoped Prototype to ensure that each can work completely independent of each other. I set a unique value into each thread worker and have each one of them sleep a random amount of time to help identify it while it is working. To start a worker we call the execute method on the thread pool with our worker as the method parameter.

package com.javaninja.spring.webmvc.threads;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.UUID;

/**
 * This is the code that controls the execution of a fixed number of worker threads.
 * @author norris.shelton
 */
@Service
public class FixedThreadService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    @Autowired
    private ThreadWorker worker1;

    @Autowired
    private ThreadWorker worker2;

    @Autowired
    private ThreadWorker worker3;

    @Autowired
    private ThreadWorker worker4;

    @Autowired
    private ThreadWorker worker5;

    public String withFixedThreads() {
        worker1.setUniqueInfo("1");
        taskExecutor.execute(worker1);

        worker2.setUniqueInfo("2");
        taskExecutor.execute(worker2);

        worker3.setUniqueInfo("3");
        taskExecutor.execute(worker3);

        worker4.setUniqueInfo("4");
        taskExecutor.execute(worker4);

        worker5.setUniqueInfo("5");
        taskExecutor.execute(worker5);

        return UUID.randomUUID().toString();
    }
}

Using a pool with dynamic workers

Sometimes we don’t know how many worker threads we will need until runtime. This requires a slightly different solution. We will need access to the Spring context to create as many workers as needed. Remember that the thread worker classes are scoped as Prototype. This means that each time we request a bean via getBean, that we are getting a totally new bean that will execute completely independent of any other thread worker bean. From there, the code is similar and will actually be shorter.

NOTE: to get the Spring context during the execution of the bean, you should implement ApplicationContextAware. This dictates that you have a setApplicationContext method. Once you have the context injected, you can use it however you need. To inject beans on demand, in our case.

package com.javaninja.spring.webmvc.threads;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.UUID;

/**
 * This is the code that controls the execution of a dynamic number of worker threads.
 * @author norris.shelton
 */
@Service
public class DynamicThreadService implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    /**
     * Set the ApplicationContext that this object runs in. Normally this call will be used to initialize the object.
     * <p>Invoked after population of normal bean properties but before an init callback such as {@link
     * InitializingBean#afterPropertiesSet()} or a custom init-method. Invoked after {@link
     * ResourceLoaderAware#setResourceLoader}, {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
     * {@link MessageSourceAware}, if applicable.
     * @param applicationContext the ApplicationContext object to be used by this object
     * @throws ApplicationContextException in case of context initialization errors
     * @throws BeansException              if thrown by application context methods
     * @see BeanInitializationException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public String withDynamicThreads(int threads) {

        ThreadWorker threadWorker = null;
        for (int i = 0; i < threads; i++) {
            threadWorker = applicationContext.getBean("threadWorker", ThreadWorker.class);
            threadWorker.setUniqueInfo(String.valueOf(i));
            taskExecutor.execute(threadWorker);
        }

        return UUID.randomUUID().toString();
    }
}

Running a pool with thread workers

The pool will run like normal. One thing to note is that we wanted our pool to continue processing, even if the server is requested to shut down. You can see by the logging that the threads continue to process. Success. The threads operate independent of the web application container and the Spring container.

INFO |Initializing ExecutorService  'taskExecutor' ||org.springframework.scheduling.concurrent.ExecutorConfigurationSupport:165 
INFO |Started runner 4 ||com.javaninja.spring.webmvc.threads.ThreadWorker:48 
INFO |Started runner 1 ||com.javaninja.spring.webmvc.threads.ThreadWorker:48 
INFO |Started runner 2 ||com.javaninja.spring.webmvc.threads.ThreadWorker:48 
INFO |Started runner 5 ||com.javaninja.spring.webmvc.threads.ThreadWorker:48 
INFO |Started runner 3 ||com.javaninja.spring.webmvc.threads.ThreadWorker:48 
INFO |4 sleeping for 8116 ms ||com.javaninja.spring.webmvc.threads.ThreadWorker:52 
INFO |1 sleeping for 586 ms ||com.javaninja.spring.webmvc.threads.ThreadWorker:52 
INFO |2 sleeping for 6754 ms ||com.javaninja.spring.webmvc.threads.ThreadWorker:52 
INFO |5 sleeping for 8060 ms ||com.javaninja.spring.webmvc.threads.ThreadWorker:52 
INFO |3 sleeping for 8841 ms ||com.javaninja.spring.webmvc.threads.ThreadWorker:52 
INFO |Closing org.springframework.context.support.GenericApplicationContext@491cc5c9: startup date [Tue May 10 10:01:27 EDT 2016]; root of context hierarchy ||org.springframework.context.support.AbstractApplicationContext:960 
INFO |Shutting down ExecutorService 'taskExecutor' ||org.springframework.scheduling.concurrent.ExecutorConfigurationSupport:203 
INFO |Runner 1 finishing data=[8aa9a123-5d0f-42d0-8be4-b703705a7a5c, 10de5358-5c7f-4881-9f9d-7706ea6ae8dd, 3f23f9c8-a594-4228-8a91-5eab26fb4d39, 6a52ec9c-82ec-4b88-bfdd-4b413291a8fe, d000aa8c-8c4d-4f6f-9dd5-c63c44431bcd] ||com.javaninja.spring.webmvc.threads.ThreadWorker:63 
INFO |Runner 2 finishing data=[cceed519-1cc9-4ce0-bdf4-02703f624853, 342f024c-c785-47a7-b4b4-aec261341fa7, 56c54700-37ac-41aa-89a2-3d1b4f92b6ed, 2ba81d54-d52b-4b4c-a26a-06996d25c2b9, c7a5e66c-b196-4936-a5aa-5ada8b416b7d] ||com.javaninja.spring.webmvc.threads.ThreadWorker:63 
INFO |Runner 5 finishing data=[159e842e-aaf8-4f86-9e01-1c814043943d, 59fa91bf-cd6a-4ad2-b7bd-8de85d5223f2, 360da0f9-91c8-4682-8d88-23a4f7327b98, a23824c5-f52a-426b-8c16-f5ec223c90cd, 0862d9a1-1635-4d15-8f7f-911877ac7165] ||com.javaninja.spring.webmvc.threads.ThreadWorker:63 
INFO |Runner 4 finishing data=[e26c4269-804c-4a6c-ae08-dc798e6f550c, 709bbf44-f480-4f32-834b-d5c8fc095b81, 807d311d-5a68-48b0-b2a6-cb74d596ee32, e4beeeeb-6628-4261-8a44-dc19a205c71a, a87c24b8-f693-4461-a54d-8a101fbc2a59] ||com.javaninja.spring.webmvc.threads.ThreadWorker:63 
INFO |Runner 3 finishing data=[389b2d85-4a64-4ea8-8b35-39480e027614, 5c85f6d0-a59e-4b7a-95be-e0ab9822e487, efb164c3-dc07-4a73-ae1f-c14c2f05ba08, 33a78ef4-8d67-4566-b20b-c74044012086, e75222f3-bf78-486f-b9e3-9b244f3237e3] ||com.javaninja.spring.webmvc.threads.ThreadWorker:63 

Process finished with exit code 0

Project files

The code for this project is in sheltonn / spring-web-threads

May 10th, 2016

Posted In: Java, java ninja, Javaninja, Spring

Leave a Comment

Next Page »
LinkedIn Auto Publish Powered By : XYZScripts.com