Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

This is an example of how to make a global exception handler. Our company had a need to work with an external vendor. They needed to get error states (person not found, account disabled, insufficient access, etc). These were mapped to various HTTP status codes and they wanted a JSON body with specific information in it. Springframework provides the ability to specify an exception handler that can process exceptions for multiple controllers.

The business logic was handled by creating Exception objects for each type of exception that was needed. Each custom exception had an empty constructor and a constructor that accepts the message. This is an example:

package com.javaninja.exception;

/**
 * Missing, invalid or expired token.
 */
public class AuthorizationException extends Exception {

    /**
     * Constructs a new exception with {@code null} as its detail message. The cause is not initialized, and may
     * subsequently be initialized by a call to {@link #initCause}.
     */
    public AuthorizationException() {
    }

    public AuthorizationException(String message) {
        super(message);
    }
}

Once you have the exceptions, you are ready to create something that can handle them. Springframework used to only support exception handlers that were within the individual controllers.

As of Spring MVC 3.2, they now support an exception handler that can handle exceptions for multiple controllers via @ControllerAdvice. This takes an optional property basePackages. The basepackages property allows you to set which packages this exception handler handles exceptions for. You can not specify it for the exception handler to apply to all controllers or you can list a package or multiple packages that are comma-separated.

An example of an exception handler that handles all packages is:

@ControllerAdvice
public class MyExceptionHandler {
    //...
}

An example of an exception handler that handles a single package is:

@ControllerAdvice(basePackages = "com.javaninja.services")
public class MyExceptionHandler {
    //...
}

An example of an exception handler that handles multiple packages is:

@ControllerAdvice(basePackages = "com.javaninja.services,com.javaninja.other")
public class MyExceptionHandler {
    //...
}

Now that you have a class that can handle exceptions, it’s time to get to work. To handle an exception, you annotate a method with @ExceptionHandler. There is an optional value property. You can specify one or more exceptions to handle. If you don’t list any exceptions, the exception handler will handle all exceptions.

An example from the Springframework documentation of an exception handler method that handles a single exception is:

@ExceptionHandler(IOException.class)
public ResponseEntity<String> handleIOException(IOException ex) {
// prepare responseEntity
return responseEntity;
}

An example that handles several exceptions is:

@ExceptionHandler(value = {IOException.class, SqlException.class})
public ResponseEntity<String> handleIOException(IOException ex) {
// prepare responseEntity
return responseEntity;
}

An example that handles all exceptions is:

@ExceptionHandler
public ResponseEntity<String> handleIOException(IOException ex) {
// prepare responseEntity
return responseEntity;
}

These methods returned a ResponseEntity. This offers you a tremendous amount of flexibility. Much more than I needed in my case.

If you are working on JSON services, you can use normal things like @ResponseBody to translate an object into it’s JSON representation.

    @ExceptionHandler(IOException.class)
    @ResponseBody
    public MyExceptionResponse handleThisException(Exception e) {
        return createResponse(e);
    }

Returning a certain HTTP status code after encountering an exception isn’t an uncommon thing. To do this, you use @ResponseStatus. There is a required value of HttpStatus type. An example is:

    @ExceptionHandler(IOException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public MyExceptionResponse handleThisException(Exception e) {
        return createResponse(e);
    }

Now, to bring this all together. This is an full example:

package com.javaninja.exception;

import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.validation.ConstraintViolationException;

/**
 * Handles exceptions for the Java Ninja.
 * @author norris.shelton
 */
@ControllerAdvice
public class ThisExceptionHandler {

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

    /**
     * Handle invalid request exceptions.
     * @param e exception object to be handled
     * @return exception response as a JSON body
     */
    @ExceptionHandler(ClassNotFoundException.class)
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ResponseBody
    public MyExceptionResponse handleBadRequestException(Exception e) {
        return createResponse(e);
    }

    /**
     * Handle authorization exceptions.
     * @param e exception object to be handled
     * @return exception response as a JSON body
     */
    @ExceptionHandler(value = {CGIServerException.class, AbandonedObjectException.class})
    @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public MyExceptionResponse handleAuthorizationException(Exception e) {
        return createResponse(e);
    }


    /*
     * Create the response body
     */

    /**
     * Create the response object.
     * @param e exception object to be handled
     * @return exception response object
     */
    private MyExceptionResponse createResponse(Exception e) {
        logger.info("{}  message: {}", e.getClass().getSimpleName(), e.getMessage());
        MyExceptionResponse exceptionResponse = new MyExceptionResponse(e.getClass().getSimpleName(),
                                                                        e.getMessage(),
                                                                        DateTime.now());
        logger.debug("exception response: {}", exceptionResponse);
        return exceptionResponse;
    }
}

When this exception handler encounters an exception, it returns a specific error code and the JSON payload appears similar to:

{
    "code": "TxnNotFoundException",
    "msg": "Unable to find the requested transaction",
    "timestamp": "2015-07-30 12:51:54"
}

July 30th, 2015

Posted In: Java, java ninja, Javaninja, Spring

Tags: , , ,

Leave a Comment

There are several times when you need to specify a location in a Springframework configuration. An example is

<util:properties id="gsiProperties" location="classpath:gaming-adapter-default.properties"/>

A location is represented as a Resource. There are several ways to specify where to find the resource.

  • classpath: This represents a resource that should be retrieved from the classpath. It works the way a normal classloader does. The first match wins. Package names can also be represented as file directories (e.g. /this/that/my.properties
  • classpath:* This means that ALL resources that match the given name must be obtained, then merged to form a single resource. Meaning multiple property files could be mapped to. The sum of them would be used to supply the properties.
  • file: This is used to access a file system resource. This can be an absolute path or relative path.
  • http: This is used to access resources via HTTP protocol with a URL.
  • ftp: this is used to access a resource via FTP protocol.
  • blank This relies upon the implementation of the underlying context. For web applications, this utilizes the Servlet context.

July 28th, 2015

Posted In: java ninja, Javaninja, Spring

Tags: , , , , ,

Leave a Comment

A common problem is to retrieve a property from a property files and to use that value within your code. The Springframework has several tools that make that very easy to do.

The first thing to do is to create your properties file. Mine contains the following:

aggregatorId=gsi
igpUrl=http://localhost:8080/igp-services
defaultSupplierId=voi

Next, you need to make Spring aware of the properties file. To do this, we will use the util schema. Line 4 shows that the properties has an id value. This allows us to later use that idid.key, instead of key.

xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
...
<util:properties id="gsiProperties" location="gaming-adapter-default.properties"/>

Now that you have the properties available to Spring, it’s time to use them. Notice that we are using Spring Expression Language (SpEl) to inject the value(…) of the key. Normally, I would use @Autowired or @Resource(name=”…”) to inject the properties object as a map, then call get(…) on the map. SpEl gives you an additional notational choice to inject the data. @value(…) can be placed on fields, methods, method parameters and constructor parameters. Inside the @value, you can use #{…}. You do not need # for predefined variables (e.g. @value({systemProperties.property})). If the property cannot be listed directly because it contains a period, etc, you can place it within square brackets with a single tick. An example is @Value(#{systemProperties[‘user.region’]}).

    @Value("#{gsiProperties.igpUrl}")
    private String igpUrl;

    @Value("#{gsiProperties.aggregatorId}")
    private String aggregatorId;

    @Value("#{gsiProperties.defaultSupplierId}")
    private String defaultSupplierId;
...
    model.setIdAggregator(aggregatorId);
    model.setIdGameSupplier(defaultSupplierId);

July 23rd, 2015

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

Tags: , , , ,

Leave a Comment

The usual usage of a Springframework RestTemplate is to get back an object. Sometimes the object will contain a list. What needs to happen when you need to get back a list of Strings? RestTemplate accepts a parameter that tells it what the data it receives will be put in. I used a String array. It converts the JSON object into a String[] and away I go.

                    String[] pokerTableNames =
                        restTemplate.getForObject(pokerSettingsService.getValueByName(PokerSettings.IGP_ADAPTER_URL) + "/poker/tableNames",
                            String[].class);

February 20th, 2015

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

Tags: , , , , , , ,

Leave a Comment

Using the Springframework RestTemplate is usually fairly straight forward. In this case, it didn’t work. I had a URL that would work when I pasted it into the web browser and would also work in the Chrome Advanced Rest Client. Each time I tried to call it with a Spring Rest Template, I got a HTTP 406.

    /**
     * Gets the poker client content objects from dotCMS.
     * @return poker clients model object
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public PokerClientsModel getPokerClients() throws InvocationTargetException, IllegalAccessException {

        String url = settingRepository.findSettingByIdSetting(SettingEnum.HOST_URL.key()).getValue() +
            "/api/content/render/false/query/+structureName:PokerClient%20+" +
            "(conhost:915f2552-793a-4f17-96d0-f0955fcc698f%20conhost:SYSTEM_HOST)" +
            "%20+languageId:1*%20+deleted:false%20%20+working:true/orderby/modDate%20desc";

        DotCmsPokerClientResponse dotCmsPokerClientResponse = restTemplate.getForObject(url,
                                                                                        DotCmsPokerClientResponse.class);
        PokerClientsModel pokerClientsModel = new PokerClientsModel();
        PokerClient pokerClient;
        for (DotCmsPokerClient dotCmsPokerClient : dotCmsPokerClientResponse.getDotCmsPokerClients()) {
            pokerClient = new PokerClient();
            BeanUtils.copyProperties(pokerClient, dotCmsPokerClient);
            pokerClientsModel.getPokerClients().add(pokerClient);
        }

        return pokerClientsModel;

    }

That just plain didn’t work.

Method threw 'org.springframework.web.client.HttpClientErrorException' exception.
406
Not Acceptable

 size = 8
UTF-8
406 Not Acceptable
org.springframework.web.client.HttpClientErrorException: 406 Not Acceptable

 size = 0

I thought about what the browser could be sending that I wasn’t. It hit me that the browser may be sending the content type as text/plain. It is a bit of a pain in the rear-end to send a content type on a get request. I eventually got to set the content type by using the Http Entity.

    /**
     * Gets the poker client content objects from dotCMS.
     * @return poker clients model object
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public PokerClientsModel getPokerClients() throws InvocationTargetException, IllegalAccessException {

        String url = settingRepository.findSettingByIdSetting(SettingEnum.HOST_URL.key()).getValue() +
            "/api/content/render/false/query/+structureName:PokerClient%20+" +
            "(conhost:915f2552-793a-4f17-96d0-f0955fcc698f%20conhost:SYSTEM_HOST)" +
            "%20+languageId:1*%20+deleted:false%20%20+working:true/orderby/modDate%20desc";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.TEXT_PLAIN);

        HttpEntity entity = new HttpEntity(headers);
        HttpEntity<String> dotCmsPokerClientResponse = restTemplate.exchange(url,
                                                                             HttpMethod.GET,
                                                                             entity,
                                                                             String.class);
        return pokerClientsModel;
    }

This did work better. No more HTTP 406, but the return object contained a blank contentlets array.

<200 OK,{"contentlets":[]},{Date=[Mon, 02 Feb 2015 15:26:09 GMT], Server=[Apache-Coyote/1.1], Content-Type=, Set-Cookie=[JSESSIONID=8CDC0C67730932FAEBBB729FBA5E2BBA; Path=/, ROUTEID=.1; path=/], Vary=[Accept-Encoding], Keep-Alive=[timeout=5, max=100], Connection=[Keep-Alive], Transfer-Encoding=[chunked]}>

Frustration set in and I was starting to get desperate. I got the idea of using HttpClient directly to make the call.

    /**
     * Gets the poker client content objects from dotCMS.
     * @return poker clients model object
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public PokerClientsModel getPokerClients() throws InvocationTargetException, IllegalAccessException {

        String url = settingRepository.findSettingByIdSetting(SettingEnum.HOST_URL.key()).getValue() +
            "/api/content/render/false/query/+structureName:PokerClient%20+" +
            "(conhost:915f2552-793a-4f17-96d0-f0955fcc698f%20conhost:SYSTEM_HOST)" +
            "%20+languageId:1*%20+deleted:false%20%20+working:true/orderby/modDate%20desc";

        return get(url);
    }

    /**
     * Performs a HTTP get of the specified URL.
     * @param url the desired URL.
     * @return Http response body as a string
     */
    protected String get(String url) {
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String responseBody = null;
        try {
            responseBody = httpClient.execute(httpGet, responseHandler);
        } catch (IOException e) {
            logger.error("IOException", e);
        } finally {
            // When HttpClient instance is no longer needed,
            // shut down the connection manager to ensure
            // immediate deallocation of all system resources
            httpClient.getConnectionManager().shutdown();
        }
        return responseBody;
    }

Success!!!!!

{"contentlets":[{"stInode":"d5af8654-aa65-4f2f-b2cd-bc6bf54753d5","owner":"norris.shelton","lastReview":"2015-01-30 16:21:56.226","modUser":"norris.shelton","identifier":"42ee0e8c-bd3c-4bae-ac51-b7837dc8e832","version":"000.000.000","clientType":"android","sortOrder":0,"modDate":"2015-01-30 16:21:56.238","host":"915f2552-793a-4f17-96d0-f0955fcc698f","whatsNew":"Initial Android Version","languageId":1,"inode":"ef33dbd6-2e47-44f7-a47f-daaa5c52e74b","folder":"SYSTEM_FOLDER"},{"stInode":"d5af8654-aa65-4f2f-b2cd-bc6bf54753d5","owner":"norris.shelton","lastReview":"2015-01-30 16:21:41.265","modUser":"norris.shelton","identifier":"b670a674-fb54-425a-93b8-432c8443e02d","version":"000.000.000","clientType":"ios","sortOrder":0,"modDate":"2015-01-30 16:21:41.278","host":"915f2552-793a-4f17-96d0-f0955fcc698f","whatsNew":"Initial IOS version","languageId":1,"inode":"929fb049-1c85-4376-bc9f-143981466a0a","folder":"SYSTEM_FOLDER"},{"stInode":"d5af8654-aa65-4f2f-b2cd-bc6bf54753d5","owner":"norris.shelton","lastReview":"2015-01-30 16:21:29.787","modUser":"norris.shelton","identifier":"df0ce56f-8e43-4169-9632-eb05fddd442f","version":"000.000.000","clientType":"flash","sortOrder":0,"modDate":"2015-01-30 16:21:29.8","host":"915f2552-793a-4f17-96d0-f0955fcc698f","whatsNew":"Initial Flash version","languageId":1,"inode":"8ff7fe3f-8064-42cf-8d9a-eaf6f65b52f9","folder":"SYSTEM_FOLDER"}]}

February 2nd, 2015

Posted In: Java, java ninja, Javaninja

Tags: , , , , , , , ,

Leave a Comment

In a previous post, I talked about Spring P-notation.  In this blog post, I will give an example of the Spring C-notation for constructor arguments.

The C-notation namespace needs to be added to your configuration file.

xmlns:c="http://www.springframework.org/schema/c"

All that is left is to use it for a constructor argument

<?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:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/task    http://www.springframework.org/schema/task/spring-task.xsd
                           http://www.springframework.org/schema/util    http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- removed unnecessary configurations -->

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

December 29th, 2014

Posted In: Java

Tags: , , , , , , , , ,

Leave a Comment

Springframework P-notation was made to make creating spring config files a little neater and shorter. Here is what a typical file would look like.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc     http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/util    http://www.springframework.org/schema/util/spring-util.xsd">

    <context:component-scan base-package="com.cdi.rng"/>
    <mvc:annotation-driven/>

    <util:constant id="mediaTypeJson" static-field="org.springframework.http.MediaType.APPLICATION_JSON"/>

    <bean id="contentNegotiatingViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    </bean>
    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="defaultContentType" ref="mediaTypeJson"/>
    </bean>

</beans>

Here is what it looks like once the P-notation is used.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:util="http://www.springframework.org/schema/util"
       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
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc     http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/util    http://www.springframework.org/schema/util/spring-util.xsd">

    <context:component-scan base-package="com.cdi.rng"/>
    <mvc:annotation-driven/>
    <util:constant id="mediaTypeJson" static-field="org.springframework.http.MediaType.APPLICATION_JSON"/>

    <bean id="contentNegotiatingViewResolver" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
          p:contentNegotiationManager-ref="contentNegotiationManager"/>
    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"
          p:defaultContentType-ref="mediaTypeJson"/>

</beans>

Springframework P-notation does not add capability, but does reduce the number of characters needed to define the Spring context.

December 8th, 2014

Posted In: Spring

Tags: , , , , , ,

One Comment

I had a Springframework-enabled JUnit test that I needed to run multiple times. I thought there used to be a JUnit annotation, but I couldn’t find it. I found and used the Spring @Repeat annotation.

package com.this.and.that;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;

import java.util.concurrent.LinkedBlockingQueue;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners(DependencyInjectionTestExecutionListener.class)
@ContextConfiguration
public class TestCardSet {

    @Repeat(10)
    @Test
    public void testGetShuffledCardQueue() throws Exception {
        LinkedBlockingQueue<Card> cards = CardSet.getShuffledCardQueue();
        assertNotNull(cards);
        assertEquals(52, cards.size());
    }
}

I used to set breakpoints to verify that the test was being ran multiple times. The Spring @Repeat annotation removed the need for this by adding logging.

2014-12-02 09:41:05,499 INFO  o.s.beans.factory.xml.XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [com/iteam/poker/server/model/game/cards/TestCardSet-context.xml]
2014-12-02 09:41:05,815 INFO  o.s.context.support.GenericApplicationContext:510 - Refreshing org.springframework.context.support.GenericApplicationContext@4c6cea8a: startup date [Tue Dec 02 09:41:05 EST 2014]; root of context hierarchy
2014-12-02 09:41:05,866 INFO  o.s.b.factory.support.DefaultListableBeanFactory:598 - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6f7503eb: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
2014-12-02 09:41:05,886 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 1 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,898 INFO  c.i.poker.server.shuffle.SecureShuffleAlgorithm:26 - Cards shuffle algorithm seed has been initialized.
2014-12-02 09:41:05,899 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 2 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,900 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 3 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,901 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 4 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,902 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 5 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,903 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 6 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,903 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 7 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,904 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 8 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,905 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 9 of test TestCardSet#testGetShuffledCardQueue()
2014-12-02 09:41:05,906 INFO  o.s.test.context.junit4.statements.SpringRepeat:69 - Repetition 10 of test TestCardSet#testGetShuffledCardQueue()

Process finished with exit code 0

December 2nd, 2014

Posted In: JUnit, Spring, Test Driven Development, Unit Tests

Tags: , , , , ,

One Comment

I have a normal Springframework-enabled project arranged as a Maven project. There were already JUnit tests in the project, along with the requisite Spring configuration.

I needed to add Cucumber tests to the project. I started by adding a cucumber directory to my src/test/java and src/test/resources directories.

I added my feature file in ../src/test/resources/com/cdi/igs/adapter/cucumber/features/Login.feature.

Feature: Login

  @2014w34 @US2422
  Scenario Outline: A lite registered player with email verified should be able submit username and password in the poker client.
  After submission player will see a system message to complete registration and will get re-direct to complete registration step 2 in IGP

    Given my username is "<UserName>"
    And my password is "<Password>"
    And my registration status is "lit"
    And my email verification status is verified as "<email verification status>"
    When I provide my credentials
    Then I should receive the following Poker status "<login result>"
  Examples:
    | UserName | Password   | login result            |email verification status|
    | player1  | Password#1 | AUTH_FAILED_LIT         | 1                       |
  @2014w34 @US2326
  Scenario Outline: A fully registered user should be able to login into the existing poker client. User in examples must be a fully registered user. 0 = SUCCESS, 1 = AUTH_FAILED

    Given my username is "<UserName>"
    And my password is "<Password>"
    And my registration status is "ful"
    When I provide my credentials
    Then I should receive the following Poker status "<Login Result>"
    And I should receive the following demographic data "<First Name>" "<Last Name>" "<Address1>" "<Address2>" "<City>" "<State>" "<Zip>"
    And I should have a third party authentication token

  Examples:
    | UserName | Password   | Login Result | First Name | Last Name | Address1          | Address2 | City     | State | Zip   |
    | player2  | Password#1 | SUCCESS      | Player     | Test      | 1505 Test Address | Apt 100  | New York | NY    | 80000 |


  @2014w34 @US2538
  Scenario Outline: A lite registered user  whose email is not verified will be shown the relevant messaging, and they will be requested to become fully registered
    Given my username is "<UserName>"
    And my password is "<Password>"
    And my registration status is "lit"
    And my email verification status is verified as "<email verification status>"
    When I provide my credentials
    Then I should receive the following Poker status "<login result>"

  Examples:
    | UserName    | Password        |email verification status  | login result             |
    | 8player     | Password!#01    |0                          | AUTH_FAILED_LIT_NO_EMAIL |


  @2014w36 @US2639
  Scenario Outline: Player with existing Password locked status with IGP authentication, cannot login to poker client.

    Given my username is "<UserName>"
    And my password is "<Password>"
    And my person status is "psl"
    When I provide my credentials
    Then I should receive the following Poker status "<login result>"

  Examples:
    | UserName | Password     | login result              |
    | gawky1  | Password#1    | LOCKED_PASSWORD_RESET     |

  @2014w36 @US2629
  Scenario Outline: Player with existing Reset locked status with IGP authentication, cannot login to poker client.

    Given my username is "<UserName>"
    And my password is "<Password>"
    And my person status is "rsl"
    When I provide my credentials
    Then I should receive the following Poker status "<login result>"

  Examples:
    | UserName  | Password      | login result                  |
    | gawky     | Password#1    | LOCKED_CUSTOMER_SERVICE_RESET |

I added my steps file that defines the implementations in …/src/test/java/com/cdi/igs/adapter/cucumber/steps/LoginSteps.java.

package com.cdi.igs.adapter.cucumber.steps;

import com.cdi.igs.adapter.login.LoginRequest;
import com.cdi.igs.adapter.login.LoginResponse;
import com.cdi.igs.adapter.poker.login.PokerLoginService;
import com.cdi.igs.dao.person.Person;
import com.cdi.igs.dao.person.PersonRepository;
import com.cdi.igs.dao.personhasverifiableitem.PersonHasVerifiableItem;
import com.cdi.igs.dao.personhasverifiableitem.PersonHasVerifiableItemRepository;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

/**
 * Login cucumber steps.
 * @author norris.shelton
 */
@ContextConfiguration("classpath:TestCucumber-context.xml")
public class LoginSteps {
    @Autowired
    private PersonRepository        personRepository;
    @Autowired
    private PersonHasVerifiableItemRepository personHasVerifiableItemRepository;
    @Autowired
    private PokerLoginService       pokerLoginService;


    private String     username;
    private String     password;
    private Person     person;
    LoginResponse loginResponse;

    @Given("^my username is "([^"]*)"$")
    public void my_username_is(String username) throws Throwable {
        this.username = username;
    }


    @And("^my password is "([^"]*)"$")
    public void my_password_is(String password) throws Throwable {
        this.password = password;
    }

    @Given("^my registration status is "(.*?)"$")
    public void my_registration_status_is(String registrationStatus) throws Throwable {
        person = personRepository.findByUserName(username);
        assertEquals(registrationStatus, person.getIdRegistrationStatus());
    }



    @Then("^I should receive the following Poker status "(.*?)"$")
    public void i_should_receive_the_following_Poker_status(String responseStatus) throws Throwable {
        assertEquals(responseStatus, loginResponse.getStatus().value());
    }

    @Given("^my email verification status is verified as "(.*?)"$")
    public void my_email_verification_status_is_verified_as(String emailVerificationStatus) throws Throwable {
     List<PersonHasVerifiableItem> personHasVerifiableItemList =
             personHasVerifiableItemRepository.findByIdPersonAndIdVerifiableItemOrderByTimeStampDesc(person.getIdPerson(), "ema");
        if (!personHasVerifiableItemList.isEmpty()) {
            for (PersonHasVerifiableItem emailVerifiableItem : personHasVerifiableItemList) {
                if (emailVerifiableItem.isSuccess()) {
                    assertEquals(person.getIdPerson(),emailVerifiableItem.getIdPerson());
                    break;
                }
            }
        }
    }

    @Given("^my person status is "(.*?)"$")
    public void my_person_status_is(String personStatus) throws Throwable {
        person = personRepository.findByUserName(username);
        assertEquals(personStatus, person.getIdPersonStatus());
    }

    @When("^I provide my credentials$")
    public void I_provide_my_credentials() throws Throwable {
        LoginRequest loginRequest = new LoginRequest();
        loginRequest.setUserId(username);
        loginRequest.setPassword(password);
        loginResponse = pokerLoginService.login(loginRequest);
    }

    @And(
        "^I should receive the following demographic data "([^"]*)" "([^"]*)" "([^"]*)" "([^"]*)" "" +
        "([^"]*)" "([^"]*)" "([^"]*)"$")
    public void I_should_receive_the_following_demographic_data(String firstName,
                                                                String lastName,
                                                                String address1,
                                                                String address2,
                                                                String city,
                                                                String state,
                                                                String zip)
    throws Throwable {
        assertEquals(firstName, StringUtils.trimToEmpty(loginResponse.getFirstName()));
        assertEquals(lastName, StringUtils.trimToEmpty(loginResponse.getLastName()));
        assertEquals(address1, StringUtils.trimToEmpty(loginResponse.getStreetAddress1()));
        assertEquals(address2, StringUtils.trimToEmpty(loginResponse.getStreetAddress2()));
        assertEquals(city, StringUtils.trimToEmpty(loginResponse.getCity()));
        assertEquals(state, StringUtils.trimToEmpty(loginResponse.getIdState()));
        assertEquals(zip, StringUtils.trimToEmpty(loginResponse.getZipCode()));
    }

    @And("^I should have a third party authentication token$")
    public void I_should_have_a_third_party_authentication_token() throws Throwable {
        assertNotNull(StringUtils.trimToNull(loginResponse.getThirdPartyAuthenticationToken()));
    }
}

Now that I have the feature and the steps created, I added in the Cucumber runner in
…/src/test/java/com/cdi/igs/adapter/cucumber/TestCucumber.java. Notice the glue property of @CucumberOptions. That defines directories to scan.

package com.cdi.igs.adapter.cucumber;</code>

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;

/**
* JUnit test class for cucumber.
* @author norris.shelton
*/
@RunWith(Cucumber.class)
@CucumberOptions(
tags = {},
glue = {"com.cdi.igs.adapter.cucumber", "cucumber.api.spring"})
public class TestCucumber {
}

In the top of the LoginSteps class, there was a ContextConfiguration annotation.

@ContextConfiguration("classpath:TestCucumber-context.xml")

That Spring context config file is located in …/src/test/resources/TestCucumber-context.xml and thee contents of that are as follows:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath*:TestAdapter-context.xml"/>
</beans>

It merely says use whatever Spring configuration has already been defined for the rest of the project.

November 20th, 2014

Posted In: Cucumber, Integration Tests, Java, JUnit, Spring, TDD, Test Driven Development, Unit Tests

Tags: , , , , , , , , ,

8 Comments

Springframework provides lots of ways to inject values into your code. What do you do when you need access to a value of something contained in a .properties file. This is so easy, but I rarely use it and always forget how to use it. This is how you define a properties:

<util:properties id="commonProperties" location="classpath:common-dev.properties"/>

The contents of the properties file is:

hostUrl=my.host.com

To inject it into a class:

    @Value("#{commonProperties.hostUrl}")
    private String hostUrl;

March 14th, 2014

Posted In: Java, Spring

Tags: , ,

Leave a Comment

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