Java Ninja Chronicles By Norris Shelton

Things I learned in the pursuit of code

Web developers were used to using cookies to store data in the user’s browser. You could then set how long you wanted the cookie to last. It could automatically be removed when the browser was closed or it could last longer. Overtime, cookies got a bad rap. There was also a relatively small size limitation.

HTML5 started a move away from cookies and to web storage. There are two types of web storage, sessionStorage and localStorage. Both of them use the same API signature, meaning that once you have an example of localStorage working, you also know how to access sessionStorage.

If they are both accessed the same way, then what is the difference? LocalStorage persists across browser sessions. You can think of it as persistent storage. LocalStorage is per origin Origin is defined as the protocol (e.g. http, https, etc), hostname and port number (e.g. 80, 443, 8080). This means that all of the pages from your website that are HTTPS can see the data set by another window, but the HTTP pages cannot see the data. This also means that if you are using multiple host names, you can’t share data across your domains.

SessionStorage has a shorter lifespan. It is intended for as long as the browser window is open. When the browser window is closed, this data is removed. Whereas localStorage is origin specific, sessionStorage is origin-window specific. Meaning, that even for the same domain, etc, the data is specific to the window that wrote it. This is something that cookies couldn’t support on their own. Any data that is written in sessionStorage is only visible by the window that wrote it.

Let’s look at how to use the web storage API. LocalStorage and sessionStorage are both accessed by global variables that are named after the type of storage, localStorage and sessionStorage. Meaning, that they are on the current window object (e.g. window.localStorage and window.sessionStorage). My examples will use localStorage, but the examples are the same for sessionStorage. In general, browsers allow up to 5MB to be stored. Much larger than the cookie size limit.

Does this browser support web storage

How do we determine if a browser supports localStorage? I saw two different ways. With that said, most browsers support web storage. IE8, FF 3.5, Chrome 4, Safari 4, Android 2.0, Chrome on Android 44.

        /**
         * Does this browser support HTML5 Local Storage.
         * @returns {boolean}
         */
        function supportsHtml5Storage() {
            try {
                return 'localStorage' in window && window['localStorage'] != null;
            } catch (e) {
                return false;
            }
        }

        /**
         * An alternative way to determine if a browser supports local storage.
         * @returns {boolean}
         */
        function supportsHtml5StorageAlternate() {
            return typeof(Storage) !== "undefined";
        }

Modernizer also has a method to determine if localStorage is supported.

// In FF4, if disabled, window.localStorage should === null.

// Normally, we could not test that directly and need to do a
//   `('localStorage' in window) && ` test first because otherwise Firefox will
//   throw bugzil.la/365772 if cookies are disabled

// Also in iOS5 & Safari Private Browsing mode, attempting to use localStorage.setItem
// will throw the exception:
//   QUOTA_EXCEEDED_ERRROR DOM Exception 22.
// Peculiarly, getItem and removeItem calls do not throw.

// Because we are forced to try/catch this, we'll go aggressive.

// Just FWIW: IE8 Compat mode supports these features completely:
//   www.quirksmode.org/dom/html5.html
// But IE8 doesn't support either with local files

Modernizr.addTest('localstorage', function() {
    var mod = 'modernizr';
    try {
        localStorage.setItem(mod, mod);
        localStorage.removeItem(mod);
        return true;
    } catch(e) {
        return false;
    }
});

How to write data

The data is stored in a key-value pair map. The value of the data is stored as a string. If you need it to be an integer, etc you will need to convert it to the value type that you need. The data is written by calling setItem. The example shows setting a value that is a string and an integer. Regardless, the value ends up as a string.

        /**
         * Sets a couple of items to local storage.
         */
        function setLocalStorageItem() {
            localStorage.setItem("foo", "bar");
            localStorage.setItem("max", 5);
        }

How to read data

Data is retrieved by calling the getItem method. Remember that the data comes back as a string and needs to be converted. Below are both examples. If the data was ‘5’, then retrieving the value of ‘5’ and adding 1 to it will result in ’51’ if you don’t convert the value to an integer. The value will be 6 if you convert it to an int, then add.

        /**
         * Gets an item from local storage.
         */
        function getLocalStorageAsString() {
            return localStorage.getItem("max") + 1;
        }

        /**
         * Gets an item from local storage.
         */
        function getLocalStorageAsNumber() {
            // local storage items are stored as a string
            return parseInt(localStorage.getItem("max")) + 1;
        }

How to remove data

Like most maps, there is the ability to remove an item from the map. However, unlike some other implementations, calling removeItem doesn’t return a value to indicate if it existed before it was removed.

        /**
         * Removes an item from local storage
         */
        function removeLocalStorage() {
            // removeItem does NOT return a value like Java does
            localStorage.removeItem("foo");
        }

There is also the option to remove all of the data that is in storage. This is accomplished by calling clear. I could not get this to work on Firefox 40.0.2.

        /**
         * Clear the contents of local storage.
         */
        function clearLocalStorage() {
            // clear did not work on FireFox 40.0.2
            localStorage.clear();
        }

How to query web storage for it’s contents

There is also the ability to get the number of items being stored in the local storage.

        /**
         * Gets the number of items in Local Storage.
         * @returns {number}
         */
        function getLocalStorageLength() {
            return localStorage.length;
        }

Once you have the number of items in a map, you can iterate over the items, get the key, then use the key to get the value.

        /**
         * Displays the contents of local storage.
         * @returns {string}
         */
        function displayLocalStorageContents() {
            var contents = "";
            var key = "";
            var value = "";
            for (var i = 0; i < localStorage.length; i++) {
                key = localStorage.key(i);
                value= localStorage.getItem(key);
                contents += "index=" + i + "\tkey=" + key + "\nvalue=" + value + "\n"
            }
            return contents;
        }

How to listen for storage events

Sometimes you will have the need to know that the storage has been changed. This will be especially useful if you are trying to coordinate the activities of multiple windows. You register an event listener by calling addEventListener, then implementing the a method to respond to the storage events. I didn’t see consistent behavior on this. I could call setItem, getItem and removeItem. I never got it to fire. I was able to make it fire in Chrome by manually changing the storage value. As of right now, the various browser implementations don’t seem to allow this to be of much use.

        /**
         * Register a local storage event listener.
         */
        function registerEventListener() {
            if (window.addEventListener) {
                addEventListener("storage", handleStorageEvent, false);
            }
        }

        /**
         * Handle the storage event.
         */
        function handleStorageEvent(storageEvent) {
            if (!storageEvent) {
                storageEvent = window.event;
            }
            alert("key=" + storageEvent.key +
                  " oldValue=" + storageEvent.oldValue +
                  " newValue=" + storageEvent.newValue +
                  " url=" + storageEvent.url);

        }

The entire file of examples

Here is the entire html file.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Java Ninja Local Storage prototype</title>
</head>
<body>
    <button onclick="alert(supportsHtml5Storage())">Local Storage Supported</button>
    <button onclick="alert(supportsHtml5StorageAlternate())">Local Storage Supported (alt)</button>
    <button onclick="registerEventListener()">Local Storage register listener</button>
    <button onclick="alert(getLocalStorageLength())">LocalStorage length</button>
    <button onclick="alert(displayLocalStorageContents())">LocalStorage contents</button>
    <button onclick="setLocalStorageItem()">LocalStorage set</button>
    <button onclick="alert(getLocalStorageAsString())">LocalStorage get as string</button>
    <button onclick="alert(getLocalStorageAsNumber())">LocalStorage get as number</button>
    <button onclick="removeLocalStorage()">LocalStorage remove foo</button>
    <button onclick="clearLocalStorage()">LocalStorage clear</button>

    <script>
        /**
         * Does this browser support HTML5 Local Storage.
         * @returns {boolean}
         */
        function supportsHtml5Storage() {
            try {
                return 'localStorage' in window && window['localStorage'] != null;
            } catch (e) {
                return false;
            }
        }

        /**
         * An alternative way to determine if a browser supports local storage.
         * @returns {boolean}
         */
        function supportsHtml5StorageAlternate() {
            return typeof(Storage) !== "undefined";
        }

        /**
         * Register a local storage event listener.
         */
        function registerEventListener() {
            if (window.addEventListener) {
                addEventListener("storage", handleStorageEvent, false);
            }
        }

        /**
         * Handle the storage event.
         */
        function handleStorageEvent(storageEvent) {
            if (!storageEvent) {
                storageEvent = window.event;
            }
            alert("key=" + storageEvent.key +
                  " oldValue=" + storageEvent.oldValue +
                  " newValue=" + storageEvent.newValue +
                  " url=" + storageEvent.url);

        }

        /**
         * Gets the number of items in Local Storage.
         * @returns {number}
         */
        function getLocalStorageLength() {
            return localStorage.length;
        }

        /**
         * Displays the contents of local storage.
         * @returns {string}
         */
        function displayLocalStorageContents() {
            var contents = "";
            var key = "";
            var value = "";
            for (var i = 0; i < localStorage.length; i++) {
                key = localStorage.key(i);
                value= localStorage.getItem(key);
                contents += "index=" + i + "\tkey=" + key + "\nvalue=" + value + "\n"
            }
            return contents;
        }

        /**
         * Sets a couple of items to local storage.
         */
        function setLocalStorageItem() {
            localStorage.setItem("foo", "bar");
            localStorage.setItem("max", 5);
        }

        /**
         * Gets an item from local storage.
         */
        function getLocalStorageAsString() {
            return localStorage.getItem("max") + 1;
        }

        /**
         * Gets an item from local storage.
         */
        function getLocalStorageAsNumber() {
            // local storage items are stored as a string
            return parseInt(localStorage.getItem("max")) + 1;
        }

        /**
         * Removes an item from local storage
         */
        function removeLocalStorage() {
            // removeItem does NOT return a value like Java does
            localStorage.removeItem("foo");
        }

        /**
         * Clear the contents of local storage.
         */
        function clearLocalStorage() {
            // clear did not work on FireFox 40.0.2
            localStorage.clear();
        }
    </script>
</body>
</html>

August 24th, 2015

Posted In: HTML, HTML5, java ninja, Javaninja, javascript

Tags: ,

Leave a Comment

We had a need to have a Cucumber example that tested several different steps in one pass. We then needed to make several different passes across the tests with different data elements. We had been using Examples before, but this took it to a whole new level. We defined a datatable for each step with variables that then were retrieved from a main examples datatable that had all of the data for all of the steps for this run.

The feature files looks like:

Feature: Logging in to play for real and fun money and retrieve player wallet

  @2015r16.3 @US5064
  Scenario Outline: Full register player can launch a casino game to play for real or fun money. In this scenario in the
  back end the player launch a game for real or fun (demo) the we auth the player and retrieve the wallet

    Given I am a fully registered user
    And I am authenticated
    Then I want to create an ACH account at the time of deposit with following details:
      | Routing Number             | <routing_number>   |
      | Account Nickname           | <account_nickname> |
      | Deposit Amount             | <deposit_amount>   |
      | Account Type               | <account_type>     |
      | Agree Terms And Conditions | <agree_t_and_c>    |
    Then my account balance is correct
      | Cash Balance | <deposit_amount> |
    When I get a game launch Url
      | External Game ID | <game_id_external> |
      | Aggregator ID    | <id_aggregator>    |
      | Game Mode        | <game_mode>        |
    And I am authenticated via the remote game server
      | Authorization Status | <auth_status> |
    Then the game should retrieve the wallet and verify the cash balance
      | Cash Balance | <deposit_amount> |
    Then I play the game
      | First Wager Amount        | <firstWagerAmount>       |
      | First Win Amount          | <firstWinAmount>         |
      | First Ending Cash Balance | <firstEndingCashBalance> |
    Then I play the game
      | Second Wager Amount        | <secondWagerAmount>       |
      | Second Win Amount          | <secondWinAmount>         |
      | Second Ending Cash Balance | <secondEndingCashBalance> |
    Then I cleanup the gaming records

    Examples:
      | routing_number | account_nickname | deposit_amount | account_type | agree_t_and_c | game_id_external | id_aggregator | game_mode | auth_status | firstWagerAmount | firstWinAmount | firstEndingCashBalance |
      | 011000015      | MyNewACHAccount  | 95             | chk          | true          | aris50Dragons    | gsi           | DEMO      | SUCCESS     | 10               | 0              | 85                     |
      | 011000015      | MyNewACHAccount  | 95             | chk          | true          | aris50Dragons    | gsi           | REAL      | SUCCESS     | 10               | 0              | 85                     |
      | 011000015      | MyNewACHAccount  | 95             | chk          | true          | aris50Lions      | gsi           | REAL      | SUCCESS     | 10               | 0              | 85                     |
      | 011000015      | MyNewACHAccount  | 95             | chk          | true          | aris50Lions      | gsi           | DEMO      | SUCCESS     | 10               | 0              | 85                     |

Let’s look at the step

Then I want to create an ACH account at the time of deposit with following details:

The datatable contains the following data. Think of the elements on the left as the keys in a map and the elements on the right as the corresponding values.

      | Routing Number             | <routing_number>   |
      | Account Nickname           | <account_nickname> |
      | Deposit Amount             | <deposit_amount>   |
      | Account Type               | <account_type>     |
      | Agree Terms And Conditions | <agree_t_and_c>    |

In this case, the corresponding values are within < and >. This tells Cucumber to look up the actual value in the Examples: datatable.

    Examples:
      | routing_number | account_nickname | deposit_amount | account_type | agree_t_and_c | game_id_external | id_aggregator | game_mode | auth_status | firstWagerAmount | firstWinAmount | firstEndingCashBalance |
      | 011000015      | MyNewACHAccount  | 95             | chk          | true          | aris50Dragons    | gsi           | DEMO      | SUCCESS     | 10               | 0              | 85                     |
      | 011000015      | MyNewACHAccount  | 95             | chk          | true          | aris50Dragons    | gsi           | REAL      | SUCCESS     | 10               | 0              | 85                     |
      | 011000015      | MyNewACHAccount  | 95             | chk          | true          | aris50Lions      | gsi           | REAL      | SUCCESS     | 10               | 0              | 85                     |
      | 011000015      | MyNewACHAccount  | 95             | chk          | true          | aris50Lions      | gsi           | DEMO      | SUCCESS     | 10               | 0              | 85                     |

For our examples test, we are going to send a map containing the following key/value data:

  • Routing Number -> 011000015
  • Account Nickname -> MyNewACHAccount
  • Deposit Amount -> 95
  • Account Type -> chk
  • Agree Terms and Conditions -> true

Now for the nitty gritty. This is what the step definition looks like:

    @Given("^I want to create an ACH account at the time of deposit with following details:$")
    public void I_want_to_create_an_ACH_account_at_the_time_of_deposit_with_following_details(Map<String, String> tableData) throws Throwable {
        assertTrue(tableData.containsKey("Routing Number"));
        assertTrue(tableData.containsKey("Account Nickname"));
        assertTrue(tableData.containsKey("Deposit Amount"));
        assertTrue(tableData.containsKey("Account Type"));
        assertTrue(tableData.containsKey("Agree Terms And Conditions"));


        achCashierModel.setRoute(tableData.get("Routing Number"));
        achCashierModel.setLabel(tableData.get("Account Nickname"));
        achCashierModel.setAcceptedTerms("true".equals(tableData.get("Agree Terms And Conditions")));
        achCashierModel.setIdAchType(tableData.get("Account Type"));
        achCashierModel.setTransactionAmountString(tableData.get("Deposit Amount"));

        // do some testing stuff
    }

The method takes Map tableData as the method parameter. From here on, you can access it like a regular map. In this case, the first thing the step does is verify that the correct input values were specified. To use them, a normal map.get() is called.

That’s for a single pass through the tests. Notice, that in our Examples: table, we have four rows of data. What this means is that there are 4 whole tests of data. In my feature file in my IDE, the rows of data are on lines 37, 38, 39 and 40. Here is the kind of data is produced.

Feature: CasinoGame: 28 total, 28 passed 51.51 s
    Feature: Logging in to play for real and fun money and retrieve player wallet
        Scenario Outline: Full register player can launch a casino game to play for real or fun money. In this scenario in the
            Examples:
                Scenario: Line: 37
                    Given I am a fully registered user -- passed
                    And I am authenticated -- passed
                    Then I want to create an ACH account at the time of deposit with the following details: -- passed
                    Then my account balance is correct -- passed
                    When I get a game launch Url -- passed
                    And I am authenticated via the remote game server -- passed
                    Then the game should retrieve the wallet and verify the cash balance -- passed
                Scenario: Line: 38
                    Given I am a fully registered user -- passed
                    And I am authenticated -- passed
                    Then I want to create an ACH account at the time of deposit with the following details: -- passed
                    Then my account balance is correct -- passed
                    When I get a game launch Url -- passed
                    And I am authenticated via the remote game server -- passed
                    Then the game should retrieve the wallet and verify the cash balance -- passed
                Scenario: Line: 39
                    Given I am a fully registered user -- passed
                    And I am authenticated -- passed
                    Then I want to create an ACH account at the time of deposit with the following details: -- passed
                    Then my account balance is correct -- passed
                    When I get a game launch Url -- passed
                    And I am authenticated via the remote game server -- passed
                    Then the game should retrieve the wallet and verify the cash balance -- passed
                Scenario: Line: 40
                    Given I am a fully registered user -- passed
                    And I am authenticated -- passed
                    Then I want to create an ACH account at the time of deposit with the following details: -- passed
                    Then my account balance is correct -- passed
                    When I get a game launch Url -- passed
                    And I am authenticated via the remote game server -- passed
                    Then the game should retrieve the wallet and verify the cash balance -- passed


August 21st, 2015

Posted In: Cucumber, Java, java ninja, Javaninja

Tags:

Leave a Comment

We’ve all had this happen. There is a large model that is being converted to JSON, but only a few fields are populated. The result looks something like this

{
    "modelStatus": "ERROR",
    "message": null,
    "messages": [
    ],
    "previousPage": null,
    "nextPage": null,
    "redirect": false,
    "errors": [
    ],
    "errorFields": [
    ],
    "exception": null,
    "ssoToken": null,
    "bossUser": null,
    "idGame": 6067,
    "idAccount": 0,
    "currency": null,
    "language": null,
    "rgsCode": "aristocrat",
    "rgsGameId": "aris50Dragons",
    "tokenType": null,
    "tokenTtl": 0,
    "tokenModelAsJsonString": null,
    "channel": "pc",
    "clientType": "flash",
    "mode": "REAL",
    "clientUrl": "http://***URL with parameters removed***",
    "method": "GET",
    "contentType": null,
    "body": null,
    "status": "ERROR"
}

Jackson 2.0 (e.g. FasterXML) offers an annotation that can be used to tune the behavior of the JSON serializer. This is accomplished by placing a @JsonInclude annotation at the top of the model. There are several options.

NON_NULL can be used to tell FasterXML to not send any elements that are null.

@JsonInclude(JsonInclude.Include.NON_NULL)

This results in the same response appearing like…

{
    "modelStatus": "ERROR",
    "messages": [
    ],
    "redirect": false,
    "errors": [
    ],
    "errorFields": [
    ],
    "idGame": 6067,
    "idAccount": 0,
    "rgsCode": "aristocrat",
    "rgsGameId": "aris50Dragons",
    "tokenTtl": 0,
    "channel": "pc",
    "clientType": "flash",
    "mode": "REAL",
    "clientUrl": "http://***URL with parameters removed***",
    "method": "GET",
    "status": "ERROR"
}

Notice that there are several empty arrays. These can also be removed by specifying that only NON_EMPTY items are sent. To determine if something sould be included in the JSON, several methods are used:

  • null objects are not included
  • Collections and Maps – isEmpty() is called. The item is included if this returns false
  • Arrays – the length must be > than 0 for the array to be included
  • String – the length() is called. The string is included if the value is greater than 0.

This is accomplished by

@JsonInclude(JsonInclude.Include.NON_EMPTY)

August 21st, 2015

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

Leave a Comment

Copying isn’t as straightforward as a copy or a pull request.

  1. Create the new repository – I used the GitHub to create a new repository that was available to others in my organization.
  2. Then push the source repository to the destination repository via the command line. git push –mirror https://github.com/exampleuser/new-repository.git

There you have it. You can then use the GitHub UI and you will see the files from the original project in the new project. At this point, you can clone it, etc and you have ready to code away.

August 18th, 2015

Posted In: Git, GitHub, java ninja, Javaninja

Leave a Comment

I have been using Logback for a while. It’s pretty easy to use and it’s fairly easy to configure. I noticed that I had some warning messages in my log file.

10:51:04,532 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
10:51:04,532 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
10:51:04,532 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/Users/norrisshelton/IdeaProjects/gsi-adapter/gsi-adapter-services/target/gsi-services/WEB-INF/classes/logback.xml]
10:51:04,578 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
10:51:04,586 |-INFO in ReconfigureOnChangeFilter{invocationCounter=0} - Will scan for changes in [[/Users/norrisshelton/IdeaProjects/gsi-adapter/gsi-adapter-services/target/gsi-services/WEB-INF/classes/logback.xml]] every 60 seconds. 
10:51:04,586 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Adding ReconfigureOnChangeFilter as a turbo filter
10:51:04,589 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
10:51:04,593 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
10:51:04,649 |-WARN in ch.qos.logback.core.ConsoleAppender[STDOUT] - This appender no longer admits a layout as a sub-component, set an encoder instead.
10:51:04,649 |-WARN in ch.qos.logback.core.ConsoleAppender[STDOUT] - To ensure compatibility, wrapping your layout in LayoutWrappingEncoder.
10:51:04,649 |-WARN in ch.qos.logback.core.ConsoleAppender[STDOUT] - See also http://logback.qos.ch/codes.html#layoutInsteadOfEncoder for details
10:51:04,650 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [com.cdi] to DEBUG
10:51:04,650 |-INFO in ch.qos.logback.classic.joran.action.LoggerAction - Setting level of logger [org.springframework.web.client.RestTemplate] to DEBUG
10:51:04,650 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to WARN
10:51:04,650 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]
10:51:04,651 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
10:51:04,652 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@c28ccfa - Registering current configuration as safe fallback point

I checked and discovered that the logging configuration had changed. An example is it used to look like:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS}|%-5level|${HOSTNAME}|cdi-services|%msg ||%class:%line %xException{full} %n</Pattern>
        </layout>
    </appender>

    <logger name="com.cdi" level="DEBUG"/>
    <!-- Show info on rest calls -->
    <logger name="org.springframework.web.client.RestTemplate" level="DEBUG"/>

    <root level="WARN">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

I was getting messages about layout should be wrapped in an encoder. After some tinkering, I arrived at the following:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
        <encoder>
            <pattern>%d{HH:mm:ss.SSS}|%-5level|${HOSTNAME}|cdi-services|%msg ||%class:%line %xException{full} %n</pattern>
        </encoder>
    </appender>

    <logger name="com.cdi" level="DEBUG"/>
    <!-- Show info on rest calls -->
    <logger name="org.springframework.web.client.RestTemplate" level="DEBUG"/>

    <root level="WARN">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

The gist of it is that the appender now has an encoder instead of a layout. When the correct changes are made to the configuration file, there is no longer any start-up logging from LogBack in the logs, but you will see that the new logging format is being honored.

A little note is that I leave a space after msg% to help with the wrapping when the lines are too long.

|%msg |

August 11th, 2015

Posted In: Java, java ninja, Javaninja, logback, Logging, Logging configuration

Leave a Comment

Streams, functional programming and Lambda expressions have opened up a whole new world of syntax for the Java language. The old forEach has new competition.

An example of a normal forEach of a list of objects was:

for (MyModel myModel : myModelList) {
    System.out.println(myModel);
}

This can be replaced with .forEach and the code gets much smaller.

myModelList.forEach(System.out::println);

One common thing to do with a forEach is to iterate over a set of data and pick and choose which objects should be added to another list.
An example of a forEach that filters a list is:

List<GameModel> externalGames = new LinkedList<>();
for (GameModel myModel : gameList) {
    if ("external".equals(myModel.getIdGameExternal())) {
        externalGames.add(myModel);
    }
}

This is when it gets fun. We can use .filter and .collect to transform this into the following. The .filter contains all of the logic that you would have had in an if statement. The .collect contains the processing necessary to convert the stream to a LinkedList.

externalGames = gameList.stream()
                        .filter(myModel -> "external".equals(myModel.getIdGameExternal()))
                        .collect(Collectors.toCollection(LinkedList::new));

Sometimes you need just one element from a list. Here is what a typical forEach loop looks like that filters a list down and then we get a reference to the first object in the list.

List<GameModel> externalGames = new LinkedList<>();
for (GameModel myModel : gameList) {
    if ("external".equals(myModel.getIdGameExternal())) {
        externalGames.add(myModel);
    }
}
gameModel1 = externalGames.get(0);

We can easily do the same thing using streams. In this case, I filter like before, then grab the first element. We pull out .findFirst to retrieve the first element of the stream, then use .get to make that object available.

gameModel1 = gameList.stream()
                     .filter(myModel -> "external".equals(myModel.getIdGameExternal()))
                     .findFirst()
                     .get();

August 6th, 2015

Posted In: Collections, Java, java ninja, Javaninja

Tags: , , , , ,

Leave a Comment

We normally use @Transactional to declaratively control transactions. Sometimes, that doesn’t quite give us the flexibility we need. I had a case where I needed the ability to write data to a database within a transaction, but I couldn’t use an exception to indicate a rollback was necessary because there was information within the method that I would need. Specifically, I needed the information related to the failure. In order for this to work. I had to use a Springframework TransactionTemplate. Like most Spring Template objects, it’s fairly easy to use. Note that an exception will cause an automatic rollback, just like the normal transactional processing.

First, you need to declare the TransactionManager and the TransactionTemplate. In this case, my transaction manager gets it’s database connection from an EntityManagerFactory because I am using JPA.

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
          p:entityManagerFactory-ref="entityManagerFactory"/>

    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"
          p:transactionManager-ref="transactionManager"/>

Once the TransactionTemplate is declared, it can be injected like any other spring bean.

    @Autowired
    private TransactionTemplate transactionTemplate;

A TransactionTemplate exposes it’s functionality via a callback method. One implementation does not have a return type and the other has a return type that can be expressed as a generic.

Here is an example of using the callback method that doesn’t have a return type. This is implemented by implementing an anonymous inner-class of type TransactionCallbackWithoutResult. This is an abstract class with one method, doInTransactionWithoutResult. The TransactionStatus object is used to rollback the transaction. This is caused by calling setRollbackOnly().

transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
        // do this
        // do that
        // if some sort of state exists
        status.setRollbackOnly();;
        // }
    }
});

If you need to return data from inside the callback method, then use the TransactionCallback. This works like the other callback method, but allows a value to be returned. Note that the Boolean return type is a generic and can be specified as whatever you need it to be.

boolean returnValue = transactionTemplate.execute(new TransactionCallback<Boolean>() {
    @Override
    public Boolean doInTransaction(TransactionStatus status) {
        // do this
        // do that
        // if some sort of state exists
        status.setRollbackOnly();
        // }
        return myObject.getMyBoolean();
    }
});

If you need a return value and you are on JDK8, you can use a Lambda expression to make the code even smaller.

boolean returnValue = transactionTemplate.execute(status -> {
    // do this
    // do that
    // if some sort of state exists
    status.setRollbackOnly();
    // }
    return null;
});

August 5th, 2015

Posted In: Java, java ninja, Javaninja, Spring

Tags: , , , , ,

Leave a Comment

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

Intellij IDEA doesn’t show hidden files in the file chooser dialog on Mac OS/X. This can be frustrating when you are trying to find files that are always in a hidden directory, such as Maven files. There are two ways around this.

This will enable it for the current window

ctrl + shift + .

There is another solution, but it involves editing the registry. Hit the following keys to access the Find Action menu.

cmd + shift + a

Once there, scroll down to ide.mac.file.chooser.show.hidden.files. Check the checkbox and select Close and away you go.

July 28th, 2015

Posted In: IntelliJ, java ninja, Javaninja, Mac, OS/X

Tags: , , ,

Leave a Comment

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