A RAR in a WAR with TomEE?


Sometimes it can be useful to deploy a JCA connector in a war.

That’s why TomEE got some features related to this need.

The technical part

First you can put the rar directly in WEB-INF/lib. If so keep in mind the rar will be unpacked by default where it is placed (WEB-INF/lib) so to avoid this behavior, set the system property tomee.unpack.dir to another folder (work/ folder is often a good choice).

Another interesting thing is the ability to put a ra.xml in WEB-INF/ folder and then put the adapter in WEB-INF/classes.

And in real? what does it mean?

To be more concrete i’ll take a sample: Hazelcast. Hazelcast is a nice library implementing distributed structures (Map, List, …) and some cloud computing features (behind an ExecutorService). This library provides a JCA connector (hazelcast-ra).

If you define a war with the rar in the lib (whatever how you do) and hazelcast in libraries of the war (not provided by default) you’ll be able to get injected the Hazelcast ConnectionFactory:

import import javax.resource.cci.ConnectionFactory;;

[...]

@Resource(name = "hazelcast-ra-2.4.1") // name provided by the ra.xml
private ConnectionFactory cf;

Then simply use it:

final Connection conn = cf.getConnection();
final LocalTransaction tx = conn.getLocalTransaction();
tw.begin();

someHazelcastMap.put("foo", "bar");

tx.commit();
conn.close();

Here we are, we simply used standard types of the JRE (Map) and JCA API (javax.resource.cci…) but in fact our map is distributed through Hazelcast and transactional through its JCA connector :).

Side note: Hazelcast transaction mecanism can be used without any JCA connector but it is interesting to be able to isolate the Hazelcast part in very few classes (CDI Map producers?) and get a 100% standard code 100%.
Side note 2: the Hazelcast transaction can be managed more easily through a custom CDI interceptor and an interceptor binding @TransactionalMap for instance.

Workaround for Hazelcast

Hazelcast is great but it uses a shutdown hook to shutdown itself (why the connector is often added to the container and not only an application). To workaround it simply add a singleton which will manage the shutdown of Hazelcast:

@Singleton
@Startup
public class ShutdownHazelcast {
    @PreDestroy
    public void shutdown() {
        for (HazelcastInstance i : Hazelcast.getAllHazelcastInstances()) {
            i.getLifecycleService().shutdown(); // kill() is a bit more aggressive
        }
    }
}
Advertisements

4 thoughts on “A RAR in a WAR with TomEE?

  1. Thorsten

    Good post – so cannot adopt it to hazelcast 3.1.3,
    tomee 1.6.0 root cause:
    Caused by: org.apache.tomee.catalina.TomEERuntimeException: org.apache.openejb.OpenEJBException: Can’t find resource for class demo.JcaTest#cf. (No provider available for resource-ref ‘null’ of type ‘javax.resource.cci.ConnectionFactory’ for ‘rest-example.Comp300822365’.)
    Changed the hazelcast-ra-2.4.1 string to hazelcast-ra-3.1.3
    –> Do you have a hint or idea how to move on?

    Also saw your comments and code snippets for hazelcast issue 440 – tried them and
    there also seem to be changes since hazelcast 2.x and cannot get them running with hazelcast 3.x.
    Also you mention a custom CDI interceptor in this post – do you have source / github link available?

    Reply
    1. rmannibucau Post author

      the name to use is logged in the startup logs, did you check it?

      about the interceptor just do Exception e = null;begin(); try {proceed(); } catch(Exception ex) {e=ex; rollback(); } finally {if (e == null) commit();}

      Reply
  2. Thorsten

    Thanks for the hint. Checked name and changed it to: hazelcast-ra-3.1.3RA
    –> taken from log: Creating Resource(id=hazelcast-ra-3.1.3RA)

    Now:
    @Resource(name = “hazelcast-ra-3.1.3RA”)
    private ConnectionFactory cf;

    try {
    final Connection conn = cf.getConnection();
    final LocalTransaction tx = conn.getLocalTransaction();
    tx.begin();
    // someHazelcastMap.put(“foo”, “bar”);
    tx.commit();
    conn.close();
    } catch( Exception e ) {
    System.out.println(“JcaTest:doit – explode”);
    }

    Results in:
    Caused by: org.apache.openejb.OpenEJBException: Can’t find resource for class org.superbiz.rest.service.UserService#cf. (No provider available for resource-ref ‘null’ of type ‘javax.resource.cci.ConnectionFactory’ for ‘rest-example.Comp2003049152’.)

    any idea?

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s