Chapter 19. JPA (Java Persistence API)

19.1. Introduction

The Jpa Gps Device provides support for database indexing through the use of the Java Persistence API (Jpa), part of the EJB3 standard. If your application uses Jpa, it couldn't be easier to integrate Compass into your application.

Jpa Gps Device utilizes Compass::Core OSEM feature (Object to Search Engine Mappings) and Jpa feature (Object to Relational Mappings) to provide simple database indexing. As well as Jpa support for life-cycle event based system to provide real time mirroring of data changes done through Jpa (see notes about real time mirroring later on). The path data travels through the system is: Database -- Jpa (Entity Manager) -- Objects -- Compass::Gps -- Compass::Core (Search Engine).

JPA Gps Device extends Compass Gps AbstractParallelGpsDevice and supports parallel index operations. It is discussed in more detail here: Section 15.5, “Parallel Device”.

19.2. Configuration

When configuring the Jpa device, one must instantiate JpaGpsDevice. After instantiating the device, it must be initialized by an EntityManagerFactory. This is the only required parameter to the JpaGpsDevice. For tighter integration with the actual implementation of Jpa (i.e. Hibernate), and frameworks that wrap it (i.e. Spring), the device allows for abstractions on top of it. Each one will be explained in the next sections, though in the spirit of compass, it already comes with implementations for popular Jpa implementations.

Here is a code sample of how to configure the Jpa device:

Compass compass = ... // set compass instance
CompassGps gps = new SingleCompassGps(compass);
CompassGpsDevice jpaDevice =
     new JpaGpsDevice("jpa", entityManagerFactory);
.... // configure other devices

The device performs all it's operations using its EntityManagerWrapper. The Jpa support comes with three different implementations: JtaEntityManagerWrapper which will only work within a JTA environment, ResourceLocalEntityManagerWrapper for resource local transactions, and DefaultEntityManagerWrapper which works with both JTA and resource local environments. The DefaultEntityManagerWrapper is the default implementation of the EntityManagerWrapper the device will use.

Several frameworks (like Spring) sometimes wrap (proxy) the actual EntityManagerFactory. Some features of the Jpa device require the actual implementation of the EntityManagerFactory. This features are the ones that integrate tightly with the implementation of the EntityManagerFactory, which are described later in the chapter. The device allows to set NativeEntityManagerFactoryExtractor, which is responsible for extracting the actual implementation.

19.3. Index Operation

Jpa Gps device provides the ability to index a database. It automatically supports all different Jpa implementations. Compass will index objects (or their matching database tables in the Jpa mappings) specified in both the Jpa mappings and Compass::Core mappings (OSEM) files.

When indexing Compass::Gps, the Jpa device can be configured with a fetchCount. The fetchCount parameter controls the pagination process of indexing a class (and it's represented table) so in case of large tables, the memory level can be controlled.

The device allows to set a JpaEntitiesLocator, which is responsible for extracting all the entities that are mapped in both Compass and Jpa EntityManager. The default implementation DefaultJpaEntitiesLocator uses Annotations to determine if a class is mapped to the database. Most of the times, this will suffice, but for applications that use both annotations and xml definitions, a tighter integration with the Jpa implementation is required, with a specialized implementation of the locator. Compass comes with several specialized implementations of a locator, and auto-detect the one to use (defaulting to the default implementation if none is found). Note, that this is one of the cases where the actual EntityManagerFactory is required, so if the application is using a framework that wraps the EntityManagerFactory, a NativeEntityManagerFactoryExtractor should be provided.

19.4. Real Time Data Mirroring

The Jpa specification allows for declaring life-cycle event listeners either on the actual domain model using annotations, or in the persistence settings. The EntityManagerFactory API does not allow for a way to register global listeners programatically. Compass comes with two abstract support classes to ease the definition of listeners. The first is the AbstractCompassJpaEntityListener, which requires the implementation to implement the getCompass which will fetch the actual compass instance (probably from Jndi). The second is the AbstractDeviceJpaEntityListener, which requires the implementation to implement the getDevice which will fetch the Jpa Gps Device.

With several Jpa implementation, Compass can automatically register life-cycle event listeners based on the actual implementation API's (like Hibernate event listeners support). In order to enable it, the injectEntityLifecycleListener must be set to true (defaults to false), and an implementation of JpaEntityLifecycleInjector can be provided. Compass can auto-detect a proper injector based on the currently provided internal injector implementations. The auto-detection will happen if no implementation for the injector is provided, and the inject flag is set to true. Note, that this is one of the cases where the actual EntityManagerFactory is required, so if the application is using a framework that wraps the EntityManagerFactory, a NativeEntityManagerFactoryExtractor should be provided.

An important point when configuring the Jpa device is that both the application and the Jpa device must use the same EntityManagerFactory.