The Tribe Blog

Apache TomEE, Arquillian, JCache, CDI, and Hazelcast – What more could you want?

4219
1 Comment

Well, OK, maybe a lot more, but these technologies just work so sweet together that we decided to jump in and give it a go at the Devoxx UK 2015 Hackergarten. Heather VanCura, a leader of the Java Community Process (JCP), clubbed several developers together for some fun key bashing and this is the result. Enjoy!

This hack session was brought to you by Bruno Baptista, Paulo Martins and Andy Gumbrecht, with thanks to Heather VanCura and Devoxx UK 2015.

JCache API

This API allows the use of caching methods in an intuitive and transparent manner. You need two things in your pom.xml:

The API definition, which defines the JCache interfaces.

    <dependency>
      <groupId>javax.cache</groupId>
      <artifactId>cache-api</artifactId>
      <version>>1.0.0</version>
    </dependency>

An implementation of the API, in this case Hazelcast. Of course you can use any compatible provider.

    <dependency>
      <groupId>com.hazelcast</groupId>
      <artifactId>hazelcast-all</artifactId>
      <version>3.5</version>
    </dependency>

Contexts and Dependency Injection – CDI

Let’s face it, there are plenty of really complicated ways of providing access to application scoped resources. So why on earth would you use them when we have something as cool, and as simple, as CDI? In Java EE 6 we just need to add the beans.xml file to an application’s META-INF directory and BANG! @Inject @Inject @Inject

CacheInterceptor.java

  @Inject
  @ObjectCache
  private Cache<String, Object> cache;

So where does that come from? Well, although not strictly true, it needs to be produced by a @Producer

CacheProducer.java

  @Produces
  @Singleton
  @LocalCacheProvider
  public CacheManager createCacheManager() {

We’ve done it this way so that you can see the Magicode and make it easy for you to choose your implementation at runtime.

  return Caching
   .getCachingProvider("com.hazelcast.cache.impl.HazelcastServerCachingProvider")
   .getCacheManager();

Note that there is a second @Producer in the game here that accepts the CacheManager in its construction…

ObjectCacheProducer.java

  @Produces
  @Singleton
  @ObjectCache
  public Cache<String, Object> createUserCache(@LocalCacheProvider final CacheManager cacheManager) {

Here we qualify it as an @ObjectCache producer, well because it is an Object cache that is being @Produced. There is nothing to stop you from creating a strongly typed cache for everything and anything. It’s just syntactic sugar; so make it the icing on your cake.

Java EE Interceptors – Pollute nothing, gain everything

Now you have seen how you can add the JCache API everywhere, but do you really want to? Is caching important to your actual business logic? Unlikely at best. Let’s nip this thought in the bud and roll straight on to Java EE Interceptors. We have two scenarios; one is to cache and the other is to invalidate the cache.

CacheInterceptor.java

  @AroundInvoke
  public Object cache(final InvocationContext ctx) throws Exception {

     final Object[] parameters = ctx.getParameters();

     final String key = parameters[0].toString();

     Object o = cache.get(key);

     if (null == o) {
       o = ctx.proceed();
       cache.put(key, o);
     }

     return o;
  }

So you can see, this just creates a super simple key using the first parameter of any method you add this interceptor to. If that’s an ID of an @Entity then it could be just what you need, but again, this is totally up to you to manage. As it happens, our example fits this scenario perfectly. Such a coincidence!

What you should also be able to see is that using this interceptor is actually pretty powerful and keeps your business logic neat and tidy, and completely unaware that there is a cache at all. That is exactly the way it should be!

But now we have our ‘Something’ in the cache. What if some other process changes our ‘Something’? Invalidate the cache, but, in the same vain as above, let’s not pollute our business logic and use another interceptor.

CacheInvalidator.java

  @AroundInvoke
  public Object cache(final InvocationContext ctx) throws Exception {

    final Object[] parameters = ctx.getParameters();

    final String key = parameters[0].toString();

    final Object proceed = ctx.proceed();

    cache.remove(key);

    return proceed;
  }

Incredible things from incredible technologies. That’s it, go cache Something today! Oh, hang on, surely we should prove all this Magicode actually works?

Testing Your Magicode with Arquillian

Arquillian compliments all other forms of testing and actually rolls unit, functional and integration testing into one tidy bundle. There is way too much here to explain in a simple blog, so pop over to Arquillian.org to learn more.

Basically, adding the following @RunWith(Arquillian.class) annotation to your test class will perform some incredible wiring. It will package up your application, fire up a TomEE server, deploy the app, run the test against the deployed app, return the results, and finally, shuts down the TomEE server.

InterceptedServiceTest.java

  @RunWith(Arquillian.class)
  public class InterceptedServiceTest extends Assert {

The test itself is designed to prove that our complex object is cached, updated and invalidated. We could have put the Invalidation interceptor on the update method, but then the test would be less obvious to follow. Give it a try.

What Next? Your own JCache API enabled project.

The world is your oyster on this one. Please feel free to use this code based example as a stepping stone to creating your own JCache API interceptor enabled project – The JCache Annotation API will be added to this project on a future blog. Check out the entire source code for this example project here: https://github.com/tomitribe/JCacheExamples, and don’t forget to have fun!


Andy

About the author

Andy Gumbrecht

Senior Software Engineer
Follow Andy Gumbrecht
Andy has been fitting in tight code since getting a Sinclair ZX81 with a whopping 1k memory back in 1982. After a rewarding military career gaining many life experiences he eventually turned his long time hobby into a professional qualification, and subsequently went on to become a lead developer on several successful local government and commercial industry projects. As a senior Java developer he has never lost his love for coding, open source and best practices within the industry and has an attention to detail, performance and infrastructure. He has been using in production environments and contributing to OpenEJB since October 2009. He still dreams of his early paragliding days when it was 'really' dangerous, but these days just loves to traverse the mountains of Bavaria by foot or cycle up the occasional hill - Sometimes he even manages to convince those he loves most to drag along behind.