J Fabian Meier
J Fabian Meier

Reputation: 35805

Keep and update data in REST service (JAX-RS)

I am writing a REST service with jersey (JAX-RS). Essentially, it should do the following:

There is a text file with a lot of key=value pairs. The user of the REST service should be able to query for a key and receive the value.

Now it takes much too long to load and split the whole text file for every query. Instead I would like to load the text file into a Hashmap and reload it in fixed intervals.

I do not know how to implement this behaviour so that the Hashmap survives between queries, and that querying the REST service while it reloads the data does not cause concurrency issues.

What should I do to have such a "cache" in my application?

Upvotes: 0

Views: 294

Answers (1)

zeppelin
zeppelin

Reputation: 9365

JAX-RS default resource lifecycle is per-request (Request scope), so you need to mark your resource as @Singleton instead, to make it shared across the concurrent requests.

@Singleton

javax.inject.Singleton

In this scope there is only one instance per jax-rs application. Singleton resource can be either annotated with @Singleton and its class can be registered using the instance of Application. You can also create singletons by registering singleton instances into Application.

Life-cycle of Root Resource Classes

Next you need to implement a periodically refreshed thread-safe cache, to store your map.

I will normally use Guava CacheBuilder to do this:

private final LoadingCache<Object,Map<String,String>> cache;
protected final Object CACHE_KEY = new Object();    

//Create a Cache and keep it in the instance variable
public MyClass() {
    this.cache = CacheBuilder.newBuilder()
        .maximumSize(1)
        .refreshAfterWrite(10,TimeUnit.MINUTES)
        .build(new CacheLoader<Object,Map<String,String>>() {
            @Override
            public Map<String, String> load(Object key) {
                //Parse your file and return a Map<String,String>
            }
        });
 }

 @GET
 public void doIt() {
      //Get a cached copy of your Map
      Map<String,String> values = cache.get(CACHE_KEY);
 }

The cache instance is safe to use across the multiple threads (though you still have to take care of the thread safety of the object you return from cache), and will automatically refresh your entry once in 10 minutes.

In a more complex system you may also want to create your LoadingCache instance elsewhere, and just inject it into your resource class (in this case you could keep it the request scoped).

Upvotes: 1

Related Questions