Java

Use Guava Cache To Improve Performance

  • Posted on: 18 April 2015
  • By: Zhijun Chen

It is quite often that you might want to use cache a value when it is expensive to compute or retrieve, e.g. involves several hibernate queries and serialization.

Guava Cache is one of the options if you just need to cache the value in RAM instead of files.

In my case, I'm using CacheLoader as I've got key/value pairs. The following utility class shows how this can be done.

package uk.co.zhijun.manager.cache;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;

/**
 * 
 */
public class StudentCache {

  private static Logger logger = LoggerFactory
      .getLogger(StudentCache.class);

  private LoadingCache<Long, Student> studentCache;
  private StudentManager studentManager;

  public StudentCache(int expirationTimeMinutes) {
    buildStudentCache(expirationTimeMinutes);
  }

  private void buildStudentCache(int expirationTimeMinutes) {
    studentCache = CacheBuilder.newBuilder()
        .expireAfterAccess(expirationTimeMinutes, TimeUnit.MINUTES)
        .removalListener(studentRemovalListener)
        .build(new CacheLoader<Long, Student>() {

          @Override
          public Student load(Long id) throws Exception {
            return studentManager.getStudentById(id);
          }
        });
  }

  public Student getStudent(Long id) throws ExecutionException {
      return studentCache.get(id);
  }

  public void invalidateStudentCache(Long id) {
    studentCache.invalidate(id);
  }

  private RemovalListener<Long, Student> studentRemovalListener = new RemovalListener<Long, Student>() {
    public void onRemoval(RemovalNotification<Long, Student> removal) {
      logger.info(
          "Refreshing student, studentId = {}, was evicted? {}",
          removal.getKey(), removal.wasEvicted());
    }
  };

  /* provided for spring setter injection */
  public void setStudentManager(StudentManager studentManager) {
    this.studentManager = studentManager;
  }
}

You can then register this class in the spring context and use it. The cache should be evicted everytime a change is going to affect the Student object.

...
<bean id="studentCache" class="uk.co.zhijun.manager.cache.StudentCache">
  <constructor-arg name="expirationTimeMinutes" value="10" />
  <property name="studentManager" ref="studentManager" />
</bean>
...

Solution for "InvalidPathException: Malformed input" in Tomcat

  • Posted on: 3 December 2014
  • By: Zhijun Chen

Today I came across the following Java Exception within Tomcat Web Application:

"java.nio.file.InvalidPathException: Malformed input or input contains unmappable characters."

This is due to file system not able to handle special characters in a file name, e.g. Tromsø.png
The solution to this issue is actually quite simple. Set the system language to be UTF8 using the following code:

export LANG = en_US.UTF8

Then restart Tomcat. Now Tomcat should pick up the system property and set the file.encode to be UTF8.

Use CRest to consume RESTful Web Service for Android

  • Posted on: 20 April 2014
  • By: Zhijun Chen

There are several ways to consume RESTful web services from Android. One option would be using the builtin HttpClient library and parsing the response using an XML/Json parser library, e.g. Gson. After several hours research, I chose CRest Android version because of its simplicity. CRest is a lightweight JAX-RS compatible framework aiming to simplify the integration of external REST services into Java applications.

* Libraries required

The following libraries are required and should be put inside Android /libs folder. Maven dependencies are also available if you are using android maven plugin.

* RESTful Web Service Example and sample Response

Suppose we have a REST service GET call which simply returns the user with id: http://192.168.0.100:8000/api/v1/user/{id}?format=json. And the sample JSON response is given as follows.

 {
  "id": 1,
  "first_name": "Zhijun",
  "last_name": "Chen",
  "name": "zhijun.chen"
}
* Java Model Objects

A Pojo is needed to map the JSON response into Java objects.

package uk.co.zhijun.model;

import org.codehaus.jackson.annotate.JsonProperty;

public class User {
	private Long id;
	@JsonProperty("first_name")
	private String firstName;
	@JsonProperty("last_name")
	private String lastName;
	private String name;
	
	public User() {
	}
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}
	
	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;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

Note: Any properties defined inside Java model but not in the JSON response should be annotated with @JsonIgnore

* Services Interfaces

Next we will create a service interface to consume the REST service.

import org.codegist.crest.annotate.Consumes;
import org.codegist.crest.annotate.EndPoint;
import org.codegist.crest.annotate.HeaderParam;
import org.codegist.crest.annotate.Path;
import org.codegist.crest.annotate.PathParam;

import uk.co.zhijun.model.User;

@EndPoint("http://192.168.0.100:8000")
@Path("/api/v1/user")
@Consumes("application/json")
public interface UserService {
	
	@Path("/{id}")
	@HeaderParam(value="Authorization", defaultValue="Basic {basic.auth.digest}")
	public User getUser(@PathParam("id") long id);
}

The @HeaderParam is needed when you need to add any http request header to the request, in this case it is an authentication token. @Consumes defines the type of response received from REST service. We will show how to pass in {basic.auth.digest} value.

* Android Integration

Now we have service interface ready, the final step would be integrated it into Android project. Android uses a seperate thread from main thread to execute http calls. And it is recommended to set CRest to use HttpClient to send requests. The following code gives an example.

private class FetchUserTask extends AsyncTask<Void, Void, User> {

			@Override
			protected User doInBackground(Void... params) {
				String username = "username";
				String password = "password";
				String basicAuthDigest = Base64.encode(username + ":" + password);

				CRest crest = CRest.placeholder("basic.auth.digest", basicAuthDigest)
						.setHttpChannelFactory(
								HttpClientHttpChannelFactory.class).build();
				UserService userService = crest.build(UserService.class);
				User user = userService.getUser(1);
				return user;
			}

			protected void onPostExecute(User user) {
				// do something with the response
			}
		}

As you can see, the authentication code is passed in using placeholder.