Iterating through Java list backwards

The most natural method of iterating through a list in Java is to start from the first element of the list and then move forward until the last one is reached. While this is the most common, it is sometimes necessary to do it otherwise – start from the last element and move in reverse direction. In this post I would like to show 4 different ways to do it easily.

This short class creates a simple list and calls 4 methods to print it in reverse order:

package com.example.iteratelistreverse;

import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.apache.commons.collections.iterators.ReverseListIterator;

public class Main {

    public static void main(String[] args) throws IOException {
        List<String> list = new ArrayList<>();
        list.add("First");
        list.add("Second");
        list.add("Third");
        list.add("Fourth");
        list.add("Fifth");

        iterateIndexedAccess(list);
        iterateListIterator(list);
        iterateReverseListIterator(list);
        iterateListsReverse(list);
    }

    private static void iterateIndexedAccess(List<String> list) {
        System.out.print("\nFor loop with random access:\n");
        for (int i = list.size() - 1; i >= 0; i--) {
            System.out.println(list.get(i));
        }
    }

    private static void iterateListIterator(List<String> list) {
        System.out.print("\nList iterator:\n");
        ListIterator<String> it = list.listIterator(list.size());
        while (it.hasPrevious()) {
            System.out.println(it.previous());
        }
    }

    private static void iterateReverseListIterator(List<String> list) {
        System.out.print("\nApache ReverseListIterator:\n");
        Iterator<String> it = new ReverseListIterator(list);
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }

    private static void iterateListsReverse(List<String> list) {
        System.out.print("\nGuava List.reverse:\n");
        for (String v : Lists.reverse(list)) {
            System.out.println(v);
        }
    }

}

Method iterateIndexedAccess() shows the most common solution. In this method we are using the indexed access to the elements of the list which is very easy and obvious. It has also very good performance assuming that the instance of the list supports fast random access. It is the case for very popular ArrayList class.

However, other classes may not support fast random access. One of the examples is LinkedList class. For every List.get() method call this class has to iterate from the beginning (or alternatively from the end) of the list to find the element at given index which makes it very slow for large lists.

Method iterateListIterator() overcomes this problem by using a list iterator which can move forward and backward using ListIterator.next() and ListIterator.previous() calls respectively. In our example we are starting from the position after the last element and are moving to the previous element on every loop iteration.

Method iterateReverseListIterator() is quite specific because it creates an iterator which pretends that it is normal iterator (forward iterator). In fact it starts from the last element of the list and moves to the previous one on every call to Iterator.next() method. This solution uses ReverseListIterator class from Apache Commons library.

The last way uses method Lists.reverse() from Guava library to create a reversed view of the given list. Once we have the view, which is in fact instance of Iterable interface, we can go over it using enhanced loop.

As usual you can find the source code of this example at GitHub.

Posted in Guava, Java | Tagged , | 1 Comment

Usage of serialVersionUID in Java serialization

Java run-time associates with each serializable class a special version number known as serialVersionUID. This number is later used during deserialization process to verify if the application which performed the serialization and the application which is doing the deserialization have loaded and use compatible Java classes (with respect to serialization). If the receiver has loaded a class which has the same name but different serialVersionUID, the Java run-time will report a problem by throwing an exception of type InvalidClassException.

Generally speaking this kind of mechanism allows us to detect and report any compatibility problems during deserialization process as early as possible. If this check was missing, the deserialization process would likely finish without raising any exception but the created object would contain invalid data. This can easily lead to unpredictable behavior and can later cause errors which root cause is hard to track.

Defining serialVersionUID

A serializable class can specify its own serialVersionUID value explicitly by declaring a static, final field of name serialVersionUID and of type long:

private static final long serialVersionUID = 4038305141805077716L;

The access modifier does not really matter but private is commonly used.

If serial version is not explicitly declared, it will be automatically generated by compiler and stored in the class file. The compiler calculates default serialVersionUID value based on several aspects of the class like its name, its all public and protected members and so on.

The default serialVersionUID calculation may vary between compilers so it may give different results in different environments. To ensure a consistent serialVersionUID value, it is strongly recommended to explicitly declare its value.

Many IDE for Java have a feature which detects if the class should declare serialVersionUID and can report it as a warning. In case of the Eclipse the warning is following:

The serializable class Person does not declare a static final serialVersionUID field of type long

Adding serialVersionUID to existing classes

If you create a new class, you can choose any arbitrary value for its serialVersionUID because there are no serialized objects of this class yet stored anywhere.

However, if you already have an old class to which you would like to add explicit serial version value, you have be careful. The best idea is to choose a value which would be automatically generated by the compiler.

Oracle JDK provides a program serialver which shows the following basic window when started with -show option from command line:
serialver
When you enter a full name of the existing class and click Show button, it will output its default generated serialVersionUID below. You can just copy-paste this line into Java class file.

Additionally, Eclipse provides a nice context tool which can simplify adding serialVersionUID:

serialver-eclipse

Managing explicit serialVersionUID

The serialVersionUID represents a class version and has to be managed. If you make a change to the existing class which makes it incompatible with the previous version (e.g. changing base class, modifying the types of the fields or removing fields), it is also necessary to modify (e.g. increment) its serialVersionUID value.

On the other hand, adding new fields to the class does not necessarily make it incompatible. Additionally, you may manage to keep the class backward compatible by customizing serialization procedure using readObject() and writeObject() methods.

Example

Let’s consider a simple application serializing and deserializing objects of Person class:

package com.example.serialversionuid;

import java.io.Serializable;

public class Person implements Serializable {
    private static final long serialVersionUID = 4038305141805077716L;
	
    private String firstName;
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "Person{" + "firstName=" + firstName + ", lastName=" + lastName + '}';
    }
    
}

with the main class:

package com.example.serialversionuid;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Main {
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        if (args.length != 2) {
            System.err.println("Usage: serialversionuid read|write FILE");
            return;
        }
        final String operation = args[0];
        final String file = args[1];
        
        
        if (operation.equals("read")) {
            try (ObjectInputStream is = new ObjectInputStream(new FileInputStream(file))) {
                Person person = (Person) is.readObject();
                System.out.println("Read person: " + person);
            }
        } else if (operation.equals("write")) {
            Person person = new Person("James", "Bond");
            try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file))) {
                os.writeObject(person);
            }
        }
    }
    
}

When the serialVersionUID is unchanged we can serialize and deserialize objects of Person class without problems:

$ java -jar serialversionuid-1.0-SNAPSHOT.jar write data.ser
$ java -jar serialversionuid-1.0-SNAPSHOT.jar read data.ser
Read person: Person{firstName=James, lastName=Bond}

However, if you change serialVersionUID in Person class, rebuild the jar file and try to read data.ser file again, the InvalidClassException exception appears:

$ java -jar serialversionuid-1.0-SNAPSHOT.jar read data.ser
Exception in thread "main" java.io.InvalidClassException: com.example.serialversionuid.Person; local class incompatible: stream classdesc serialVersionUID = 4038305141805077716, local class serialVersionUID = 4038305141805077717
        at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:617)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1622)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
        at com.example.serialversionuid.Main.main(Main.java:22)

As you can easily notice, the Java run-time reports incompatibility between classes used to serialize data and deserialize it later.

Conclusion

Field serialVersionUID is often forgotten and ignored. In most cases not declaring it does not cause any problems. However, if your application exchanges serialized objects over network with another applications or stores serialized data on disk for long time, the importance of proper management of serialVersionUID becomes crucial.

The source code for the example is available at GitHub.

Posted in Java | Tagged | Leave a comment

Creating executable jar file with Maven

Building an executable jar file with maven-jar-plugin is fairly easy. However, it has one disadvantage that the Maven dependencies are not packaged together inside the resulting jar file but have to be stored separately on the file system and added to the class path. Often it is not an issue but sometimes you may want to create a single self-contained jar file which does not depend on anything external. Below you can find an example how to do it.

Consider we have a very simple application with main method:

package com.example.runnablejar;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.codec.digest.DigestUtils;

public class Main {
    
    public static void main(String[] args) throws IOException  {
        if (args.length == 0) {
            System.err.println("Usage: cryptohash file1 ...");
            return;
        }
        
        for (String arg : args) {
            Path file = Paths.get(arg);
            calculateSha256CommonsIO2(file);
        }
    }
        
    private static void calculateSha256CommonsIO2(Path path) throws IOException {
        try (InputStream is = Files.newInputStream(path)) {
            String hashString = DigestUtils.sha256Hex(is);
            System.out.printf("SHA256(%s) = %s%n", path, hashString);
        }
    }

}

This application uses Apache Commons Codec library which is distributed as a separate jar file. Storing this jar file inside our application jar file would not work because it would not be present on the class path.

To overcome this issue we can use maven-assembly-plugin in POM file:

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>runnablejar</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>runnablejar</name>

    <build>
        <plugins>      
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>           
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.5.2</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <appendAssemblyId>false</appendAssemblyId>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                            <archive>
                                <manifest>
                                    <mainClass>com.example.runnablejar.Main</mainClass>
                                </manifest>
                            </archive>
                        </configuration>
                    </execution>
                </executions>
            </plugin>        
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.9</version>
            <type>jar</type>
        </dependency>
    </dependencies>
</project>

Looking from the high level perspective the Apache Commons Codec jar will be merged together with our application jar and the new MANIFEST.MF file will be added:

$ jar tf runnablejar-1.0-SNAPSHOT.jar 
META-INF/
META-INF/MANIFEST.MF
(...)
org/apache/commons/codec/digest/DigestUtils.class
(...)
com/
com/example/
com/example/runnablejar/
com/example/runnablejar/Main.class
(...)

The final application can be run using following command:

$ java -jar runnablejar-1.0-SNAPSHOT.jar

without manually downloading any dependencies and without configuring class path.

As usual you can find the source code of the example at GitHub.

Posted in Java, Maven | Tagged , | 3 Comments

Customizing HTML file input style

Styling an HTML file input control is very cumbersome and the number of available options is quite limited. Moreover, each web browser renders this control differently which makes it difficult to have consistent view of the application between browsers. Here is how the HTML file input looks in Mozilla Firefox:
file-input-img0

In most cases it is impossible to style the HTML file input control with CSS to obtain the wanted results. One of the easiest ways to overcome this issue is to place the HTML file input control visually on top of the other element (e.g. image or button) and make the HTML file input control transparent by setting opacity to zero. Because the HTML file input is on top, it will receive the click event and will open the dialog for choosing the file.

No JavaScript code is necessary, only HTML:

<div class="file-input-container">
   <div>Upload</div>
   <input id="file-input1" type="file"></input>
</div>

and a bit of CSS:

.file-input-container {
  position: relative;
  width: 10em;
  height: 2em;
 
  background: #8ac007;
  border: 2px solid black;
}

.file-input-container > div {
  text-align: center;
  margin-top: 0.5em;
}

.file-input-container > input {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
   
  filter: alpha(opacity=0);
  opacity: 0;
}

After the change the button for choosing the file will look more or less like this:
file-input-img1

The provided example is easy to tune. For example you can completely remove child div element and set the background CSS property on parent div.

Posted in HTML | Tagged , | Leave a comment

Primary key generation in JPA

Generation of primary key values is a very important functionality of relational database management systems. The main idea is to let RDBMS automatically calculate and assign primary key value to the row being inserted into the database table. This not only simplifies the source code of the application using database but also makes the application more robust. There are two widely known methods to perform the generation of primary key values on the database level: auto-increment/identity columns or sequences.

Due to these differences JPA provide three different ways to automatically generate primary key values. Let’s explore them below.

Using auto-increment/identity columns

MySQL and Microsoft SQL Server provide a functionality to automatically generate a unique number for the primary key when a new row is added into a table. For example, in MySQL it is done by marking primary key column with AUTO_INCREMENT keyword:

CREATE TABLE JPAGEN_ADDRESS
(
  ID INT PRIMARY KEY AUTO_INCREMENT,
  CITY VARCHAR(255) NOT NULL,
  STREET VARCHAR(255) NOT NULL
);

and in Microsoft SQL Server with IDENTITY keyword:

CREATE TABLE JPAGEN_ADDRESS
(
    ID INT IDENTITY(1,1) PRIMARY KEY,
    CITY VARCHAR(255) NOT NULL,
    STREET VARCHAR(255) NOT NULL
);

JPA must be informed to use auto-increment/identity for primary key by specifying IDENTITY generation strategy on the ID column:

@Entity
@Table(name = "JPAGEN_ADDRESS")
public class Address implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    // other fields and methods are omitted 
}

Now, when a new Address entity is persisted, the value of the primary key column will be automatically generated by the database.

Using sequences

Oracle Database and PostgreSQL use explicit sequence type to generate unique primary key numbers. For example, in Oracle Database the table and its sequence can be defined like this:

CREATE TABLE JPAGEN_ADDRESS
(
    ID NUMBER PRIMARY KEY,
    CITY VARCHAR(255) NOT NULL,
    STREET VARCHAR(255) NOT NULL
);
CREATE SEQUENCE JPAGEN_ADDRESS_SEQ START WITH 100;

When using sequence for given entity, the SEQUENCE strategy must be defined on its ID column and additionally the name of the sequence must be specified using @SequenceGenerator annotation:

@Entity
@Table(name = "JPAGEN_ADDRESS")
public class Address implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
            generator = "addressGen")
    @SequenceGenerator(name = "addressGen",
            sequenceName = "JPAGEN_ADDRESS_SEQ")
    private long id;

    // other fields and methods are omitted 
}

When a new Address entity is persisted, JPA implementation will obtain the next value of the sequence and use it to insert a new row into the database table.

Using table

The third method to generate primary keys is to have a separate table which stores in a single row the sequence name along with the next number to use for the primary key. For performance reasons the next value is not increased by one, whenever JPA implementation needs a new value for the primary key but by a much higher number (e.g. 50). Once the range of values becomes reserved, JPA implementation can assign primary keys without accessing the database. When every value in the range becomes used, JPA implementation reserves a new range and the cycle continues.

Additionally, in such table we can have multiple rows with each row serving different entity. The only requirement is to use unique sequence names for each entity.

The table strategy is the most complicated one but it is the only strategy that is really portable across different databases. If you are developing an application which can use multiple RDBMS or there may be a need to port to a new RDBMS in the future, using table strategy is the most viable option.

The table to store the Person entity and the table to generate sequences can be created like this:

CREATE TABLE JPAGEN_PERSON
(
    ID NUMBER PRIMARY KEY,
    NAME VARCHAR(255) NOT NULL,
    ADDRESS_ID NUMBER
);
CREATE TABLE JPAGEN_GENERATORS
(
    NAME VARCHAR(255) PRIMARY KEY,
    VALUE NUMBER
);

The table with sequences must have two columns. The first one should contain the name of the sequence and the second one should be of numeric type. JPA implementation will automatically update the second column when reserving a new range of values.

Additionally, JPA must be instructed to use TABLE generation strategy:

@Entity
@Table(name = "JPAGEN_PERSON")
public class Person implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE,
            generator = "personGen")
    @TableGenerator(name = "personGen",
            table = "JPAGEN_GENERATORS",
            pkColumnName = "NAME",
            pkColumnValue = "JPAGEN_PERSON_GEN",
            valueColumnName = "VALUE")
    private long id;

    // other fields and methods are omitted 
}

We also have to add @TableGenerator annotation to inform JPA about the name of the generator table (table element), the names of its both columns (pkColumnName and valueColumnName elements) and also the name of the sequence (pkColumnValue element).

Conclusion

The choice between IDENTITY, SEQUENCE and TABLE strategies should be pretty obvious. If you application is going to use only one RDBMS, the first or the second option should be fine (depending on your RDBMS vendor). In other cases, TABLE strategy is preferred, if not the only possible.

The source code for the article can be found at GitHub. It has been tested with Oracle Database 11gR2 so it supports only SEQUENCE and TABLE strategies.

Posted in Database, Java, Java EE, JPA | Tagged , , , | 1 Comment

Charts with jqPlot, Spring REST, AJAX and JQuery

One of the most notable features of HTML5 is Canvas API which provides a rectangular region for custom drawing. There are several uses of it like: building games, image compositions, animations but this time we will see how to use it to render charts in web browser. Of course, we could write source code for drawing charts ourselves but it would be tedious and time-consuming task. Fortunately, there are several good JavaScript libraries which can perform this task for us.

One of them is jqPlot which we will use to render a very simple chart showing sales in given country in the current month:

springrestchart

Creating web page

Our only web page sales.jsp is pretty simple:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="s" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Sales</title>
        <script type="text/javascript"
                src="<s:url value='/resources/libs/jquery/jquery.min.js' />" >
        </script>
        <script type="text/javascript"
                src="<s:url value='/resources/libs/jqplot/jquery.jqplot.min.js' />" >
        </script>
        <link href="<s:url value='/resources/libs/jqplot/jquery.jqplot.min.css'/>"
              rel="stylesheet" type="text/css" />

        <script type="text/javascript"
                src="<s:url value='/resources/js/sales.js' />" >
        </script>
        <link href="<s:url value='/resources/css/styles.css'/>"
              rel="stylesheet" type="text/css" />
    </head>
    <body>
        <form>
            <label for="countrySelect">Country:</label>
            <select id="countrySelect" >
                <c:forEach var="country" items="${countries}">
                    <option value="${country.code}">${country.name}</option>
                </c:forEach>
            </select>
        </form>

        <div id="chartError">Failed to contact server</div>
        <div id="chart"></div>
    </body>
</html>

First, we include JQuery and jqPlot libraries which we are going to use later. Then we add our custom js/sales.js JavaScript file which contains logic to asynchronously update the web page once the country is changed (we will look at this file later) and css/styles.css CSS stylesheet:

#countrySelect {
    padding: 0.2em;
}

#chart {
    margin: 1em;
    width: 90%;
    height: auto;
    clear: both;
}

#chartError {
    margin: 1em;
    border-style: solid;
    border-width: medium;
    border-color: black;
    background-color: lightpink;
    font-weight: bold;
    padding: 0.5em;
    display: none;
}

Finally, we add a drop-down menu with the list of all supported countries, a message to inform user about error (hidden by default) and a div element with identifier chart in which jqPlot will draw the chart. There are no canvas elements at the moment but they will be added later to the DOM tree by jqPlot.

Creating Spring MVC controller

The JSP web page retrieves the list of all supported countries from ${countries} model attribute which was populated by the following Spring controller:

package com.example.springrestchart;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value = "/sales")
public class SalesController {
    
    @Autowired
    private SalesProvider salesProvider;
    
    @RequestMapping(method = RequestMethod.GET)
    public String list(Model model) {
        
        List<Country> countries = salesProvider.getCountries();
        model.addAttribute("countries", countries);
        
        return "sales";
    }
}

The controller uses injected instance of SalesProvider singleton bean:

package com.example.springrestchart;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;

@Component
public class SalesProvider {

    private static final List<Country> COUNTRIES = Arrays.asList(
            new Country("UK", "United Kingdom"),
            new Country("DE", "Germany"),
            new Country("FR", "France"));

    private Map<String, Sales> sales;

    @PostConstruct
    protected void init() {
        sales = createSales();
    }

    public List<Country> getCountries() {
        return Collections.unmodifiableList(COUNTRIES);
    }

    public Sales getSales(String countryCode) {
        Sales result = sales.get(countryCode);
        if (result != null) {
            return result;
        } else {
            throw new CountryNotFoundException("Country not found: " + countryCode);
        }
    }

    private static Map<String, Sales> createSales() {
       // omitted
    }

    private static Sales createRandomValues(Country country, int count) {
       // omitted
    }

}

This provider is responsible for returning the list of all supported countries and their sales from the first day of the current month till today (one value per day). The actual sales values are auto-generated but the source code for this was omitted for clarity.

One important thing to notice is that getSales() method throws CountryNotFoundException exception if the sales for given country do not exist. The definitions of Country, Sales and CountryNotFoundException classes are straightforward:

Country:

package com.example.springrestchart;

public class Country {
    private String code;
    private String name;

    public Country(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public String getName() {
        return name;
    }
    
}

Sales:

package com.example.springrestchart;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Sales {
    private Country country;
    private List<Double> values;

    public Sales(Country country, List<Double> values) {
        this.country = country;
        this.values = new ArrayList<>(values);
    }

    public Country getCountry() {
        return country;
    }
    
    public List<Double> getValues() {
        return Collections.unmodifiableList(values);
    }
}

CountryNotFoundException:

package com.example.springrestchart;

public class CountryNotFoundException extends RuntimeException {

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

Creating Spring REST Controller

Now, we should have the web page display in web browser but nothing happens when country is changed. We are going to improve this by exposing the sales data using REST web service and later consuming it from web browser using AJAX and JQuery.

Let’s first look at the implementation of REST web service:

package com.example.springrestchart;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

@Controller
public class SalesRestController {
    
    @Autowired
    private SalesProvider salesProvider;
    
    @RequestMapping(value = "/services/sales/{countryCode}", method = RequestMethod.GET,
            produces = "application/json")
    public @ResponseBody Sales getSales(@PathVariable("countryCode") String countryCode) {
        return salesProvider.getSales(countryCode);
    }
    
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(CountryNotFoundException.class)
    public void countryNotFound() {
    }
}

It is a standard Spring controller with @Controller annotation. Alternatively, we could use RestController annotation and remove @ResponseBody annotation from getSales() method.

We inject the same SalesProvider as before to access sales data. Method getSales() of the controller is annotated with @RequestMapping to inform Spring that it should be invoked whenever HTTP GET request is sent to relative and parameterized URL services/sales/{countryCode} where {countryCode} should be replaced by one of the available country codes. In our case it would be UK, DE or FR.

Finally, we add @ResponseBody annotation to the method and specify produces element to indicate that the returned instance of Sales class should be automatically converted to JSON format before sending over HTTP. Spring uses Jackson library for this task so it must be added as a dependency to Maven POM file:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.4.1.1</version>
</dependency>

If you have been following the article closely, you should remember that getSales() method in SalesProvider class throws CountryNotFoundException if the country code is unknown. Therefore, we install exception handler for it and inform Spring to return HTTP status 404 (Not Found) in case of the exception.

Implementing client-side logic

Finally, after all setup is done we can take a look at previously mentioned js/sales.js file:


function renderPlot(data) {
    $("#chart").empty();
    $("#chartError").hide();

    var countryName = data.country.name;
    var values = data.values;
    $.jqplot("chart", [values], {
        title: "<h2> Sales in " + countryName + " in current month</h2>",
        axes: {
            xaxis: {
                label: 'Day of month',
                pad: 0
            },
            yaxis: {
                label: 'Mln USD'
            }
        }});
}

function renderError() {
    $("#chart").empty();
    $("#chartError").show();
}

function reloadPlot(countryCode) {
    $.ajax({
        url: encodeURI("services/sales/" + countryCode),
        type: "GET",
        dataType: "json",
        success: renderPlot,
        error: renderError
    });
}

function initializeCountries() {
    $("#countrySelect").change(function() {
        var countryCode = $(this).val();
        reloadPlot(countryCode);
    });
    reloadPlot($("#countrySelect").val());
}

$(document).ready(initializeCountries);

Function initializeCountries(), which is called once the document is fully loaded, registers listener to be called when the country is changed. If it happens, the plot is reloaded to show the data for the chosen country.

Function reloadPlot() issues AJAX request to our REST service and passes country code as part of the URL path. If the request succeeds, renderPlot() function is called to render the chart with sales. Because the sales data was returned in JSON format, we can easily access it from JavaScript. We extract the country name and its sales (as an array of real numbers).

Finally, we call $.jqplot() function and pass it identifier of the div element where the chart should be rendered and the actual data. jqPlot can draw multiple data series on a single chart. We have only one series so we have to create an array with one element (our array with sales data) beforehand. jqPlot can take multiple options to customize appearance and behavior of the chart but for simplicity we specify axes labels and padding only.

Conclusion

jqPlot is versatile and very easy to use JavaScript library to render charts in web browser. The functionality used in this article is only a small portion of what it can do.

From user point of view charts generated by such library are more responsive and interactive than the charts generated on a server. It is for example possible to use highlighting, zooming, cursor tracking and even modify the values using drag-and-drop.

The complete source code for the example is available at GitHub.

Posted in AJAX, Java, Spring | Tagged , , , , , , | Leave a comment

Accessing local files from a web browser using HTML5 File API

HTML5 introduced a standard interface called File API which lets programmers access meta-data and read contents of local files selected by a user. The selection is typically done using input element but the recent browsers also allow using drag and drop for this task. The number of opportunities this new API gives us is very wide and include at least: checking files before sending to server, showing thumbnails while uploading files and processing files without interaction with server.

In this article I would like to show how to use this API to read basic properties of a file chosen by a user and additionally read it and calculate its SHA-1 hash. The main window of the sample application will look like this:
html5fileapi

Because the File API is quite new, it is supported only by the latest versions of the web browsers. So if you still have an older one, I strongly suggest upgrading it.

Accessing selected files

The classic method to select a file from local disk is to add HTML input element with type file:

<input id="fileInput" type="file" />

If optional attribute multiple is specified, it is possible to select many files at once.

In JavaScript it is possible to access FileList object, representing files selected by a user, using files property of file input element. FileList behaves like an array so accessing individual File objects is easy:

var fileInput = $("#fileInput")[0];
var fileList = fileInput.files;
for (var i = 0; i < fileList.length; i++) {
    var file = fileList[i];
    // handle file
}

Of course, if user selected only one file (e.g. because multiple attribute was not specified), FileList object contains only one file at index 0.

Once we get a reference to File object representing file selected by a user, we can access one of the following attributes providing useful information about the file:

  • name – The name of the file without any path information
  • size – The size of the file in bytes
  • type – The MIME type of the file (e.g. text/plain) or empty string if it is not available
  • lastModifiedDate – The date of the last modification of the file

Reading file contents

Reading the contents of the file is a bit more complicated. First, we have to create FileReader object, assign listeners to one or more of its events and then call one of these asynchronous methods to start reading the file:

  • FileReader.readAsText(Blob or File, optional_encoding) – Starts reading a text file using given encoding. If the encoding is not specified, file contents is interpreted as UTF-8 text.
  • FileReader.readAsDataURL(Blob or File) – Starts reading a file into data URL string. Typically, this operation is used to read an image file and the result of thss operation can be assigned to src attribute of img element.
  • FileReader.readAsArrayBuffer(Blob or File) – Starts reading a binary file into ArrayBuffer object.

These three methods are asynchronous which means that they finish immediately but the reading operation continues in the background. Once the operation finishes successfully, onload event of FileReader is triggered and the read data can be accessed using result property of the FileReader object. The complete list of available events is below:

  • onloadstart – Triggered when reading operation is starting
  • onload – Triggered when reading operation is finished successfully
  • onloadend – Triggered when reading operation finished (either successfully or with an error)
  • onprogress – Triggered multiple times while reading. Can be used to monitor the progress.
  • onerror – Triggered when reading operation finished with an error
  • onabort – Triggered when reading operation is aborted

Example

Knowing the basics we can start writing sample application by creating index.html file:

<!DOCTYPE html>
<html>
    <head>
        <title>HTML5 File API</title>
        <meta charset="UTF-8" />
        <script type="text/javascript" src="js/libs/jquery/jquery.js"></script>
        <script type="text/javascript" src="js/libs/sha1.js"></script>
        <script type="text/javascript" src="js/process.js"></script>
        <link type="text/css" rel="stylesheet" href="css/styles.css" />
    </head>
    <body>
        <form id="fileForm" class="fileForm">
            <input id="fileInput" type="file" required="required" />
            <button id="processButton" type="submit">Process</button>
        </form>

        <div class="fileStatus">
            <progress id="processProgress" max="1" value="0"></progress>
            <p><span id="processError" class="error"></span></p>
            <table id="processResults">
                <thead>
                    <tr><th>Param</th><th>Value</th></tr>
                </thead>
                <tbody>
                    <tr><td>Name</td><td id="nameValue"></td></tr>
                    <tr><td>Size</td><td id="sizeValue"></td></tr>
                    <tr><td>Type</td><td id="typeValue"></td></tr>
                    <tr><td>Hash</td><td id="hashValue"></td></tr>
                </tbody>
            </table>
        </div>
    </body>
</html>

We use JQuery to simplify several DOM operations and a very nice JavaScript library to calculate SHA-1 hashes (created by T. Michael Keesey). We use a basic form to select single file from local disk and submit it for processing. Once the file is submitted, we are periodically informing the user about the progress of the operation using progress element and finally update the values in the table. Alternatively, if the reading fails, we show the error.

One important thing I did not mention yet is js/process.js file where lives logic of our application:

function calculateHash(fileContents) {
    return sha1.hash(fileContents);
}

function startProcessing(fileInput, onsuccess, onerror, onprogress) {
    var fileList = fileInput[0].files;
    var file = fileList[0];
    var results = {
        name: file.name,
        size: file.size,
        type: file.type,
        hash: ""
    };

    var fileReader = new FileReader();
    fileReader.onload = function(e) {
        results.hash = calculateHash(e.target.result);
        onsuccess(results);
    };
    fileReader.onerror = function(e) {
        onerror(e.target.error.name);
    };
    fileReader.onprogress = function(e) {
        onprogress(e.loaded, e.total);
    };
    fileReader.readAsArrayBuffer(file);
}

function setResults(name, size, type, hash) {
    var table = $("#processResults");
    table.find("#nameValue").text(name);
    table.find("#sizeValue").text(size);
    table.find("#typeValue").text(type);
    table.find("#hashValue").text(hash);
}

function clearResults() {
    $("#processProgress").val(0).show();
    $("#processError").hide();
    $("#processResults").hide();
    setResults("", "", "", "");
}

function populateResults(data) {
    $("#processProgress").val(1);
    $("#processResults").show();
    setResults(data.name, data.size, data.type, data.hash);
}

function populateError(msg) {
    $("#processProgress").hide();
    $("#processError").text("Failed to read file: " + msg);
    $("#processError").show();
}

function populateProgress(loaded, total) {
    $("#processProgress").val(loaded / total);
}

function initialize() {
    $("#fileForm").submit(function(e) {
        e.preventDefault();
        clearResults();
        startProcessing($("#fileInput"), populateResults, populateError, populateProgress);
    });
    clearResults();
}

$(document).ready(initialize);

The most interesting things happen in two first functions. Function calculateHash() calculates and returns SHA-1 hash based on already read contents of the file (passed in as ArrayBuffer object). This function is synchronous which means that it may take some time to finish. On my system it is about 2 seconds per 100MB of data which in practice is not a big issue. Should it become a problem, you may consider putting SHA-1 calculation in a separate thread using web workers.

Function startProcessing() is the place where all the reading happens. At first, we obtain an object named file representing a file selected by a user and create object named results holding the data to be returned after reading operation finishes successfully. Then we create FileReader, setup listeners for onload, onerror and onprogress events of FileReader, and start reading the file into ArrayBuffer. The call fileReader.readAsArrayBuffer() ends immediately.

When the reading operation finishes successfully, event onload is triggered and the first event listener is called. In this event listener we calculate the SHA-1 hash and invoke onsuccess callback. Please, note that e.target.result is actually the same as fileReader.results and holds the contents of the file. In case of an error, event onerror is triggered which in our application shows an error message to a user. Additionally, event onprogress is called several times while reading the file and is used to update the progress bar.

The rest of the functions are responsible for updating, showing and hiding elements on the web page. Function initialize() additionally registers event listener to be called when a user submits the form.

Conclusion

File API is nothing fancy but if used correctly it can significantly improve user experience by reducing the number of round-trips to server and providing better feedback to user (e.g. showing thumbnails of selected files or monitoring progress of file upload).

The article shows only a portion of what File API can do. If you are interested in knowing more, take a look at W3C Working Draft.

The source code for the example can be found at GitHub.

Posted in HTML, JavaScript | Tagged , , | Leave a comment