OGM-1206 Highlight the referential integrity problem better in the Hot Rod documentation

[[ogm-infinispan]]

// vim: set colorcolumn=100:

== Infinispan

Infinispan is an open source in-memory data grid focusing on high performance.
As a data grid, you can deploy it on multiple servers - referred to as nodes -
and connect to it as if it were a single storage engine:
it will cleverly distribute both the computation effort and the data storage.

It is trivial to setup on a single node and Hibernate OGM knows how to boot one,
so you can easily try it out.
But Infinispan really shines in multiple node deployments:
you will need to configure some networking details
but nothing changes in terms of application behaviour,
while performance and data size can scale linearly.

From all its features we will only describe those relevant to Hibernate OGM;
for a complete description of all its capabilities and configuration options,
refer to the Infinispan project documentation at
http://infinispan.org/documentation/[infinispan.org].

=== Why use Hibernate OGM with Infinispan?

Infinispan provides great scalability and elasticity features but
it can have a steep learning curve.

If you are already familiar with the JPA API you will
be able to store your data in Infinispan quickly and you will also benefit
from the optimizations that a framework like Hibernate OGM can
apply under the hood.

In particular:

* you can get started without having to learn `Protobuf` first
* no need to learn the Infinispan API
* Hibernate OGM will setup and manage the `Hot Rod client` for you
* same API as Hibernate ORM, meaning that you can use the same tools

You will still need to learn about Infinispan, all its capabilities and how to configure
them to reach your application top performance, but you can get a proof of concept
done quickly with the example configuration.

=== Infinispan: Choosing between Embedded Mode and Hot Rod

Java applications can use Infinispan in two fundamentally different ways:

* Run Infinispan in _Embedded Mode_.
* Connect to an _Infinispan Server_ using an _Hot Rod client_.

Hibernate OGM supports connecting in either mode, but since the APIs and capabilities
are different in the two modes, it provides two different modules
each having its own set of configuration options and features.

Running Infinispan in _Embedded Mode_ implies that the Infinispan node is running
in the same JVM as the code using it.
The benefit is that some data (or all data) will be stored on the same JVM, making reads
of this data extremely fast and efficient as there won't be RPCs to other systems.
Write operations will still need to issue some coordination RPCs but they also
benefit from a reduction of necessary operations.

However the very fact that some data is stored in the same JVM is also the drawback
of this choice: this typically implies having to configure your JVM for larger
heap sizes, which are harder to tune for optimal performance. Other system
parameters might also need to be configured as this JVM node is now to be treated
as a "data holding node" rather than a stateless app node.
Some architects and system administrators will not like that.

When connecting to an _Infinispan Server_ over the _Hot Rod client_, the architecture
is similar to having Hibernate connect to traditional database: the data is stored
on the _Infinispan Server_ nodes, and Hibernate OGM uses a client with a pool of
TCP connections to talk to the server.
But the Hot Rod client is not transactional, see the limitation described here:
(<<storage-principles-of-infinispan-dataprovider>>).

Another important difference, is that when connecting to _Infinispan Server_ via
_Hot Rod_ the data is encoded using _Google Protobuf_, which requires a schema.
This schema is auto-generated by Hibernate OGM.

Having a _Protobuf Schema_ makes it possible to evolve the schema in non-destructive
ways, and makes it possible for other clients to access the data - even clients written
in other programming languages.

[NOTE]
====
Most introductory tutorials of Hibernate OGM focus on Infinispan in _Embedded Mode_
because in this mode OGM can start its own embedded Infinispan node, using
a simple, local only Infinispan configuration.

When using _Infinispan Server_ instead, you'll need to http://infinispan.org/download/[download
the server distribution], unpack and start it, then set the Hibernate OGM configuration
properties so that the integrated Hot Rod client knows how to connect to it.
====

[TIP]
====
[.lead]
Advanced performance options & interaction with Hibernate 2nd level caching

When using Infinispan in Embedded Mode, and it's caches are configured in `REPLICATION` Mode,
all nodes will contain a full replica of the database: write performance won't scale but
your reads will be very fast and scale up linearly with the size of the cluster,
making usage of Hibernate's 2nd level cache redundant.

When configuring Infinispan in `DISTRIBUTED` cache mode, each of your nodes will have a
local copy of a slice of your data; remember you can tune how large the section
should be with various Infinispan configuration options (such as _numOwners_), and you
could combine this with Hibernate's 2nd level caching and/or enable Infinispan's
1st level caching.

You can even combine Infinispan with having it passivate to other storage systems
such as a RDBMs or another NoSQL engine; such storage can be configured to be asynchronous.
This option is available to both Infinispan Embedded and Infinispan Server; it's even possible
to use a light layer of Infinispan Embedded - containing a small data set - and have it
backed by an Infinispan Server cluster to expand its storage capabilities without
having to enlarge heap size too much on the embedded, application nodes.

Finally, remember that options such as replication vs distribution (`CacheMode`) and passivation
to additional storage (``CacheStore``s) can be configured differently for each of Infinispan caches.
====

[[ogm-infinispan-embedded]]
=== Hibernate OGM & Infinispan Embedded

Let's see how to configure and use Hibernate OGM with Infinispan in Embedded Mode.

For usage of Infinispan Server over Hot Rod, skip to <<ogm-infinispan-remote>>.

[[ogm-infinispan-configuration]]

==== Configure Hibernate OGM for Infinispan Embedded

You configure Hibernate OGM and Infinispan in two steps basically:

* Add the dependencies to your classpath
* And then choose one of:

** Use the default Infinispan configuration (no action needed)
** Point to your own configuration resource file
** Point to a [acronym]`JNDI` name of an existing instance of an Infinispan `CacheManager`

* If you need to run JPQL or HQL queries, add Hibernate Search on the classpath
  (<<ogm-query-using-hibernate-search>>)

Note that, except when using [acronym]`JNDI`, Hibernate OGM will bootstrap and Infinispan Embedded node
in your same JVM, and terminate it on shutdown of the Hibernate instance.

[CAUTION]
====
If you have Hibernate OGM boot Infinispan using a clustered configuration, this might automatically join the cluster of
other Infinispan nodes running in your network: the default is automatic discovery!
====

[[ogm-infinispan-adddepencies]]

==== Adding Infinispan dependencies

To add the dependencies for the Hibernate OGM extensions for Infinispan Embedded via Maven, add the following module:

[source, XML]
[subs="verbatim,attributes"]
----
<dependency>
    <groupId>org.hibernate.ogm</groupId>
    <artifactId>hibernate-ogm-infinispan-embedded</artifactId>
    <version>{hibernate-ogm-version}</version>
</dependency>
----

If you're not using a dependency management tool,
copy all the dependencies from the distribution in the directories:

* `/lib/required`
* `/lib/infinispan`
* Optionally - depending on your container - you might need some of the jars from `/lib/provided`

[[ogm-infinispan-configuration-properties]]

==== Infinispan specific configuration properties

The advanced configuration details of an Infinispan Cache
are defined in an Infinispan specific XML configuration file;
the Hibernate OGM properties are simple
and usually just point to this external resource.

To use the default configuration provided by Hibernate OGM -
which is a good starting point for new users - you don't have to set any property.

.Hibernate OGM properties for Infinispan
`hibernate.ogm.datastore.provider`::
Set it to `infinispan_embedded` to use Infinispan as the datastore provider in embedded mode.
`hibernate.ogm.infinispan.cachemanager_jndi_name`::
If you have an Infinispan `EmbeddedCacheManager` registered in JNDI,
provide the JNDI name and Hibernate OGM will use this instance
instead of starting a new `CacheManager`.
This will ignore any further configuration properties
as Infinispan is assumed being already configured.
Infinispan can typically be pushed to JNDI via WildFly, Spring or Seam.
`hibernate.ogm.infinispan.configuration_resource_name`::
Should point to the resource name of an Infinispan configuration file.
This is ignored in case [acronym]`JNDI`  lookup is set.
Defaults to `org/hibernate/ogm/datastore/infinispan/default-config.xml`.
`hibernate.ogm.datastore.keyvalue.cache_storage`::
The strategy for persisting data in Infinispan.
The following two strategies exist (values of the `org.hibernate.ogm.datastore.keyvalue.options.CacheMappingType` enum):

* `CACHE_PER_TABLE`: A dedicated cache will be used for each entity type, association type and id source table.
* `CACHE_PER_KIND`: Three caches will be used: one cache for all entities, one cache for all associations and one cache for all id sources.

+
Defaults to `CACHE_PER_TABLE`. It is the recommended strategy as it makes it easier to target a specific cache for a given entity.
`hibernate.ogm.datastore.create_database`::
If set to `true` Hibernate OGM will create any missing Cache definitions on the Infinispan Server.
This requires the Infinispan Server configuration to have a default configuration defined, as this will be copied to the newly defined caches.
If set to `false` an exception is thrown when a Cache is expected but not explicitly configured on the server.
Defaults to `false`.

[NOTE]
====
When bootstrapping a session factory or entity manager factory programmatically,
you should use the constants accessible via `org.hibernate.ogm.datastore.infinispan.InfinispanProperties`
when specifying the configuration properties listed above.

Common properties shared between stores are declared on `OgmProperties`
(a super interface of `InfinispanProperties`).

For maximum portability between stores, use the most generic interface possible.
====

==== Cache names used by Hibernate OGM

Depending on the cache mapping approach, Hibernate OGM will either:

* store each entity type, association type and id source table in a dedicated cache
  very much like what Hibernate ORM would do. This is the `CACHE_PER_TABLE` approach.
* store data in three different caches when using the `CACHE_PER_KIND` approach:
** `ENTITIES`: is going to be used to store the main attributes of all your entities.
** `ASSOCIATIONS`: stores the association information representing the links between entities.
** `IDENTIFIER_STORE`: contains internal metadata that Hibernate OGM needs
    to provide sequences and auto-incremental numbers for primary key generation.

The preferred strategy is `CACHE_PER_TABLE` as it offers both more fine grained configuration options
and the ability to work on specific entities in a more simple fashion.

In the following paragraphs, we will explain which aspects of Infinispan
you're likely to want to reconfigure from their defaults.
All attributes and elements from Infinispan which we don't mention are safe to ignore.
Refer to the http://infinispan.org/documentation/[Infinispan User Guide]
for the guru level performance tuning and customizations.

An Infinispan configuration file is an XML file complying with the Infinispan schema;
the basic structure is shown in the following example:

.Simple example of an Infinispan configuration file
====
[source, XML]
----
<?xml version="1.0" encoding="UTF-8"?>
<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:9.1 http://www.infinispan.org/schemas/infinispan-config-9.1.xsd"
    xmlns="urn:infinispan:config:9.1">

    <cache-container name="HibernateOGM" default-cache="DEFAULT">

        <!-- Default cache settings -->
        <local-cache name="DEFAULT">
            <transaction mode="NON_DURABLE_XA" />
        </local-cache>

        <local-cache name="User"/>

        <local-cache name="Order"/>

        <local-cache name="associations_User_Order"/>

    </cache-container>
</infinispan>
----
====

There are global settings that can be set before the `cache_container` section.
These settings will affect the whole instance;
mainly of interest for Hibernate OGM users is the `jgroups` element
in which we will set JGroups configuration overrides.

Inside the `cache-container` section are defined explicit named caches and their configurations
as well as the default cache (named `DEFAULT` here) if we want to affect all named caches.
This is where we will likely want to configure clustering modes, eviction policies and ``CacheStore``s.

[[ogm-infinispan-storage]]

==== Manage data size

In its default configuration Infinispan stores all data in the heap of the JVM;
in this barebone mode it is conceptually not very different than using a HashMap:
the size of the data should fit in the heap of your VM,
and stopping/killing/crashing your application will get all data lost
with no way to recover it.

To store data permanently (out of the JVM memory) a `CacheStore` should be enabled.
The Infinispan project provides many `CacheStore` implementations;
a simple one is the http://infinispan.org/docs/stable/user_guide/user_guide.html#single_file_store["Single File Store"]
which is able to store data in simple binary files, on any read/write mounted filesystem;
You can find many more implementations to store your data in anything
from JDBC connected relational databases, other NoSQL engines such as MongoDB and Cassandra,
or even delegate to other Infinispan clusters.
Finally, implementing a custom `CacheStore` is quite easy.

To limit the memory consumption of the precious heap space,
you can activate a `passivation` or an `eviction` policy;
again there are several strategies to play with,
for now let's just consider you'll likely need one to avoid running out of memory
when storing too many entries in the bounded JVM memory space;
of course you don't need to choose one while experimenting with limited data sizes:
enabling such a strategy doesn't have any other impact
in the functionality of your Hibernate OGM application
(other than performance: entries stored in the Infinispan in-memory space
is accessed much quicker than from any CacheStore).

A `CacheStore` can be configured as write-through,
committing all changes to the `CacheStore` before returning (and in the same transaction)
or as write-behind.
A write-behind configuration is normally not encouraged in storage engines,
as a failure of the node implies some data might be lost
without receiving any notification about it,
but this problem is mitigated in Infinispan because of its capability
to combine CacheStore write-behind
with a synchronous replication to other Infinispan nodes.

.Enabling a FileCacheStore and eviction
====

[source, XML]
----
<local-cache name="User">
    <transaction mode="NON_DURABLE_XA" />
    <eviction strategy="LIRS" max-entries="2000"/>
    <persistence passivation="true">
        <file-store
           shared="false"
           path="/var/infinispan/myapp/users">
            <write-behind flush-lock-timeout="15000" thread-pool-size="5" />
        </file-store>
    </persistence>
</local-cache>
----

====

In this example we enabled both `eviction` and a `CacheStore` (the `persistence` element).
`LIRS` is one of the choices we have for eviction strategies.
Here it is configured to keep (approximately) 2000 entries in live memory
and evict the remaining as a memory usage control strategy.

The `CacheStore` is enabling `passivation`,
which means that the entries which are evicted are stored on the filesystem.

[WARNING]
====
You could configure an eviction strategy while not configuring a passivating CacheStore!
That is a valid configuration for Infinispan but will have the evictor permanently remove entries.
Hibernate OGM will break in such a configuration.
====

[[ogm-infinispan-clustering]]

==== Clustering: store data on multiple Infinispan nodes

The best thing about Infinispan is that all nodes are treated equally
and it requires almost no beforehand capacity planning:
to add more nodes to the cluster you just have to start new JVMs,
on the same or different physical servers,
having your same Infinispan configuration and your same application.

Infinispan supports several clustering _cache modes_;
each mode provides the same API and functionality
but with different performance, scalability and availability options:

.Infinispan cache modes
local::
Useful for a single VM: networking stack is disabled
replication::
All data is replicated to each node;
each node contains a full copy of all entries.
Consequentially reads are faster but writes don't scale as well.
Not suited for very large datasets.
distribution::
Each entry is distributed on multiple nodes for redundancy and failure recovery,
but not to all the nodes.
Provides linear scalability for both write and read operations.
distribution is the default mode.

To use the `replication` or `distribution` cache modes
Infinispan will use JGroups to discover and connect to the other nodes.

In the default configuration,
JGroups will attempt to autodetect peer nodes using a multicast socket;
this works out of the box in the most network environments
but will require some extra configuration in cloud environments
(which often block multicast packets) or in case of strict firewalls.
See the http://www.jgroups.org/manual/html_single/[JGroups reference documentation],
specifically look for _Discovery Protocols_ to customize the detection of peer nodes.

Nowadays, the [acronym]`JVM` defaults to use [acronym]`IPv6` network stack;
this will work fine with JGroups, but only if you configured [acronym]`IPv6` correctly.
It is often useful to force the [acronym]`JVM` to use [acronym]`IPv4`.

It is also important to let JGroups know which networking interface you want to use;
it will bind to one interface by default, but if you have multiple network interfaces
that might not be the one you expect.

.JVM properties to set for clustering
====
[source]
----
#192.168.122.1 is an example IPv4 address
-Djava.net.preferIPv4Stack=true -Djgroups.bind_addr=192.168.122.1
----
====

[NOTE]
====
You don't need to use [acronym]`IPv4`: JGroups is compatible with [acronym]`IPv6`
provided you have routing properly configured and valid addresses assigned.

The `jgroups.bind_addr` needs to match a placeholder name
in your JGroups configuration in case you don't use the default one.
====

The default configuration uses `distribution` as cache mode
and uses the `jgroups-tcp.xml` configuration for JGroups,
which is contained in the Infinispan jar
as the default configuration for Infinispan users.
Let's see how to reconfigure this:

.Reconfiguring cache mode and override JGroups configuration
====
[source, XML]
----
<?xml version="1.0" encoding="UTF-8"?>
<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:9.1 http://www.infinispan.org/schemas/infinispan-config-9.1.xsd"
    xmlns="urn:infinispan:config:9.1">

    <jgroups>
        <stack-file name="custom-stack" path="my-jgroups-conf.xml" />
    </jgroups>

    <cache-container name="HibernateOGM" default-cache="DEFAULT">
        <transport stack="custom-stack" />

        <!-- *************************************** -->
        <!--     Default cache used as template      -->
        <!-- *************************************** -->
        <distributed-cache name="DEFAULT" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </distributed-cache>

        <!-- Override the cache mode: -->
        <replicated-cache name="User" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </replicated-cache>

        <distributed-cache name="Order" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </distributed-cache>

        <distributed-cache name="associations_User_Order" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </distributed-cache>

    </cache-container>

</infinispan>
----
====

In the example above we specify a custom JGroups configuration file
and set the cache mode for the default cache to `distribution`;
this is going to be inherited by the `Order` and the `associations_User_Order` caches.
But for `User` we have chosen (for the sake of this example) to use `replication`.

Now that you have clustering configured, start the service on multiple nodes.
Each node will need the same configuration and jars.

[TIP]
====
We have just shown how to override the clustering mode
and the networking stack for the sake of completeness, but you don't have to!

Start with the default configuration and see if that fits you.
You can fine tune these setting when you are closer to going in production.
====

[[ogm-infinispan-storage-principles]]
==== Storage principles

To describe things simply, each entity is stored under a single key.
The value itself is a map containing the columns / values pair.

Each association from one entity instance to (a set of) another is stored under a single key.
The value contains the navigational information to the (set of) entity.

[[ogm-infinispan-built-in-types]]
===== Properties and built-in types

Each entity is represented by a map.
Each property or more precisely column is represented by an entry in this map,
the key being the column name.

Hibernate OGM support by default the following property types:

* `java.lang.String`
* `java.lang.Character` (or char primitive)
* `java.lang.Boolean` (or boolean primitive); Optionally the annotations `@Type(type = "true_false")`, `@Type(type = "yes_no")` and `@Type(type = "numeric_boolean")` can be used to map boolean properties to the characters 'T'/'F', 'Y'/'N' or the int values 0/1, respectively.
* `java.lang.Byte` (or byte primitive)
* `java.lang.Short` (or short primitive)
* `java.lang.Integer` (or integer primitive)
* `java.lang.Long` (or long primitive)
* `java.lang.Integer` (or integer primitive)
* `java.lang.Float` (or float primitive)
* `java.lang.Double` (or double primitive)

* `java.math.BigDecimal`
* `java.math.BigInteger`

* `java.util.Calendar`
* `java.util.Date`
* `java.util.UUID`
* `java.util.URL`

[NOTE]
====
Hibernate OGM doesn't store null values in Infinispan,
setting a value to null is the same as removing the corresponding entry
from Infinispan.

This can have consequences when it comes to queries on null value.
====

===== Identifiers

Entity identifiers are used to build the key in which the entity is stored in the cache.

The key is comprised of the following information:

* the identifier column names
* the identifier column values
* the entity table (for the `CACHE_PER_KIND` strategy)

In `CACHE_PER_TABLE`, the table name is inferred from the cache name.
In `CACHE_PER_KIND`, the table name is necessary to identify the entity in the generic cache.

.Define an identifier as a primitive type
====
[source, JAVA]
----
@Entity
public class Bookmark {

    @Id
    private Long id;

    private String title;

    // getters, setters ...
}
----

.Content of the `Bookmark` cache in `CACHE_PER_TABLE`
[cols="3*", options="header"]
|===
     ^| KEY                   2+^| MAP ENTRIES

.2+^.^| ["id"], [42]             | id       | 42
                                 | title    | "Hibernate OGM documentation"
|===

.Content of the `ENTITIES` cache in `CACHE_PER_KIND`
[cols="3*", options="header"]
|===
     ^| KEY                   2+^| MAP ENTRIES

.2+^.^| "Bookmark", ["id"], [42] | id       | 42
                                 | title    | "Hibernate OGM documentation"
|===
====

.Define an identifier using @EmbeddedId
====
[source, JAVA]
----
@Embeddable
public class NewsID implements Serializable {

    private String title;
    private String author;

    // getters, setters ...
}

@Entity
public class News {

    @EmbeddedId
    private NewsID newsId;
    private String content;

    // getters, setters ...
}
----

.Content of the `News` cache in `CACHE_PER_TABLE`
[cols="3*", options="header"]
|===
     ^| KEY
   2+^| MAP ENTRIES

.3+^.^| [newsId.author, newsId.title], ["Guillaume", "How to use Hibernate OGM ?"]
      | newsId.author  | "Guillaume"

      | newsId.title   | "How to use Hibernate OGM ?"

      | content        | "Simple, just like ORM but with a NoSQL database"
|===

.Content of the `ENTITIES` cache in `CACHE_PER_KIND`
[cols="3*", options="header"]
|===
     ^| KEY
   2+^| MAP ENTRIES

.3+^.^| "News", [newsId.author, newsId.title], ["Guillaume", "How to use Hibernate OGM ?"]
      | newsId.author  | "Guillaume"

      | newsId.title   | "How to use Hibernate OGM ?"

      | content        | "Simple, just like ORM but with a NoSQL database"
|===
====

====== Identifier generation strategies

Since Infinispan has not native sequence nor identity column support,
these are simulated using the table strategy, however their default values vary.
We highly recommend you explicitly use a `TABLE` strategy if you want to generate a monotonic identifier.

But if you can, use a pure in-memory and scalable strategy like a UUID generator.

.Id generation strategy TABLE using default values
====
[source, JAVA]
----
@Entity
public class GuitarPlayer {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private long id;

    private String name;

    // getters, setters ...
}

----

.Content of the `hibernate_sequences` cache in `CACHE_PER_TABLE`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | ["sequence_name"], ["default"]
^.^|  2
|===

.Content of the IDENTIFIERS cache in `CACHE_PER_KIND`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | "hibernate_sequences", ["sequence_name"], ["default"]
^.^|  2
|===
====

As you can see, in `CACHE_PER_TABLE`, the key does not contain the id source table name.
It is inferred by the cache name hosting that key.

.Id generation strategy TABLE using a custom table
====
[source, JAVA]
----
@Entity
public class GuitarPlayer {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "guitarGen")
    @TableGenerator(
        name = "guitarGen",
        table = "GuitarPlayerSequence",
        pkColumnName = "seq"
        pkColumnValue = "guitarPlayer",
    )
    private long id;

    // getters, setters ...
}

----

.Content of the `GuitarPlayerSequence` cache in `CACHE_PER_TABLE`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | ["seq"], ["guitarPlayer"]
^.^| 2
|===

.Content of the IDENTIFIERS cache in `CACHE_PER_KIND`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | "GuitarPlayerSequence", ["seq"], ["guitarPlayer"]
^.^| 2
|===
====

.SEQUENCE id generation strategy
====
[source, JAVA]
----
@Entity
public class Song {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "songSequenceGenerator")
  @SequenceGenerator(
      name = "songSequenceGenerator",
      sequenceName = "song_sequence",
      initialValue = 2,
      allocationSize = 20
  )
  private Long id;

  private String title;

  // getters, setters ...
}
----

.Content of the `hibernate_sequences` cache in `CACHE_PER_TABLE`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | ["sequence_name"], ["song_sequence"]
^.^| 11
|===

.Content of the `IDENTIFIERS` cache in `CACHE_PER_KIND`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | "hibernate_sequences", "["sequence_name"], ["song_sequence"]
^.^| 11
|===
====

===== Entities

Entities are stored in the cache named after the entity name when using the `CACHE_PER_TABLE` strategy.
In the `CACHE_PER_KIND` strategy, entities are stored in a single cache named `ENTITIES`.

The key is comprised of the following information:

* the identifier column names
* the identifier column values
* the entity table (for the `CACHE_PER_KIND` strategy)

In `CACHE_PER_TABLE`, the table name is inferred from the cache name.
In `CACHE_PER_KIND`, the table name is necessary to identify the entity in the generic cache.

The entry value is an instance of `org.infinispan.atomic.FineGrainedMap`
which contains all the entity properties -
or to be specific columns.
Each column name and value is stored as a key / value pair in the map.
We use this specialized map as Infinispan is able to transport changes
in a much more efficient way.

.Default JPA mapping for an entity
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private String id;
    private String title;

    // getters, setters ...
}
----

.Content of the `News` cache in `CACHE_PER_TYPE`
[cols="3*", options="header"]
|===
     ^| KEY                        2+^| MAP ENTRIES

.2+^.^| ["id"], ["1234-5678"] | id       | "1234-5678"
                                      | title    | "On the merits of NoSQL"
|===

.Content of the `ENTITIES` cache in `CACHE_PER_KIND`
[cols="3*", options="header"]
|===
     ^| KEY                        2+^| MAP ENTRIES

.2+^.^| "News", ["id"], ["1234-5678"] | id       | "1234-5678"
                                      | title    | "On the merits of NoSQL"
|===
====

As you can see, the table name is not part of the key for `CACHE_PER_TYPE`.
In the rest of this section we will no longer show the `CACHE_PER_KIND` strategy.

.Rename field and collection using @Table and @Column
====
[source, JAVA]
----
@Entity
@Table(name = "Article")
public class News {

    @Id
    private String id;

    @Column(name = "headline")
    private String title;

    // getters, setters ...
}
----

.Content of the `Article` cache
[cols="3*", options="header"]
|===
     ^| KEY                               2+^| MAP ENTRIES

.2+^.^| ["id"], ["1234-5678"]                | id       | "1234-5678"
                                             | headline | "On the merits of NoSQL"
|===
====

====== Embedded objects and collections

.Embedded object
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private String id;
    private String title;

    @Embedded
    private NewsPaper paper;

    // getters, setters ...
}

@Embeddable
public class NewsPaper {

    private String name;
    private String owner;

    // getters, setters ...
}
----

.Content of the `News` cache
[cols="3*", options="header"]
|===
     ^| KEY                               2+^| MAP ENTRIES

.4+^.^| ["id"], ["1234-5678"]                | id          | "1234-5678"
                                             | title       | "On the merits of NoSQL"
                                             | paper.name  | "NoSQL journal of prophecies"
                                             | paper.owner | "Delphy"
|===
====

.@ElementCollection with one attribute
====
[source, JAVA]
----
@Entity
public class GrandMother {

    @Id
    private String id;

    @ElementCollection
    private List<GrandChild> grandChildren = new ArrayList<GrandChild>();

    // getters, setters ...
}

@Embeddable
public class GrandChild {

    private String name;

    // getters, setters ...
}
----

.Content of the `GrandMother` cache
[cols="3*", options="header"]
|===
     ^| KEY                            2+^| MAP ENTRIES
   ^.^| ["id"], ["granny"]                | id          | "granny"
|===

.Content of the `associations_GrandMother_grandChildren` cache in `CACHE_PER_TYPE`
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| ROW MAP ENTRIES

.4+^.^| ["GrandMother_id"], ["granny"]
.2+^.^| ["GrandMother_id", "name"], ["granny", "Leia"]
      | GrandMother_id
      | "granny"

      | name
      | "Leia"

.2+^.^| ["GrandMother_id", "name"], ["granny", "Luke"]
      | GrandMother_id
      | "granny"

      | name
      | "Luke"
|===

.Content of the `ASSOCIATIONS` cache in `CACHE_PER_KIND`
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| ROW MAP ENTRIES

.4+^.^| "GrandMother_grandChildren", ["GrandMother_id"], ["granny"]
.2+^.^| ["GrandMother_id", "name"], ["granny", "Leia"]
      | GrandMother_id
      | "granny"

      | name
      | "Leia"

.2+^.^| ["GrandMother_id", "name"], ["granny", "Luke"]
      | GrandMother_id
      | "granny"

      | name
      | "Luke"
|===
====

Here, we see that the collection of elements is stored in a separate cache and entry.
The association key is made of:

* the foreign key column names pointing to the owner of this association
* the foreign key column values pointing to the owner of this association
* the association table name in the `CACHE_PER_KIND` approach where all associations share the same cache

The association entry is a map containing the representation of each entry in the collection.
The keys of that map are made of:

* the names of the columns uniquely identifying that specific collection entry
  (e.g. for a `Set` this is all of the columns)
* the values of the columns uniquely identifying that specific collection entry

The value attack to that collection entry key is a Map containing the key value pairs column name / column value.

.@ElementCollection with @OrderColumn
====
[source, JAVA]
----
@Entity
public class GrandMother {

    @Id
    private String id;

    @ElementCollection
    @OrderColumn( name = "birth_order" )
    private List<GrandChild> grandChildren = new ArrayList<GrandChild>();

    // getters, setters ...
}

@Embeddable
public class GrandChild {

    private String name;

    // getters, setters ...
}
----

.Content of the `GrandMother` cache
[cols="3*", options="header"]
|===
     ^| KEY                            2+^| MAP ENTRIES
   ^.^| ["id"], ["granny"]                | id          | "granny"
|===

.Content of the `GrandMother_grandChildren` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| ROW MAP ENTRIES

.6+^.^| ["GrandMother_id"], ["granny"]
.3+^.^| ["GrandMother_id", "birth_order"], ["granny", 0]
      | GrandMother_id
      | "granny"

      | birth_order
      | 0

      | name
      | "Leia"

.3+^.^| ["GrandMother_id", "birth_order"], ["granny", 1]
      | GrandMother_id
      | "granny"

      | birth_order
      | 1

      | name
      | "Luke"
|===
====

Here we used an indexed collection and to identify the entry in the collection,
only the owning entity id and the index value is enough.

.@ElementCollection with Map of @Embeddable
====
[source, JAVA]
----
@Entity
public class ForumUser {

	@Id
	private String name;

	@ElementCollection
	private Map<String, JiraIssue> issues = new HashMap<>();

    // getters, setters ...
}

@Embeddable
public class JiraIssue {

	private Integer number;
	private String project;

    // getters, setters ...
}
----

.Content of the `ForumUser` cache
[cols="3*", options="header"]
|===
     ^| KEY                            2+^| MAP ENTRIES
   ^.^| ["id"], ["Jane Doe"]                | id          | "Jane Doe"
|===

.Content of the `ForumUser_issues` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| ROW MAP ENTRIES

.12+^.^| ["ForumUser_id"], ["Jane Doe"]

.4+^.^| ["ForumUser_id", "issues_KEY"], ["Jane Doe", "issueWithNull"]

      | ForumUser_id
      | Jane Doe

      | issue_KEY
      | "issueWithNull"

      | issues.value.project
      | <null>

      | issues.value.number
      | <null>

.4+^.^| ["ForumUser_id", "issues_KEY"], ["Jane Doe", "issue1"]

      | ForumUser_id
      | "Jane Doe"

      | issue_KEY
      | "issue1"

      | issues.value.project
      | "OGM"

      | issues.value.number
      | 1253

.4+^.^| ["ForumUser_id", "issues_KEY"], ["Jane Doe", "issue2"]

      | ForumUser_id
      | "Jane Doe"

      | issue_KEY
      | "issue2"

      | issues.value.project
      | "HSEARCH"

      | issues.value.number
      | 2000
|===
====

===== Associations

Associations between entities are mapped like (collection of) embeddables
except that the target entity is represented by its identifier(s).

.Unidirectional one-to-one
====
[source, JAVA]
----
@Entity
public class Vehicule {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    private Vehicule vehicule;

    // getters, setters ...
}
----

.Content of the `Vehicule` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.2+^.^| ["id"], ["V_01"]             | id             | "V_01"
                                     | brand          | "Mercedes"
|===

.Content of the `Wheel` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.3+^.^| ["id"], ["W001"]             | id             | "W001"
                                     | diameter       | 0.0
                                     | vehicule_id    | "V_01"
|===
====

[[infinispan-in-entity-one-to-one-join-column]]
.Unidirectional one-to-one with @JoinColumn
====
[source, JAVA]
----
@Entity
public class Vehicule {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    @JoinColumn( name = "part_of" )
    private Vehicule vehicule;

    // getters, setters ...
}
----

.Content of the `Vehicle` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.2+^.^| ["id"], ["V_01"]             | id             | "V_01"
                                     | brand          | "Mercedes"
|===

.Content of the `Wheel` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.3+^.^| "Wheel", ["id"], ["W001"]    | id             | "W001"
                                     | diameter       | 0.0
                                     | part_of       | "V_01"
|===
====

.Unidirectional one-to-one with @MapsId and @PrimaryKeyJoinColumn
====
[source, JAVA]
----
@Entity
public class Vehicule {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    @PrimaryKeyJoinColumn
    @MapsId
    private Vehicule vehicule;

    // getters, setters ...
}
----

.Content of the `Vehicle` cache
[cols="3*", options="header"]
|===
     ^| KEY                                2+^| MAP ENTRIES

.2+^.^| ["id"], ["V_01"]                      | id             | "V_01"
                                              | brand          | "Mercedes"
|===

.Content of the `Wheel` cache
[cols="3*", options="header"]
|===
     ^| KEY                                2+^| MAP ENTRIES

.2+^.^| ["vehicule_id"], ["V_01"]             | vehicule_id    | "V_01"
                                              | diameter       | 0.0
|===
====

.Bidirectional one-to-one
====
[source, JAVA]
----
@Entity
public class Husband {

    @Id
    private String id;
    private String name;

    @OneToOne
    private Wife wife;

    // getters, setters ...
}

@Entity
public class Wife {

    @Id
    private String id;
    private String name;

    @OneToOne(mappedBy="wife")
    private Husband husband;

    // getters, setters ...
}
----

.Content of the `Husband` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES
.3+^.^| ["id"], ["alex"]             | id             | "alex"
                                     | name           | "Alex"
                                     | wife           | "bea"
|===

.Content of the `Wife` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES
.2+^.^| ["id"], ["bea"]              | id             | "bea"
                                     | name           | "Bea"
|===

.Content of the `associations_Husband` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.2+^.^| ["wife"], ["bea"]
.2+^.^| ["id", "wife"], ["alex", "bea"]
      | id
      | "alex"

      | wife
      | "bea"
|===
====

.Unidirectional one-to-many
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

.Content of the `Basket` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.2+^.^| ["id"], ["davide_basket"]           | id               | "davide_basket"
                                            | owner            | "Davide"
|===

.Content of the `Product` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES
.2+^.^| ["name"], ["Beer"]                  | name             | "Beer"
                                            | description      | "Tactical Nuclear Penguin"

.2+^.^| ["name"], ["Pretzel"]               | name             | "Pretzel"
                                            | description      | "Glutino Pretzel Sticks"
|===

.Content of the `associations_Basket_Product` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.4+^.^| ["Basket_id"], ["davide_basket"]
.2+^.^| ["Basket_id", "products_name"], ["davide_basket", "Beer"]
      | Basket_id
      | "davide_basket"

      | products_name
      | "Beer"

.2+^.^| ["Basket_id", "products_name"], ["davide_basket", "Pretzel"]
      | Basket_id
      | "davide_basket"

      | products_name
      | "Pretzel"

|===
====

.Unidirectional one-to-many with `@JoinTable`
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    @JoinTable( name = "BasketContent" )
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

.Content of the `Basket` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.2+^.^| ["id"], ["davide_basket"]           | id               | "davide_basket"
                                            | owner            | "Davide"
|===

.Content of the `Basket` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES
.2+^.^| ["name"], ["Beer"]                  | name             | "Beer"
                                            | description      | "Tactical Nuclear Penguin"

.2+^.^| ["name"], ["Pretzel"]               | name             | "Pretzel"
                                            | description      | "Glutino Pretzel Sticks"
|===

.Content of the `associations_BasketContent` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.4+^.^| ["Basket_id"], ["davide_basket"]
.2+^.^| ["Basket_id", "products_name"], ["davide_basket", "Beer"]
      | Basket_id
      | "davide_basket"

      | products_name
      | "Beer"

.2+^.^| ["Basket_id", "products_name"], ["davide_basket", "Pretzel"]
      | Basket_id
      | "davide_basket"

      | products_name
      | "Pretzel"
|===
====

.Unidirectional one-to-many using maps with defaults
====
[source, JAVA]
----
@Entity
public class User {

    @Id
    private String id;

    @OneToMany
    private Map<String, Address> addresses = new HashMap<String, Address>();

    // getters, setters ...
}

@Entity
public class Address {

    @Id
    private String id;
    private String city;

    // getters, setters ...
}
----

.Content of the `User` cache
[cols="3*", options="header"]
|===
     ^| KEY                             2+^| MAP ENTRIES

   ^.^| ["id"], ["user_001"]               | id   | "user_001"
|===

.Content of the `Address` cache
[cols="3*", options="header"]
|===
     ^| KEY                             2+^| MAP ENTRIES
.2+^.^| ["id"], ["address_001"]            | id   | "address_001"
                                           | city | "Rome"

.2+^.^| ["id"], ["address_002"]            | id   | "address_002"
                                           | city | "Paris"
|===

.Content of the `associations_User_address` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.6+^.^| ["User_id"], "user_001"]
.3+^.^| ["User_id", "addresses_KEY"], ["user_001", "home"]
      | User_id
      | "user_001"

      | addresses_KEY
      | "home"

      | addresses_id
      | "address_001"

.3+^.^| ["User_id", "addresses_KEY"], ["user_001", "work"]
      | User_id
      | "user_002"

      | addresses_KEY
      | "work"

      | addresses_id
      | "address_002"
|===
====

.Unidirectional one-to-many using maps with @MapKeyColumn
====
[source, JAVA]
----
@Entity
public class User {

    @Id
    private String id;

    @OneToMany
    @MapKeyColumn(name = "addressType")
    private Map<String, Address> addresses = new HashMap<String, Address>();

    // getters, setters ...
}

@Entity
public class Address {

    @Id
    private String id;
    private String city;

    // getters, setters ...
}
----

.Content of the `User` cache
[cols="3*", options="header"]
|===
     ^| KEY                             2+^| MAP ENTRIES

   ^.^| ["id"], ["user_001"]               | id   | "user_001"
|===

.Content of the `Address` cache
[cols="3*", options="header"]
|===
     ^| KEY                             2+^| MAP ENTRIES
.2+^.^| ["id"], ["address_001"]            | id   | "address_001"
                                           | city | "Rome"

.2+^.^| ["id"], ["address_002"]            | id   | "address_002"
                                           | city | "Paris"
|===

.Content of the `associations_User_address` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.6+^.^| ["User_id"], "user_001"]
.3+^.^| ["User_id", "addressType"], ["user_001", "home"]
      | User_id
      | "user_001"

      | addressesType
      | "home"

      | addresses_id
      | "address_001"

.3+^.^| ["User_id", "addressType"], ["user_001", "work"]
      | User_id
      | "user_002"

      | addressesType
      | "work"

      | addresses_id
      | "address_002"
|===
====

.Unidirectional many-to-one
====
[source, JAVA]
----
@Entity
public class JavaUserGroup {

    @Id
    private String jugId;
    private String name;

    // getters, setters ...
}

@Entity
public class Member {

    @Id
    private String id;
    private String name;

    @ManyToOne
    private JavaUserGroup memberOf;

    // getters, setters ...
}
----

.Content of the `JavaUserGroup` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES

.2+^.^| ["jugId"], ["summer_camp"]                  | jugId           | "summer_camp"
                                                    | name            | "JUG Summer Camp"
|===

.Content of the `Member` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES
.3+^.^| ["member_id"], ["emmanuel"]                 | member_id       | "emmanuel"
                                                    | name            | "Emmanuel Bernard"
                                                    | memberOf_jug_id | "summer_camp"

.3+^.^| ["member_id"], ["jerome"]                   | member_id       | "jerome"
                                                    | name            | "Jerome"
                                                    | memberOf_jug_id | "summer_camp"
|===
====

.Bidirectional many-to-one
====
[source, JAVA]
----
@Entity
public class SalesForce {

    @Id
    private String id;
    private String corporation;

    @OneToMany(mappedBy = "salesForce")
    private Set<SalesGuy> salesGuys = new HashSet<SalesGuy>();

    // getters, setters ...
}

@Entity
public class SalesGuy {
    private String id;
    private String name;

    @ManyToOne
    private SalesForce salesForce;

    // getters, setters ...
}
----

.Content of the `SalesForce` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES

.2+^.^| ["id"], ["red_hat"]                         | id              | "red_hat"
                                                    | corporation     | "Red Hat"
|===

.Content of the `SalesGuy` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES
.3+^.^| ["id"], ["eric"]                            | id              | "eric"
                                                    | name            | "Eric"
                                                    | salesForce_id   | "red_hat"

.3+^.^| ["id"], ["simon"]                           | id              | "simon"
                                                    | name            | "Simon"
                                                    | salesForce_id   | "red_hat"
|===

.Content of the `associations_SalesGuy` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.4+^.^| ["salesForce_id"], ["red_hat"]
.2+^.^| ["salesForce_id", "id"], ["red_hat", "eric"]
      | salesForce_id
      | "red_hat"

      | id
      | "eric"

.2+^.^| ["salesForce_id", "id"], ["red_hat", "simon"]
      | salesForce_id
      | "red_hat"

      | id
      | "simon"
|===
====

.Unidirectional many-to-many
====
[source, JAVA]
----
@Entity
public class Student {

    @Id
    private String id;
    private String name;

    // getters, setters ...
}

@Entity
public class ClassRoom {

    @Id
    private long id;
    private String lesson;

    @ManyToMany
    private List<Student> students = new ArrayList<Student>();

    // getters, setters ...
}
----

The "Math" class has 2 students: John Doe and Mario Rossi

The "English" class has 2 students: Kate Doe and Mario Rossi

.Content of the `ClassRoom` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES

.2+^.^| ["id"], [1]                    | id         | 1
                                       | name       | "Math"

.2+^.^| ["id"], [2]                    | id         | 2
                                       | name       | "English"
|===

.Content of the `Student` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES
.2+^.^| ["id"], ["john"]               | id         | "john"
                                       | name       | "John Doe"

.2+^.^| ["id"], ["mario"]              | id         | "mario"
                                       | name       | "Mario Rossi"

.2+^.^| ["id"], ["kate"]               | id         | "kate"
                                       | name       | "Kate Doe"
|===

.Content of the `associations_ClassRoom_Student` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.4+^.^| ["ClassRoom_id"], [1]
.2+^.^| ["ClassRoom_id", "students_id"], [1, "mario"]
      | ClassRoom_id
      | 1

      | students_id
      | "mario"

.2+^.^| ["ClassRoom_id", "students_id"], [1, "john"]
      | ClassRoom_id
      | 1

      | students_id
      | "john"

.4+^.^| ["ClassRoom_id"], [2]
.2+^.^| ["ClassRoom_id", "students_id"], [2, "kate"]
      | ClassRoom_id
      | 2

      | students_id
      | "kate"

.2+^.^| ["ClassRoom_id", "students_id"], [2, "mario"]
      | ClassRoom_id
      | 2

      | students_id
      | "mario"
|===
====

.Bidirectional many-to-many
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany( mappedBy = "bankAccounts" )
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

David owns 2 accounts: "012345" and "ZZZ-009"

.Content of the `AccountOwner` cache
[cols="3*", options="header"]
|===
     ^| KEY                               2+^| MAP ENTRIES

.2+^.^| ["id"], ["David"]                    | id            | "David"
                                             | SSN           | "0123456"
|===

.Content of the `BankAccount` cache
[cols="3*", options="header"]
|===
     ^| KEY                               2+^| MAP ENTRIES
.2+^.^| ["id"], ["account_1"]                | id            | "account_1"
                                             | accountNumber | "X2345000"

.2+^.^| ["id"], ["account_2"]                | id            | "account_2"
                                             | accountNumber | "ZZZ-009"
|===

.Content of the `AccountOwner_BankAccount` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.2+^.^| ["bankAccounts_id"], ["account_1"]
.2+^.^| ["bankAccounts_id", "owners_id"], ["account_1", "David"]
      | bankAccounts_id
      | "account_1"

      | owners_id
      | "David"

.2+^.^| ["bankAccounts_id"], ["account_2"]
.2+^.^| ["bankAccounts_id", "owners_id"], ["account_2", "David"]
      | bankAccounts_id
      | "account_2"

      | owners_id
      | "David"

.4+^.^| ["owners_id"], ["David"]
.2+^.^| ["owners_id", "banksAccounts_id"], ["David", "account_1"]
      | bankAccounts_id
      | "account_1"

      | owners_id
      | "David"

.2+^.^| ["owners_id", "banksAccounts_id"], ["David", "account_2"]
      | bankAccounts_id
      | "account_2"

      | owners_id
      | "David"

|===
====

[[ogm-infinispan-transactions]]

==== Transactions

Infinispan supports transactions and integrates with any standard JTA `TransactionManager`;
this is a great advantage for JPA users as it allows to experience a _similar_ behaviour
to the one we are used to when we work with RDBMS databases.

This capability is only available to Infinispan Embedded users: the transactional integration
capabilities are not exposed to the Hot Rod clients.

If you're having Hibernate OGM start and manage Infinispan,
you can skip this as it will inject the same `TransactionManager` instance
which you already have set up in the Hibernate / JPA configuration.

If you are providing an already started Infinispan CacheManager instance
by using the [acronym]`JNDI` lookup approach,
then you have to make sure the CacheManager is using the same `TransactionManager`
as Hibernate:

.Configuring a JBoss Standalone TransactionManager lookup in Infinispan configuration
====
[source, XML]
----
<default>
   <transaction
      transactionMode="TRANSACTIONAL"
      transactionManagerLookupClass=
    "org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup" />
</default>
----
====

Infinispan supports different transaction modes like `PESSIMISTIC` and `OPTIMISTIC`,
supports [acronym]`XA` recovery and provides many more configuration options;
see the http://infinispan.org/documentation/[Infinispan User Guide]
for more advanced configuration options.

[[ogm-infinispan-indexstorage]]

==== Storing a Lucene index in Infinispan

Hibernate Search, which can be used for advanced query capabilities (see <<ogm-query>>),
needs some place to store the indexes for its embedded `Apache Lucene` engine.

A common place to store these indexes is the filesystem
which is the default for Hibernate Search;
however if your goal is to scale your NoSQL engine on multiple nodes
you need to share this index.
Network sharing file systems are a possibility but we don't recommended that.
Often the best option is to store the index
in whatever NoSQL database you are using (or a different dedicated one).

[TIP]
====
You might find this section useful even if you don't intend to store your data in Infinispan.
====

The Infinispan project provides an adaptor to plug into Apache Lucene,
so that it writes the indexes in Infinispan and searches data in it.
Since Infinispan can be used as an application cache to other NoSQL storage engines
by using a CacheStore (see <<ogm-infinispan-storage>>)
you can use this adaptor to store the Lucene indexes
in any NoSQL store supported by Infinispan:

* JDBC databases
* Cassandra
* Filesystem (but locked correctly at the Infinispan level)
* MongoDB
* HBase
* LevelDB
* A secondary (independent) Infinispan grid

How to configure it? Here is a simple cheat sheet to get you started with this type of setup:

* Add `org.infinispan:infinispan-directory-provider:{infinispanVersion}` to your dependencies
* set these configuration properties:

** `hibernate.search.default.directory_provider = infinispan`
** `hibernate.search.default.exclusive_index_use = false`
** `hibernate.search.infinispan.configuration_resourcename =` [infinispan configuration filename]

This configuration is simple and will work fine in most scenarios, but keep in mind that using
'exclusive_index_use' will be neither fast nor scalable.
For high performance, high concurrency or production use please refer to the
http://infinispan.org/documentation/[Infinispan documentation] for more advanced configuration options and tuning.

The referenced Infinispan configuration should define a `CacheStore`
to load/store the index in the NoSQL engine of choice.
It should also define three cache names:

.Infinispan caches used to store indexes
[cols="1,2,1", options="header"]
|===============
|Cache name|Description|Suggested cluster mode
|LuceneIndexesLocking|Transfers locking information. Does not need a cache
            store.|replication
|LuceneIndexesData|Contains the bulk of Lucene data. Needs a cache
            store.|distribution + L1
|LuceneIndexesMetadata|Stores metadata on the index segments. Needs a cache
            store.|replication
|===============

This configuration is not going to scale well on write operations:
to do that you should read about the master/slave and sharding options in Hibernate Search.
The complete explanation and configuration options can be found in the
https://docs.jboss.org/hibernate/search/{hibernate-search-major-minor-version}/reference/en-US/html_single/#infinispan-directories[Hibernate Search Reference Guide]

Some NoSQL support storage of Lucene indexes directly,
in which case you might skip the Infinispan Lucene integration
by implementing a custom `DirectoryProvider` for Hibernate Search.
You're very welcome to share the code
and have it merged in Hibernate Search for others to use, inspect, improve and maintain.

[[ogm-infinispan-remote]]

=== Hibernate OGM & Infinispan Server over Hot Rod

In this section we'll see how to configure Hibernate OGM to connect to
"Infinispan Server using the Hot Rod protocol", which we will call "Infinispan Remote"
for brevity and to differentiate it from "Infinispan Embedded".

In this mode Hibernate OGM can not boostrap or otherwise control the lifecycle
of Infinispan, so we will assume that you already have a cluster of Infinispan Server
nodes running.
For instructions on setting one up, see the http://infinispan.org/docs/stable/server_guide/server_guide.html[Infinispan Server Guide].

The good news is that - since it's a separate service - there won't be much to configure
in Hibernate OGM.

[CAUTION]
====
The Hibernate OGM support for Infinispan Remote is considered experimental.
In particular, the storage format is not set in stone.
====

==== Adding Infinispan Remote dependencies

To use Hibernate OGM to connect to an Infinispan Server using the Hot Rod protocol, you will need the following extension
and its transitive dependencies (which include, among others, the Hot Rod client):

[source, XML]
[subs="verbatim,attributes"]
----
<dependency>
    <groupId>org.hibernate.ogm</groupId>
    <artifactId>hibernate-ogm-infinispan-remote</artifactId>
    <version>{hibernate-ogm-version}</version>
</dependency>
----

==== Configuration properties for Infinispan Remote

First, let Hibernate know that you want to use the OGM Infinispan Remote datastore by setting the
`hibernate.ogm.datastore.provider` property to `infinispan_remote`.

The next step is to configure the Hot Rod client.
You have two options:

* either provide a resource file containing all Hot Rod client configuration properties
* or include all the Hot Rod client configuration properties with a custom prefix, as explained below.

To use an external configuration resource, set the `hibernate.ogm.infinispan_remote.configuration_resource_name`
configuration property to the resource name.

.Using a separate resource to configure the Hot Rod client
====
[source, XML]
----
<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
	version="2.0">

	<persistence-unit name="ogm-with-hotrod">
		<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider> # <1>
		<properties>
			<property name="hibernate.ogm.datastore.provider"
				value="infinispan_remote" /> # <2>
			<property name="hibernate.ogm.infinispan_remote.configuration_resource_name"
				value="hotrodclient.properties" /> # <3>
		</properties>
	</persistence-unit>
</persistence>
----
<1> Choose Hibernate OGM as JPA Provider
<2> pick `infinispan_remote` as datastore
<3> point to the Hot Rod configuration file

[source]
----
infinispan.client.hotrod.server_list = 127.0.0.1:11222
infinispan.client.hotrod.tcp_no_delay = true
infinispan.client.hotrod.tcp_keep_alive = false

## below is connection pooling config
maxActive=-1
maxTotal = -1
maxIdle = -1
whenExhaustedAction = 1
timeBetweenEvictionRunsMillis = 120000
minEvictableIdleTimeMillis = 300000
testWhileIdle = true
minIdle = 1
----
====

Alternatively you can embed the Hot Rod properties in your Hibernate (or JPA) configuration
file, but you'll have to replace the `infinispan.client.hotrod.` prefix with the custom
prefix `hibernate.ogm.infinispan_remote.client.`.

Some of the Hot Rod client configuration properties don't normally use a prefix - specifically
all properties relating to connection pooling as in the previous example - these will also
need to use the `hibernate.ogm.infinispan_remote.client.` prefix.

Properties set with the `hibernate.ogm.infinispan_remote.client.` prefix will override the same
properties configured using an external reosurce file.

.Embedding the Hot Rod client configuration properties in the Hibernate configuration
====
[source, XML]
----
<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
	version="2.0">

	<persistence-unit name="ogm-with-hotrod">
		<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider> # <1>
		<properties>
			<property name="hibernate.ogm.datastore.provider"
				value="infinispan_remote" /> # <2>
			<property name="hibernate.ogm.infinispan_remote.client.server_list"
				value="127.0.0.1:11222" /> # <3>
			<property name="hibernate.ogm.infinispan_remote.client.tcp_no_delay"
				value="true" />
			<property name="hibernate.ogm.infinispan_remote.client.tcp_keep_alive"
				value="false" />
			<property name="hibernate.ogm.infinispan_remote.client.maxActive"
				value="-1" />
			<property name="hibernate.ogm.infinispan_remote.client.maxTotal"
				value="-1" />
			<property name="hibernate.ogm.infinispan_remote.client.maxIdle"
				value="-1" />
			<property name="hibernate.ogm.infinispan_remote.client.whenExhaustedAction"
				value="1" />
			<property name="hibernate.ogm.infinispan_remote.client.timeBetweenEvictionRunsMillis"
				value="120000" />
			<property name="hibernate.ogm.infinispan_remote.client.minEvictableIdleTimeMillis"
				value="300000" />
			<property name="hibernate.ogm.infinispan_remote.client.testWhileIdle"
				value="true" />
			<property name="hibernate.ogm.infinispan_remote.client.minIdle"
				value="1" />
		</properties>
	</persistence-unit>
</persistence>
----
<1> Choose Hibernate OGM as JPA Provider
<2> pick `infinispan_remote` as datastore
<3> include Hot Rod configuration properties, just replacing/adding the OGM prefix.
====

In the next section we'll see a couple more advanced properties which might be of interest.

hibernate.ogm.infinispan_remote.schema_capture_service::
If you set this to an implementation of `org.hibernate.ogm.datastore.infinispanremote.schema.spi.SchemaCapture` you
can collect any generated Protobuf Schema. Could be useful for integrations with other tools.
You can either provide a fully qualified classname or a `SchemaCapture`, or pass an instance of a `SchemaCapture`
in the configuration properties, if you're booting Hibernate programmatically.

hibernate.ogm.infinispan_remote.schema_package_name::
Defines the package name of the generated Protobuf schema. Defaults to `HibernateOGMGenerated`.
Useful to isolate different applications using the same Infinispan Server instance.

==== Data encoding: Protobuf Schema

Using the _Infinispan Remote_ backend your data will be encoded using Protocol Buffers,
also known as Protobuf.

> Protocol Buffers are a language-neutral, platform-neutral
> extensible mechanism for serializing structured data
> -- https://developers.google.com/protocol-buffers/

This encoding strategy will be used both during _transmission_ to and from the datagrid, and
as a _storage format_ on the Infinispan Server.

Typical usage of Google's developer tools for Java would require you to download the `protoc`
compiler to generate Java stubs; you won't need that when using Hibernate OGM as the backend
will generate the encoding and decoding functions on the fly from your entities.

The benefit of having Hibernate OGM generate the schema for you will make it easier to get
started, but there's a drawback: you are not directly in control of the protobuf schema
It will deploy this schema - or expect a compatible schema to be deployed - as it will use
its generated codecs to read and write data to the Infinispan Server.

The protobuf technology is designed to allow evolution of your schema: you can deploy a
different schema on the Infinispan Server than the one OGM expects, but this is an advanced
topic and you'll have to make sure the deployed schema is compatible with the one OGM is
generating and using.

Another reason to make sure the deployed protobuf schema is a _compatible evolution_ of
a previous schema, is to make sure you can still read data which is already stored in
the datagrid.

[IMPORTANT]
====
Remember that the Protobuf schema is used both during _transmission_ and _storage_.
The fact that it's used also during _transmission_ of your data is a key difference to the
schema of a SQL database.

For example even if a property "A" is not nullable in terms of storage, you will still
want it to be flagged as `optional` in a protobuf schema to allow, for example, retrieving
a subset of data properties without having to always retrieve the property "A".
====

You don't need to do anything regarding the schema: Hibernate OGM will automatically
deploy it to the Infinispan datagrid at boostrap of Hibernate.
You might want to keep this in mind though, both to be able to evolve your schema
without data loss, and to be able to generate decoders for other Infinispan clients not
using Hibernate OGM.

The deployed schemas can be fetched from the Infinispan Server; Hibernate OGM also
logs the generated schemas at `INFO` level in the logging category
`org.hibernate.ogm.datastore.infinispanremote.impl.protobuf.SchemaDefinitions`.

[[storage-principles-of-infinispan-dataprovider]]

==== Storage Principles of the Infinispan Remote dataprovider

This is actually very simple.

Imagine you were mapping your entities to a traditional, table based [acronym]`RDBMS`;
now instead of tables, you have caches. Each cache has a name, and a consistent schema,
and for each cache we define a key with some properties (the id, aka the primary key).

Relations are mapped by encoding a "foreign key"; these are used either as keys perform
a key lookup on another table, or can be used in queries on other tables to identify
relations which have a higher than one cardinality.

So let's highlight the differences with the relational world:

Referential integrity::
While we can use relations based on foreign keys, Infinispan has no notion of referential integrity.
Hibernate is able to maintain the integrity as it won't "forget" stale references, but since
the storage doesn't support transactions either it is possible to interrupt Hibernate OGM
during such maintenance and introduce breaks of integrity.

When integrity could be broken::
When the unit of work involves several operations we might risk to have a partial writes
(updates, deletes, inserts); due to the fact that the Hot Rod client is not transactional
some operation would be flushed to data store, other not.
For instance let's imagine you create a new entity, remove an old one and update an association
from the old to the new one in a single transaction,
this would correspond to three different remote invocations: an Entity insert, an Entity delete
and an Association update.
If there were network problems during the third invocation,
we could have a partial write in which only the first and the second operations
would be actually stored on the remote storage and this could lead to a breaking referential
integrity of the association.

How to detect broken integrity::
Unfortunately, at the moment the only way to detect a referential integrity error is to
inspect the logs for error messages or periodically monitor the associations cache.

A key. And a Value.::
In a key/value store the two elements _key_ and _value_ are different, separate objects.
The schema - and consequentially all operations - generated by Hibernate OGM will treat
and encode these two objects separately. You will notice that the attributes of the key
are encoded in the value *as well*, as it is not possible to run e.g. range queries
on attributes of keys.

No Sequences, no auto-incrementing values::
Infinispan does not support sequences, yet allows concurrent "compare and set" operations;
Hibernate OGM makes use of such CAS operations to emulate the need of sequences or auto-incrementing
primary keys if your entity mapping uses them, however this solution might not work
under high load: make sure to use a different strategy, such as assigning IDs explicitly,
or using the `org.hibernate.id.UUIDGenerator` generator.
Hibernate OGM will log a warning if it detects excessive spinning on such CAS operations.

Not mapped to JDBC types, but to Protobuf types::
Rather than mapping your Java properties to corresponding JDBC (SQL) types, your Java
properties are mapped to Protobuf types.
See the https://developers.google.com/protocol-buffers/docs/proto#scalar[protobuf documentation]
for an overview of protocol buffer "primitive" types.

.Example auto-generated Protobuf Schema for a simple entity
====
[source, JAVA]
----
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Hypothesis {

	@Id String id;

	String description;

	@Column(name = "pos")
	int position;

}
----
[source]
----
package HibernateOGMGenerated; # <1>

message Hypothesis_id { # <2>
	required string id = 1;
}

message Hypothesis {
	required string id = 1;
	optional string description = 2;
	optional int32 pos = 3;  # <3>
}
----
<1> The default Protobuf package name.
<2> A dedicated message type for the Key of the Key/Value pair
<3> The `pos` attribute name respects the option of the `@Column` annotation
====

The above example shows how a Protobuf schema looks like, as automatically generated from a mapped entity.
Any property type supported by Hibernate ORM will be converted to a matching Protobuf type.

===== Each Table requires a Cache with the same name

In a relational database world, when Hibernate defines the schema this implicitly creates the tables;
this is not the case on Infinispan.

With Infinispan, the _Protobuf Schema_ just unlocks the capability to transmit messages with
such payloads (read/write), and allows the remote servers to process the fields, for example
to execute queries and extract projections out of the stored entries.
So this establishes a transmission and storage encoding contract, but doesn't actually
start or allocate any storing Cache.

Hibernate OGM by convention will write to several named ``Cache``s, mapping each "table name"
to a "cache name". In the above example, when having an `Hypothesis` entity this will
write to a Cache named `Hypothesis`.

The benefit is that you can tune each cache (each "table") independently; for example you could
configure the caches for the most important data to have a synchronous CacheStore which replicates
data to a relational database, and have less important entries use an asynchronous CacheStore,
or none at all, to favour performance over redundancy.

The drawback of this design choice is that each named cache must be pre-defined in the Infinispan
Server configuration: at this point, the Hot Rod protocol is not allowed to start missing caches
so Hibernate OGM can not define the missing tables automatically.
It generates the encoding protobuf, but you have to list the Cache names in the server configuration.

[WARNING]
====
For each "table name" your model would generate on a relational database, you have to define
a matching Cache on the Infinispan Server.

If any Cache is missing, Hibernate OGM will fail to start and list which table names were
expected, but not found. We plan to automate the creation of missing caches in the future.
====

==== Known Limitations & Future improvements

The Infinispan Remote dataprovider has some known limitations, some of which are
unsolvable without further development of Infinispan itself.

Transaction Support::
We're eagerly waiting for Infinispan to support transactions over Hot Rod, as it
already provides this feature in Embedded Mode.

Queries::
At this point the Hibernate OGM backend is able to run the queries it needs to materialize
relations, but does not yet translate JPQL queries nor Criteria queries to the
Infinispan remote queries.

Indexing::
Infinispan supports Hibernate Search annotations directly embedded within its protobuf
schema definitions; this would enable the queries on them to use indexes.
Hibernate OGM doesn't generate these annotations in the schemas it generates yet.

Native support for write skew checks::
The Hot Rod client has native support for versioning of datagrid entries, yet this is
not supported on all of the client APIs. For Hibernate OGM to be able to consistently
use versioning requires enhancements to the Hot Rod client API.

Enums::
Protobuf has native support for Enum types, yet the JPA annotations force to choose
between ordinal or string encoding. We might have to introduce a "native" encoding,
probably via a novel mapping annotation.
Hibernate OGM supports the native protobuf Encoding but the JPA metadata will always
force the ordinal or string representations.

Nesting and embedding::
The Protobuf schema could allow us to embed objects, including series of objects,
as nested elements. This could allow mappings similar to the document based NoSQL
stores, such as our MongoDB dialect, but is not supported yet.

Automatic creating of ``Cache``s::
When deploying the _Protobuf Schema_, we should also automatically define and start
the needed Caches if they are not defined.
This is currently not allowed over the Hot Rod protocol.

[[ogm-infinispan]]

// vim: set colorcolumn=100:

== Infinispan

Infinispan is an open source in-memory data grid focusing on high performance.
As a data grid, you can deploy it on multiple servers - referred to as nodes -
and connect to it as if it were a single storage engine:
it will cleverly distribute both the computation effort and the data storage.

It is trivial to setup on a single node and Hibernate OGM knows how to boot one,
so you can easily try it out.
But Infinispan really shines in multiple node deployments:
you will need to configure some networking details
but nothing changes in terms of application behaviour,
while performance and data size can scale linearly.

From all its features we will only describe those relevant to Hibernate OGM;
for a complete description of all its capabilities and configuration options,
refer to the Infinispan project documentation at
http://infinispan.org/documentation/[infinispan.org].

=== Why use Hibernate OGM with Infinispan?

Infinispan provides great scalability and elasticity features but
it can have a steep learning curve.

If you are already familiar with the JPA API you will
be able to store your data in Infinispan quickly and you will also benefit
from the optimizations that a framework like Hibernate OGM can
apply under the hood.

In particular:

* you can get started without having to learn `Protobuf` first
* no need to learn the Infinispan API
* Hibernate OGM will setup and manage the `Hot Rod client` for you
* same API as Hibernate ORM, meaning that you can use the same tools

You will still need to learn about Infinispan, all its capabilities and how to configure
them to reach your application top performance, but you can get a proof of concept
done quickly with the example configuration.

=== Infinispan: Choosing between Embedded Mode and Hot Rod

Java applications can use Infinispan in two fundamentally different ways:

* Run Infinispan in _Embedded Mode_.
* Connect to an _Infinispan Server_ using an _Hot Rod client_.

Hibernate OGM supports connecting in either mode, but since the APIs and capabilities
are different in the two modes, it provides two different modules
each having its own set of configuration options and features.

Running Infinispan in _Embedded Mode_ implies that the Infinispan node is running
in the same JVM as the code using it.
The benefit is that some data (or all data) will be stored on the same JVM, making reads
of this data extremely fast and efficient as there won't be RPCs to other systems.
Write operations will still need to issue some coordination RPCs but they also
benefit from a reduction of necessary operations.

However the very fact that some data is stored in the same JVM is also the drawback
of this choice: this typically implies having to configure your JVM for larger
heap sizes, which are harder to tune for optimal performance. Other system
parameters might also need to be configured as this JVM node is now to be treated
as a "data holding node" rather than a stateless app node.
Some architects and system administrators will not like that.

When connecting to an _Infinispan Server_ over the _Hot Rod client_, the architecture
is similar to having Hibernate connect to traditional database: the data is stored
on the _Infinispan Server_ nodes, and Hibernate OGM uses a client with a pool of
TCP connections to talk to the server.

Another important difference, is that when connecting to _Infinispan Server_ via
_Hot Rod_ the data is encoded using _Google Protobuf_, which requires a schema.
This schema is auto-generated by Hibernate OGM.

Having a _Protobuf Schema_ makes it possible to evolve the schema in non-destructive
ways, and makes it possible for other clients to access the data - even clients written
in other programming languages.

[NOTE]
====
Most introductory tutorials of Hibernate OGM focus on Infinispan in _Embedded Mode_
because in this mode OGM can start its own embedded Infinispan node, using
a simple, local only Infinispan configuration.

When using _Infinispan Server_ instead, you'll need to http://infinispan.org/download/[download
the server distribution], unpack and start it, then set the Hibernate OGM configuration
properties so that the integrated Hot Rod client knows how to connect to it.
====

[TIP]
====
[.lead]
Advanced performance options & interaction with Hibernate 2nd level caching

When using Infinispan in Embedded Mode, and it's caches are configured in `REPLICATION` Mode,
all nodes will contain a full replica of the database: write performance won't scale but
your reads will be very fast and scale up linearly with the size of the cluster,
making usage of Hibernate's 2nd level cache redundant.

When configuring Infinispan in `DISTRIBUTED` cache mode, each of your nodes will have a
local copy of a slice of your data; remember you can tune how large the section
should be with various Infinispan configuration options (such as _numOwners_), and you
could combine this with Hibernate's 2nd level caching and/or enable Infinispan's
1st level caching.

You can even combine Infinispan with having it passivate to other storage systems
such as a RDBMs or another NoSQL engine; such storage can be configured to be asynchronous.
This option is available to both Infinispan Embedded and Infinispan Server; it's even possible
to use a light layer of Infinispan Embedded - containing a small data set - and have it
backed by an Infinispan Server cluster to expand its storage capabilities without
having to enlarge heap size too much on the embedded, application nodes.

Finally, remember that options such as replication vs distribution (`CacheMode`) and passivation
to additional storage (``CacheStore``s) can be configured differently for each of Infinispan caches.
====

[[ogm-infinispan-embedded]]
=== Hibernate OGM & Infinispan Embedded

Let's see how to configure and use Hibernate OGM with Infinispan in Embedded Mode.

For usage of Infinispan Server over Hot Rod, skip to <<ogm-infinispan-remote>>.

[[ogm-infinispan-configuration]]

==== Configure Hibernate OGM for Infinispan Embedded

You configure Hibernate OGM and Infinispan in two steps basically:

* Add the dependencies to your classpath
* And then choose one of:

** Use the default Infinispan configuration (no action needed)
** Point to your own configuration resource file
** Point to a [acronym]`JNDI` name of an existing instance of an Infinispan `CacheManager`

* If you need to run JPQL or HQL queries, add Hibernate Search on the classpath
  (<<ogm-query-using-hibernate-search>>)

Note that, except when using [acronym]`JNDI`, Hibernate OGM will bootstrap and Infinispan Embedded node
in your same JVM, and terminate it on shutdown of the Hibernate instance.

[CAUTION]
====
If you have Hibernate OGM boot Infinispan using a clustered configuration, this might automatically join the cluster of
other Infinispan nodes running in your network: the default is automatic discovery!
====

[[ogm-infinispan-adddepencies]]

==== Adding Infinispan dependencies

To add the dependencies for the Hibernate OGM extensions for Infinispan Embedded via Maven, add the following module:

[source, XML]
[subs="verbatim,attributes"]
----
<dependency>
    <groupId>org.hibernate.ogm</groupId>
    <artifactId>hibernate-ogm-infinispan-embedded</artifactId>
    <version>{hibernate-ogm-version}</version>
</dependency>
----

If you're not using a dependency management tool,
copy all the dependencies from the distribution in the directories:

* `/lib/required`
* `/lib/infinispan`
* Optionally - depending on your container - you might need some of the jars from `/lib/provided`

[[ogm-infinispan-configuration-properties]]

==== Infinispan specific configuration properties

The advanced configuration details of an Infinispan Cache
are defined in an Infinispan specific XML configuration file;
the Hibernate OGM properties are simple
and usually just point to this external resource.

To use the default configuration provided by Hibernate OGM -
which is a good starting point for new users - you don't have to set any property.

.Hibernate OGM properties for Infinispan
`hibernate.ogm.datastore.provider`::
Set it to `infinispan_embedded` to use Infinispan as the datastore provider in embedded mode.
`hibernate.ogm.infinispan.cachemanager_jndi_name`::
If you have an Infinispan `EmbeddedCacheManager` registered in JNDI,
provide the JNDI name and Hibernate OGM will use this instance
instead of starting a new `CacheManager`.
This will ignore any further configuration properties
as Infinispan is assumed being already configured.
Infinispan can typically be pushed to JNDI via WildFly, Spring or Seam.
`hibernate.ogm.infinispan.configuration_resource_name`::
Should point to the resource name of an Infinispan configuration file.
This is ignored in case [acronym]`JNDI`  lookup is set.
Defaults to `org/hibernate/ogm/datastore/infinispan/default-config.xml`.
`hibernate.ogm.datastore.keyvalue.cache_storage`::
The strategy for persisting data in Infinispan.
The following two strategies exist (values of the `org.hibernate.ogm.datastore.keyvalue.options.CacheMappingType` enum):

* `CACHE_PER_TABLE`: A dedicated cache will be used for each entity type, association type and id source table.
* `CACHE_PER_KIND`: Three caches will be used: one cache for all entities, one cache for all associations and one cache for all id sources.

+
Defaults to `CACHE_PER_TABLE`. It is the recommended strategy as it makes it easier to target a specific cache for a given entity.
`hibernate.ogm.datastore.create_database`::
If set to `true` Hibernate OGM will create any missing Cache definitions on the Infinispan Server.
This requires the Infinispan Server configuration to have a default configuration defined, as this will be copied to the newly defined caches.
If set to `false` an exception is thrown when a Cache is expected but not explicitly configured on the server.
Defaults to `false`.

[NOTE]
====
When bootstrapping a session factory or entity manager factory programmatically,
you should use the constants accessible via `org.hibernate.ogm.datastore.infinispan.InfinispanProperties`
when specifying the configuration properties listed above.

Common properties shared between stores are declared on `OgmProperties`
(a super interface of `InfinispanProperties`).

For maximum portability between stores, use the most generic interface possible.
====

==== Cache names used by Hibernate OGM

Depending on the cache mapping approach, Hibernate OGM will either:

* store each entity type, association type and id source table in a dedicated cache
  very much like what Hibernate ORM would do. This is the `CACHE_PER_TABLE` approach.
* store data in three different caches when using the `CACHE_PER_KIND` approach:
** `ENTITIES`: is going to be used to store the main attributes of all your entities.
** `ASSOCIATIONS`: stores the association information representing the links between entities.
** `IDENTIFIER_STORE`: contains internal metadata that Hibernate OGM needs
    to provide sequences and auto-incremental numbers for primary key generation.

The preferred strategy is `CACHE_PER_TABLE` as it offers both more fine grained configuration options
and the ability to work on specific entities in a more simple fashion.

In the following paragraphs, we will explain which aspects of Infinispan
you're likely to want to reconfigure from their defaults.
All attributes and elements from Infinispan which we don't mention are safe to ignore.
Refer to the http://infinispan.org/documentation/[Infinispan User Guide]
for the guru level performance tuning and customizations.

An Infinispan configuration file is an XML file complying with the Infinispan schema;
the basic structure is shown in the following example:

.Simple example of an Infinispan configuration file
====
[source, XML]
----
<?xml version="1.0" encoding="UTF-8"?>
<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:9.1 http://www.infinispan.org/schemas/infinispan-config-9.1.xsd"
    xmlns="urn:infinispan:config:9.1">

    <cache-container name="HibernateOGM" default-cache="DEFAULT">

        <!-- Default cache settings -->
        <local-cache name="DEFAULT">
            <transaction mode="NON_DURABLE_XA" />
        </local-cache>

        <local-cache name="User"/>

        <local-cache name="Order"/>

        <local-cache name="associations_User_Order"/>

    </cache-container>
</infinispan>
----
====

There are global settings that can be set before the `cache_container` section.
These settings will affect the whole instance;
mainly of interest for Hibernate OGM users is the `jgroups` element
in which we will set JGroups configuration overrides.

Inside the `cache-container` section are defined explicit named caches and their configurations
as well as the default cache (named `DEFAULT` here) if we want to affect all named caches.
This is where we will likely want to configure clustering modes, eviction policies and ``CacheStore``s.

[[ogm-infinispan-storage]]

==== Manage data size

In its default configuration Infinispan stores all data in the heap of the JVM;
in this barebone mode it is conceptually not very different than using a HashMap:
the size of the data should fit in the heap of your VM,
and stopping/killing/crashing your application will get all data lost
with no way to recover it.

To store data permanently (out of the JVM memory) a `CacheStore` should be enabled.
The Infinispan project provides many `CacheStore` implementations;
a simple one is the http://infinispan.org/docs/stable/user_guide/user_guide.html#single_file_store["Single File Store"]
which is able to store data in simple binary files, on any read/write mounted filesystem;
You can find many more implementations to store your data in anything
from JDBC connected relational databases, other NoSQL engines such as MongoDB and Cassandra,
or even delegate to other Infinispan clusters.
Finally, implementing a custom `CacheStore` is quite easy.

To limit the memory consumption of the precious heap space,
you can activate a `passivation` or an `eviction` policy;
again there are several strategies to play with,
for now let's just consider you'll likely need one to avoid running out of memory
when storing too many entries in the bounded JVM memory space;
of course you don't need to choose one while experimenting with limited data sizes:
enabling such a strategy doesn't have any other impact
in the functionality of your Hibernate OGM application
(other than performance: entries stored in the Infinispan in-memory space
is accessed much quicker than from any CacheStore).

A `CacheStore` can be configured as write-through,
committing all changes to the `CacheStore` before returning (and in the same transaction)
or as write-behind.
A write-behind configuration is normally not encouraged in storage engines,
as a failure of the node implies some data might be lost
without receiving any notification about it,
but this problem is mitigated in Infinispan because of its capability
to combine CacheStore write-behind
with a synchronous replication to other Infinispan nodes.

.Enabling a FileCacheStore and eviction
====

[source, XML]
----
<local-cache name="User">
    <transaction mode="NON_DURABLE_XA" />
    <eviction strategy="LIRS" max-entries="2000"/>
    <persistence passivation="true">
        <file-store
           shared="false"
           path="/var/infinispan/myapp/users">
            <write-behind flush-lock-timeout="15000" thread-pool-size="5" />
        </file-store>
    </persistence>
</local-cache>
----

====

In this example we enabled both `eviction` and a `CacheStore` (the `persistence` element).
`LIRS` is one of the choices we have for eviction strategies.
Here it is configured to keep (approximately) 2000 entries in live memory
and evict the remaining as a memory usage control strategy.

The `CacheStore` is enabling `passivation`,
which means that the entries which are evicted are stored on the filesystem.

[WARNING]
====
You could configure an eviction strategy while not configuring a passivating CacheStore!
That is a valid configuration for Infinispan but will have the evictor permanently remove entries.
Hibernate OGM will break in such a configuration.
====

[[ogm-infinispan-clustering]]

==== Clustering: store data on multiple Infinispan nodes

The best thing about Infinispan is that all nodes are treated equally
and it requires almost no beforehand capacity planning:
to add more nodes to the cluster you just have to start new JVMs,
on the same or different physical servers,
having your same Infinispan configuration and your same application.

Infinispan supports several clustering _cache modes_;
each mode provides the same API and functionality
but with different performance, scalability and availability options:

.Infinispan cache modes
local::
Useful for a single VM: networking stack is disabled
replication::
All data is replicated to each node;
each node contains a full copy of all entries.
Consequentially reads are faster but writes don't scale as well.
Not suited for very large datasets.
distribution::
Each entry is distributed on multiple nodes for redundancy and failure recovery,
but not to all the nodes.
Provides linear scalability for both write and read operations.
distribution is the default mode.

To use the `replication` or `distribution` cache modes
Infinispan will use JGroups to discover and connect to the other nodes.

In the default configuration,
JGroups will attempt to autodetect peer nodes using a multicast socket;
this works out of the box in the most network environments
but will require some extra configuration in cloud environments
(which often block multicast packets) or in case of strict firewalls.
See the http://www.jgroups.org/manual/html_single/[JGroups reference documentation],
specifically look for _Discovery Protocols_ to customize the detection of peer nodes.

Nowadays, the [acronym]`JVM` defaults to use [acronym]`IPv6` network stack;
this will work fine with JGroups, but only if you configured [acronym]`IPv6` correctly.
It is often useful to force the [acronym]`JVM` to use [acronym]`IPv4`.

It is also important to let JGroups know which networking interface you want to use;
it will bind to one interface by default, but if you have multiple network interfaces
that might not be the one you expect.

.JVM properties to set for clustering
====
[source]
----
#192.168.122.1 is an example IPv4 address
-Djava.net.preferIPv4Stack=true -Djgroups.bind_addr=192.168.122.1
----
====

[NOTE]
====
You don't need to use [acronym]`IPv4`: JGroups is compatible with [acronym]`IPv6`
provided you have routing properly configured and valid addresses assigned.

The `jgroups.bind_addr` needs to match a placeholder name
in your JGroups configuration in case you don't use the default one.
====

The default configuration uses `distribution` as cache mode
and uses the `jgroups-tcp.xml` configuration for JGroups,
which is contained in the Infinispan jar
as the default configuration for Infinispan users.
Let's see how to reconfigure this:

.Reconfiguring cache mode and override JGroups configuration
====
[source, XML]
----
<?xml version="1.0" encoding="UTF-8"?>
<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:9.1 http://www.infinispan.org/schemas/infinispan-config-9.1.xsd"
    xmlns="urn:infinispan:config:9.1">

    <jgroups>
        <stack-file name="custom-stack" path="my-jgroups-conf.xml" />
    </jgroups>

    <cache-container name="HibernateOGM" default-cache="DEFAULT">
        <transport stack="custom-stack" />

        <!-- *************************************** -->
        <!--     Default cache used as template      -->
        <!-- *************************************** -->
        <distributed-cache name="DEFAULT" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </distributed-cache>

        <!-- Override the cache mode: -->
        <replicated-cache name="User" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </replicated-cache>

        <distributed-cache name="Order" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </distributed-cache>

        <distributed-cache name="associations_User_Order" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </distributed-cache>

    </cache-container>

</infinispan>
----
====

In the example above we specify a custom JGroups configuration file
and set the cache mode for the default cache to `distribution`;
this is going to be inherited by the `Order` and the `associations_User_Order` caches.
But for `User` we have chosen (for the sake of this example) to use `replication`.

Now that you have clustering configured, start the service on multiple nodes.
Each node will need the same configuration and jars.

[TIP]
====
We have just shown how to override the clustering mode
and the networking stack for the sake of completeness, but you don't have to!

Start with the default configuration and see if that fits you.
You can fine tune these setting when you are closer to going in production.
====

[[ogm-infinispan-storage-principles]]
==== Storage principles

To describe things simply, each entity is stored under a single key.
The value itself is a map containing the columns / values pair.

Each association from one entity instance to (a set of) another is stored under a single key.
The value contains the navigational information to the (set of) entity.

[[ogm-infinispan-built-in-types]]
===== Properties and built-in types

Each entity is represented by a map.
Each property or more precisely column is represented by an entry in this map,
the key being the column name.

Hibernate OGM support by default the following property types:

* `java.lang.String`
* `java.lang.Character` (or char primitive)
* `java.lang.Boolean` (or boolean primitive); Optionally the annotations `@Type(type = "true_false")`, `@Type(type = "yes_no")` and `@Type(type = "numeric_boolean")` can be used to map boolean properties to the characters 'T'/'F', 'Y'/'N' or the int values 0/1, respectively.
* `java.lang.Byte` (or byte primitive)
* `java.lang.Short` (or short primitive)
* `java.lang.Integer` (or integer primitive)
* `java.lang.Long` (or long primitive)
* `java.lang.Integer` (or integer primitive)
* `java.lang.Float` (or float primitive)
* `java.lang.Double` (or double primitive)

* `java.math.BigDecimal`
* `java.math.BigInteger`

* `java.util.Calendar`
* `java.util.Date`
* `java.util.UUID`
* `java.util.URL`

[NOTE]
====
Hibernate OGM doesn't store null values in Infinispan,
setting a value to null is the same as removing the corresponding entry
from Infinispan.

This can have consequences when it comes to queries on null value.
====

===== Identifiers

Entity identifiers are used to build the key in which the entity is stored in the cache.

The key is comprised of the following information:

* the identifier column names
* the identifier column values
* the entity table (for the `CACHE_PER_KIND` strategy)

In `CACHE_PER_TABLE`, the table name is inferred from the cache name.
In `CACHE_PER_KIND`, the table name is necessary to identify the entity in the generic cache.

.Define an identifier as a primitive type
====
[source, JAVA]
----
@Entity
public class Bookmark {

    @Id
    private Long id;

    private String title;

    // getters, setters ...
}
----

.Content of the `Bookmark` cache in `CACHE_PER_TABLE`
[cols="3*", options="header"]
|===
     ^| KEY                   2+^| MAP ENTRIES

.2+^.^| ["id"], [42]             | id       | 42
                                 | title    | "Hibernate OGM documentation"
|===

.Content of the `ENTITIES` cache in `CACHE_PER_KIND`
[cols="3*", options="header"]
|===
     ^| KEY                   2+^| MAP ENTRIES

.2+^.^| "Bookmark", ["id"], [42] | id       | 42
                                 | title    | "Hibernate OGM documentation"
|===
====

.Define an identifier using @EmbeddedId
====
[source, JAVA]
----
@Embeddable
public class NewsID implements Serializable {

    private String title;
    private String author;

    // getters, setters ...
}

@Entity
public class News {

    @EmbeddedId
    private NewsID newsId;
    private String content;

    // getters, setters ...
}
----

.Content of the `News` cache in `CACHE_PER_TABLE`
[cols="3*", options="header"]
|===
     ^| KEY
   2+^| MAP ENTRIES

.3+^.^| [newsId.author, newsId.title], ["Guillaume", "How to use Hibernate OGM ?"]
      | newsId.author  | "Guillaume"

      | newsId.title   | "How to use Hibernate OGM ?"

      | content        | "Simple, just like ORM but with a NoSQL database"
|===

.Content of the `ENTITIES` cache in `CACHE_PER_KIND`
[cols="3*", options="header"]
|===
     ^| KEY
   2+^| MAP ENTRIES

.3+^.^| "News", [newsId.author, newsId.title], ["Guillaume", "How to use Hibernate OGM ?"]
      | newsId.author  | "Guillaume"

      | newsId.title   | "How to use Hibernate OGM ?"

      | content        | "Simple, just like ORM but with a NoSQL database"
|===
====

====== Identifier generation strategies

Since Infinispan has not native sequence nor identity column support,
these are simulated using the table strategy, however their default values vary.
We highly recommend you explicitly use a `TABLE` strategy if you want to generate a monotonic identifier.

But if you can, use a pure in-memory and scalable strategy like a UUID generator.

.Id generation strategy TABLE using default values
====
[source, JAVA]
----
@Entity
public class GuitarPlayer {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private long id;

    private String name;

    // getters, setters ...
}

----

.Content of the `hibernate_sequences` cache in `CACHE_PER_TABLE`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | ["sequence_name"], ["default"]
^.^|  2
|===

.Content of the IDENTIFIERS cache in `CACHE_PER_KIND`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | "hibernate_sequences", ["sequence_name"], ["default"]
^.^|  2
|===
====

As you can see, in `CACHE_PER_TABLE`, the key does not contain the id source table name.
It is inferred by the cache name hosting that key.

.Id generation strategy TABLE using a custom table
====
[source, JAVA]
----
@Entity
public class GuitarPlayer {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "guitarGen")
    @TableGenerator(
        name = "guitarGen",
        table = "GuitarPlayerSequence",
        pkColumnName = "seq"
        pkColumnValue = "guitarPlayer",
    )
    private long id;

    // getters, setters ...
}

----

.Content of the `GuitarPlayerSequence` cache in `CACHE_PER_TABLE`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | ["seq"], ["guitarPlayer"]
^.^| 2
|===

.Content of the IDENTIFIERS cache in `CACHE_PER_KIND`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | "GuitarPlayerSequence", ["seq"], ["guitarPlayer"]
^.^| 2
|===
====

.SEQUENCE id generation strategy
====
[source, JAVA]
----
@Entity
public class Song {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "songSequenceGenerator")
  @SequenceGenerator(
      name = "songSequenceGenerator",
      sequenceName = "song_sequence",
      initialValue = 2,
      allocationSize = 20
  )
  private Long id;

  private String title;

  // getters, setters ...
}
----

.Content of the `hibernate_sequences` cache in `CACHE_PER_TABLE`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | ["sequence_name"], ["song_sequence"]
^.^| 11
|===

.Content of the `IDENTIFIERS` cache in `CACHE_PER_KIND`
[cols="2*", options="header"]
|===
  ^| KEY
  ^| NEXT VALUE
   | "hibernate_sequences", "["sequence_name"], ["song_sequence"]
^.^| 11
|===
====

===== Entities

Entities are stored in the cache named after the entity name when using the `CACHE_PER_TABLE` strategy.
In the `CACHE_PER_KIND` strategy, entities are stored in a single cache named `ENTITIES`.

The key is comprised of the following information:

* the identifier column names
* the identifier column values
* the entity table (for the `CACHE_PER_KIND` strategy)

In `CACHE_PER_TABLE`, the table name is inferred from the cache name.
In `CACHE_PER_KIND`, the table name is necessary to identify the entity in the generic cache.

The entry value is an instance of `org.infinispan.atomic.FineGrainedMap`
which contains all the entity properties -
or to be specific columns.
Each column name and value is stored as a key / value pair in the map.
We use this specialized map as Infinispan is able to transport changes
in a much more efficient way.

.Default JPA mapping for an entity
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private String id;
    private String title;

    // getters, setters ...
}
----

.Content of the `News` cache in `CACHE_PER_TYPE`
[cols="3*", options="header"]
|===
     ^| KEY                        2+^| MAP ENTRIES

.2+^.^| ["id"], ["1234-5678"] | id       | "1234-5678"
                                      | title    | "On the merits of NoSQL"
|===

.Content of the `ENTITIES` cache in `CACHE_PER_KIND`
[cols="3*", options="header"]
|===
     ^| KEY                        2+^| MAP ENTRIES

.2+^.^| "News", ["id"], ["1234-5678"] | id       | "1234-5678"
                                      | title    | "On the merits of NoSQL"
|===
====

As you can see, the table name is not part of the key for `CACHE_PER_TYPE`.
In the rest of this section we will no longer show the `CACHE_PER_KIND` strategy.

.Rename field and collection using @Table and @Column
====
[source, JAVA]
----
@Entity
@Table(name = "Article")
public class News {

    @Id
    private String id;

    @Column(name = "headline")
    private String title;

    // getters, setters ...
}
----

.Content of the `Article` cache
[cols="3*", options="header"]
|===
     ^| KEY                               2+^| MAP ENTRIES

.2+^.^| ["id"], ["1234-5678"]                | id       | "1234-5678"
                                             | headline | "On the merits of NoSQL"
|===
====

====== Embedded objects and collections

.Embedded object
====
[source, JAVA]
----
@Entity
public class News {

    @Id
    private String id;
    private String title;

    @Embedded
    private NewsPaper paper;

    // getters, setters ...
}

@Embeddable
public class NewsPaper {

    private String name;
    private String owner;

    // getters, setters ...
}
----

.Content of the `News` cache
[cols="3*", options="header"]
|===
     ^| KEY                               2+^| MAP ENTRIES

.4+^.^| ["id"], ["1234-5678"]                | id          | "1234-5678"
                                             | title       | "On the merits of NoSQL"
                                             | paper.name  | "NoSQL journal of prophecies"
                                             | paper.owner | "Delphy"
|===
====

.@ElementCollection with one attribute
====
[source, JAVA]
----
@Entity
public class GrandMother {

    @Id
    private String id;

    @ElementCollection
    private List<GrandChild> grandChildren = new ArrayList<GrandChild>();

    // getters, setters ...
}

@Embeddable
public class GrandChild {

    private String name;

    // getters, setters ...
}
----

.Content of the `GrandMother` cache
[cols="3*", options="header"]
|===
     ^| KEY                            2+^| MAP ENTRIES
   ^.^| ["id"], ["granny"]                | id          | "granny"
|===

.Content of the `associations_GrandMother_grandChildren` cache in `CACHE_PER_TYPE`
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| ROW MAP ENTRIES

.4+^.^| ["GrandMother_id"], ["granny"]
.2+^.^| ["GrandMother_id", "name"], ["granny", "Leia"]
      | GrandMother_id
      | "granny"

      | name
      | "Leia"

.2+^.^| ["GrandMother_id", "name"], ["granny", "Luke"]
      | GrandMother_id
      | "granny"

      | name
      | "Luke"
|===

.Content of the `ASSOCIATIONS` cache in `CACHE_PER_KIND`
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| ROW MAP ENTRIES

.4+^.^| "GrandMother_grandChildren", ["GrandMother_id"], ["granny"]
.2+^.^| ["GrandMother_id", "name"], ["granny", "Leia"]
      | GrandMother_id
      | "granny"

      | name
      | "Leia"

.2+^.^| ["GrandMother_id", "name"], ["granny", "Luke"]
      | GrandMother_id
      | "granny"

      | name
      | "Luke"
|===
====

Here, we see that the collection of elements is stored in a separate cache and entry.
The association key is made of:

* the foreign key column names pointing to the owner of this association
* the foreign key column values pointing to the owner of this association
* the association table name in the `CACHE_PER_KIND` approach where all associations share the same cache

The association entry is a map containing the representation of each entry in the collection.
The keys of that map are made of:

* the names of the columns uniquely identifying that specific collection entry
  (e.g. for a `Set` this is all of the columns)
* the values of the columns uniquely identifying that specific collection entry

The value attack to that collection entry key is a Map containing the key value pairs column name / column value.

.@ElementCollection with @OrderColumn
====
[source, JAVA]
----
@Entity
public class GrandMother {

    @Id
    private String id;

    @ElementCollection
    @OrderColumn( name = "birth_order" )
    private List<GrandChild> grandChildren = new ArrayList<GrandChild>();

    // getters, setters ...
}

@Embeddable
public class GrandChild {

    private String name;

    // getters, setters ...
}
----

.Content of the `GrandMother` cache
[cols="3*", options="header"]
|===
     ^| KEY                            2+^| MAP ENTRIES
   ^.^| ["id"], ["granny"]                | id          | "granny"
|===

.Content of the `GrandMother_grandChildren` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| ROW MAP ENTRIES

.6+^.^| ["GrandMother_id"], ["granny"]
.3+^.^| ["GrandMother_id", "birth_order"], ["granny", 0]
      | GrandMother_id
      | "granny"

      | birth_order
      | 0

      | name
      | "Leia"

.3+^.^| ["GrandMother_id", "birth_order"], ["granny", 1]
      | GrandMother_id
      | "granny"

      | birth_order
      | 1

      | name
      | "Luke"
|===
====

Here we used an indexed collection and to identify the entry in the collection,
only the owning entity id and the index value is enough.

.@ElementCollection with Map of @Embeddable
====
[source, JAVA]
----
@Entity
public class ForumUser {

	@Id
	private String name;

	@ElementCollection
	private Map<String, JiraIssue> issues = new HashMap<>();

    // getters, setters ...
}

@Embeddable
public class JiraIssue {

	private Integer number;
	private String project;

    // getters, setters ...
}
----

.Content of the `ForumUser` cache
[cols="3*", options="header"]
|===
     ^| KEY                            2+^| MAP ENTRIES
   ^.^| ["id"], ["Jane Doe"]                | id          | "Jane Doe"
|===

.Content of the `ForumUser_issues` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| ROW MAP ENTRIES

.12+^.^| ["ForumUser_id"], ["Jane Doe"]

.4+^.^| ["ForumUser_id", "issues_KEY"], ["Jane Doe", "issueWithNull"]

      | ForumUser_id
      | Jane Doe

      | issue_KEY
      | "issueWithNull"

      | issues.value.project
      | <null>

      | issues.value.number
      | <null>

.4+^.^| ["ForumUser_id", "issues_KEY"], ["Jane Doe", "issue1"]

      | ForumUser_id
      | "Jane Doe"

      | issue_KEY
      | "issue1"

      | issues.value.project
      | "OGM"

      | issues.value.number
      | 1253

.4+^.^| ["ForumUser_id", "issues_KEY"], ["Jane Doe", "issue2"]

      | ForumUser_id
      | "Jane Doe"

      | issue_KEY
      | "issue2"

      | issues.value.project
      | "HSEARCH"

      | issues.value.number
      | 2000
|===
====

===== Associations

Associations between entities are mapped like (collection of) embeddables
except that the target entity is represented by its identifier(s).

.Unidirectional one-to-one
====
[source, JAVA]
----
@Entity
public class Vehicule {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    private Vehicule vehicule;

    // getters, setters ...
}
----

.Content of the `Vehicule` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.2+^.^| ["id"], ["V_01"]             | id             | "V_01"
                                     | brand          | "Mercedes"
|===

.Content of the `Wheel` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.3+^.^| ["id"], ["W001"]             | id             | "W001"
                                     | diameter       | 0.0
                                     | vehicule_id    | "V_01"
|===
====

[[infinispan-in-entity-one-to-one-join-column]]
.Unidirectional one-to-one with @JoinColumn
====
[source, JAVA]
----
@Entity
public class Vehicule {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    @JoinColumn( name = "part_of" )
    private Vehicule vehicule;

    // getters, setters ...
}
----

.Content of the `Vehicle` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.2+^.^| ["id"], ["V_01"]             | id             | "V_01"
                                     | brand          | "Mercedes"
|===

.Content of the `Wheel` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.3+^.^| "Wheel", ["id"], ["W001"]    | id             | "W001"
                                     | diameter       | 0.0
                                     | part_of       | "V_01"
|===
====

.Unidirectional one-to-one with @MapsId and @PrimaryKeyJoinColumn
====
[source, JAVA]
----
@Entity
public class Vehicule {

    @Id
    private String id;
    private String brand;

    // getters, setters ...
}

@Entity
public class Wheel {

    @Id
    private String id;
    private double diameter;

    @OneToOne
    @PrimaryKeyJoinColumn
    @MapsId
    private Vehicule vehicule;

    // getters, setters ...
}
----

.Content of the `Vehicle` cache
[cols="3*", options="header"]
|===
     ^| KEY                                2+^| MAP ENTRIES

.2+^.^| ["id"], ["V_01"]                      | id             | "V_01"
                                              | brand          | "Mercedes"
|===

.Content of the `Wheel` cache
[cols="3*", options="header"]
|===
     ^| KEY                                2+^| MAP ENTRIES

.2+^.^| ["vehicule_id"], ["V_01"]             | vehicule_id    | "V_01"
                                              | diameter       | 0.0
|===
====

.Bidirectional one-to-one
====
[source, JAVA]
----
@Entity
public class Husband {

    @Id
    private String id;
    private String name;

    @OneToOne
    private Wife wife;

    // getters, setters ...
}

@Entity
public class Wife {

    @Id
    private String id;
    private String name;

    @OneToOne(mappedBy="wife")
    private Husband husband;

    // getters, setters ...
}
----

.Content of the `Husband` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES
.3+^.^| ["id"], ["alex"]             | id             | "alex"
                                     | name           | "Alex"
                                     | wife           | "bea"
|===

.Content of the `Wife` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES
.2+^.^| ["id"], ["bea"]              | id             | "bea"
                                     | name           | "Bea"
|===

.Content of the `associations_Husband` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.2+^.^| ["wife"], ["bea"]
.2+^.^| ["id", "wife"], ["alex", "bea"]
      | id
      | "alex"

      | wife
      | "bea"
|===
====

.Unidirectional one-to-many
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

.Content of the `Basket` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.2+^.^| ["id"], ["davide_basket"]           | id               | "davide_basket"
                                            | owner            | "Davide"
|===

.Content of the `Product` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES
.2+^.^| ["name"], ["Beer"]                  | name             | "Beer"
                                            | description      | "Tactical Nuclear Penguin"

.2+^.^| ["name"], ["Pretzel"]               | name             | "Pretzel"
                                            | description      | "Glutino Pretzel Sticks"
|===

.Content of the `associations_Basket_Product` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.4+^.^| ["Basket_id"], ["davide_basket"]
.2+^.^| ["Basket_id", "products_name"], ["davide_basket", "Beer"]
      | Basket_id
      | "davide_basket"

      | products_name
      | "Beer"

.2+^.^| ["Basket_id", "products_name"], ["davide_basket", "Pretzel"]
      | Basket_id
      | "davide_basket"

      | products_name
      | "Pretzel"

|===
====

.Unidirectional one-to-many with `@JoinTable`
====
[source, JAVA]
----
@Entity
public class Basket {

    @Id
    private String id;

    private String owner;

    @OneToMany
    @JoinTable( name = "BasketContent" )
    private List<Product> products = new ArrayList<Product>();

    // getters, setters ...
}

@Entity
public class Product {

    @Id
    private String name;

    private String description;

    // getters, setters ...
}
----

.Content of the `Basket` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES

.2+^.^| ["id"], ["davide_basket"]           | id               | "davide_basket"
                                            | owner            | "Davide"
|===

.Content of the `Basket` cache
[cols="3*", options="header"]
|===
     ^| KEY                       2+^| MAP ENTRIES
.2+^.^| ["name"], ["Beer"]                  | name             | "Beer"
                                            | description      | "Tactical Nuclear Penguin"

.2+^.^| ["name"], ["Pretzel"]               | name             | "Pretzel"
                                            | description      | "Glutino Pretzel Sticks"
|===

.Content of the `associations_BasketContent` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.4+^.^| ["Basket_id"], ["davide_basket"]
.2+^.^| ["Basket_id", "products_name"], ["davide_basket", "Beer"]
      | Basket_id
      | "davide_basket"

      | products_name
      | "Beer"

.2+^.^| ["Basket_id", "products_name"], ["davide_basket", "Pretzel"]
      | Basket_id
      | "davide_basket"

      | products_name
      | "Pretzel"
|===
====

.Unidirectional one-to-many using maps with defaults
====
[source, JAVA]
----
@Entity
public class User {

    @Id
    private String id;

    @OneToMany
    private Map<String, Address> addresses = new HashMap<String, Address>();

    // getters, setters ...
}

@Entity
public class Address {

    @Id
    private String id;
    private String city;

    // getters, setters ...
}
----

.Content of the `User` cache
[cols="3*", options="header"]
|===
     ^| KEY                             2+^| MAP ENTRIES

   ^.^| ["id"], ["user_001"]               | id   | "user_001"
|===

.Content of the `Address` cache
[cols="3*", options="header"]
|===
     ^| KEY                             2+^| MAP ENTRIES
.2+^.^| ["id"], ["address_001"]            | id   | "address_001"
                                           | city | "Rome"

.2+^.^| ["id"], ["address_002"]            | id   | "address_002"
                                           | city | "Paris"
|===

.Content of the `associations_User_address` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.6+^.^| ["User_id"], "user_001"]
.3+^.^| ["User_id", "addresses_KEY"], ["user_001", "home"]
      | User_id
      | "user_001"

      | addresses_KEY
      | "home"

      | addresses_id
      | "address_001"

.3+^.^| ["User_id", "addresses_KEY"], ["user_001", "work"]
      | User_id
      | "user_002"

      | addresses_KEY
      | "work"

      | addresses_id
      | "address_002"
|===
====

.Unidirectional one-to-many using maps with @MapKeyColumn
====
[source, JAVA]
----
@Entity
public class User {

    @Id
    private String id;

    @OneToMany
    @MapKeyColumn(name = "addressType")
    private Map<String, Address> addresses = new HashMap<String, Address>();

    // getters, setters ...
}

@Entity
public class Address {

    @Id
    private String id;
    private String city;

    // getters, setters ...
}
----

.Content of the `User` cache
[cols="3*", options="header"]
|===
     ^| KEY                             2+^| MAP ENTRIES

   ^.^| ["id"], ["user_001"]               | id   | "user_001"
|===

.Content of the `Address` cache
[cols="3*", options="header"]
|===
     ^| KEY                             2+^| MAP ENTRIES
.2+^.^| ["id"], ["address_001"]            | id   | "address_001"
                                           | city | "Rome"

.2+^.^| ["id"], ["address_002"]            | id   | "address_002"
                                           | city | "Paris"
|===

.Content of the `associations_User_address` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.6+^.^| ["User_id"], "user_001"]
.3+^.^| ["User_id", "addressType"], ["user_001", "home"]
      | User_id
      | "user_001"

      | addressesType
      | "home"

      | addresses_id
      | "address_001"

.3+^.^| ["User_id", "addressType"], ["user_001", "work"]
      | User_id
      | "user_002"

      | addressesType
      | "work"

      | addresses_id
      | "address_002"
|===
====

.Unidirectional many-to-one
====
[source, JAVA]
----
@Entity
public class JavaUserGroup {

    @Id
    private String jugId;
    private String name;

    // getters, setters ...
}

@Entity
public class Member {

    @Id
    private String id;
    private String name;

    @ManyToOne
    private JavaUserGroup memberOf;

    // getters, setters ...
}
----

.Content of the `JavaUserGroup` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES

.2+^.^| ["jugId"], ["summer_camp"]                  | jugId           | "summer_camp"
                                                    | name            | "JUG Summer Camp"
|===

.Content of the `Member` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES
.3+^.^| ["member_id"], ["emmanuel"]                 | member_id       | "emmanuel"
                                                    | name            | "Emmanuel Bernard"
                                                    | memberOf_jug_id | "summer_camp"

.3+^.^| ["member_id"], ["jerome"]                   | member_id       | "jerome"
                                                    | name            | "Jerome"
                                                    | memberOf_jug_id | "summer_camp"
|===
====

.Bidirectional many-to-one
====
[source, JAVA]
----
@Entity
public class SalesForce {

    @Id
    private String id;
    private String corporation;

    @OneToMany(mappedBy = "salesForce")
    private Set<SalesGuy> salesGuys = new HashSet<SalesGuy>();

    // getters, setters ...
}

@Entity
public class SalesGuy {
    private String id;
    private String name;

    @ManyToOne
    private SalesForce salesForce;

    // getters, setters ...
}
----

.Content of the `SalesForce` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES

.2+^.^| ["id"], ["red_hat"]                         | id              | "red_hat"
                                                    | corporation     | "Red Hat"
|===

.Content of the `SalesGuy` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES
.3+^.^| ["id"], ["eric"]                            | id              | "eric"
                                                    | name            | "Eric"
                                                    | salesForce_id   | "red_hat"

.3+^.^| ["id"], ["simon"]                           | id              | "simon"
                                                    | name            | "Simon"
                                                    | salesForce_id   | "red_hat"
|===

.Content of the `associations_SalesGuy` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.4+^.^| ["salesForce_id"], ["red_hat"]
.2+^.^| ["salesForce_id", "id"], ["red_hat", "eric"]
      | salesForce_id
      | "red_hat"

      | id
      | "eric"

.2+^.^| ["salesForce_id", "id"], ["red_hat", "simon"]
      | salesForce_id
      | "red_hat"

      | id
      | "simon"
|===
====

.Unidirectional many-to-many
====
[source, JAVA]
----
@Entity
public class Student {

    @Id
    private String id;
    private String name;

    // getters, setters ...
}

@Entity
public class ClassRoom {

    @Id
    private long id;
    private String lesson;

    @ManyToMany
    private List<Student> students = new ArrayList<Student>();

    // getters, setters ...
}
----

The "Math" class has 2 students: John Doe and Mario Rossi

The "English" class has 2 students: Kate Doe and Mario Rossi

.Content of the `ClassRoom` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES

.2+^.^| ["id"], [1]                    | id         | 1
                                       | name       | "Math"

.2+^.^| ["id"], [2]                    | id         | 2
                                       | name       | "English"
|===

.Content of the `Student` cache
[cols="3*", options="header"]
|===
     ^| KEY                                      2+^| MAP ENTRIES
.2+^.^| ["id"], ["john"]               | id         | "john"
                                       | name       | "John Doe"

.2+^.^| ["id"], ["mario"]              | id         | "mario"
                                       | name       | "Mario Rossi"

.2+^.^| ["id"], ["kate"]               | id         | "kate"
                                       | name       | "Kate Doe"
|===

.Content of the `associations_ClassRoom_Student` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.4+^.^| ["ClassRoom_id"], [1]
.2+^.^| ["ClassRoom_id", "students_id"], [1, "mario"]
      | ClassRoom_id
      | 1

      | students_id
      | "mario"

.2+^.^| ["ClassRoom_id", "students_id"], [1, "john"]
      | ClassRoom_id
      | 1

      | students_id
      | "john"

.4+^.^| ["ClassRoom_id"], [2]
.2+^.^| ["ClassRoom_id", "students_id"], [2, "kate"]
      | ClassRoom_id
      | 2

      | students_id
      | "kate"

.2+^.^| ["ClassRoom_id", "students_id"], [2, "mario"]
      | ClassRoom_id
      | 2

      | students_id
      | "mario"
|===
====

.Bidirectional many-to-many
====
[source, JAVA]
----
@Entity
public class AccountOwner {

    @Id
    private String id;

    private String SSN;

    @ManyToMany
    private Set<BankAccount> bankAccounts;

    // getters, setters ...
}

@Entity
public class BankAccount {

    @Id
    private String id;

    private String accountNumber;

    @ManyToMany( mappedBy = "bankAccounts" )
    private Set<AccountOwner> owners = new HashSet<AccountOwner>();

    // getters, setters ...
}
----

David owns 2 accounts: "012345" and "ZZZ-009"

.Content of the `AccountOwner` cache
[cols="3*", options="header"]
|===
     ^| KEY                               2+^| MAP ENTRIES

.2+^.^| ["id"], ["David"]                    | id            | "David"
                                             | SSN           | "0123456"
|===

.Content of the `BankAccount` cache
[cols="3*", options="header"]
|===
     ^| KEY                               2+^| MAP ENTRIES
.2+^.^| ["id"], ["account_1"]                | id            | "account_1"
                                             | accountNumber | "X2345000"

.2+^.^| ["id"], ["account_2"]                | id            | "account_2"
                                             | accountNumber | "ZZZ-009"
|===

.Content of the `AccountOwner_BankAccount` cache
[cols="4*", options="header"]
|===
     ^| KEY
     ^| ROW KEY
   2+^| MAP ENTRIES

.2+^.^| ["bankAccounts_id"], ["account_1"]
.2+^.^| ["bankAccounts_id", "owners_id"], ["account_1", "David"]
      | bankAccounts_id
      | "account_1"

      | owners_id
      | "David"

.2+^.^| ["bankAccounts_id"], ["account_2"]
.2+^.^| ["bankAccounts_id", "owners_id"], ["account_2", "David"]
      | bankAccounts_id
      | "account_2"

      | owners_id
      | "David"

.4+^.^| ["owners_id"], ["David"]
.2+^.^| ["owners_id", "banksAccounts_id"], ["David", "account_1"]
      | bankAccounts_id
      | "account_1"

      | owners_id
      | "David"

.2+^.^| ["owners_id", "banksAccounts_id"], ["David", "account_2"]
      | bankAccounts_id
      | "account_2"

      | owners_id
      | "David"

|===
====

[[ogm-infinispan-transactions]]

==== Transactions

Infinispan supports transactions and integrates with any standard JTA `TransactionManager`;
this is a great advantage for JPA users as it allows to experience a _similar_ behaviour
to the one we are used to when we work with RDBMS databases.

This capability is only available to Infinispan Embedded users: the transactional integration
capabilities are not exposed to the Hot Rod clients.

If you're having Hibernate OGM start and manage Infinispan,
you can skip this as it will inject the same `TransactionManager` instance
which you already have set up in the Hibernate / JPA configuration.

If you are providing an already started Infinispan CacheManager instance
by using the [acronym]`JNDI` lookup approach,
then you have to make sure the CacheManager is using the same `TransactionManager`
as Hibernate:

.Configuring a JBoss Standalone TransactionManager lookup in Infinispan configuration
====
[source, XML]
----
<default>
   <transaction
      transactionMode="TRANSACTIONAL"
      transactionManagerLookupClass=
    "org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup" />
</default>
----
====

Infinispan supports different transaction modes like `PESSIMISTIC` and `OPTIMISTIC`,
supports [acronym]`XA` recovery and provides many more configuration options;
see the http://infinispan.org/documentation/[Infinispan User Guide]
for more advanced configuration options.

[[ogm-infinispan-indexstorage]]

==== Storing a Lucene index in Infinispan

Hibernate Search, which can be used for advanced query capabilities (see <<ogm-query>>),
needs some place to store the indexes for its embedded `Apache Lucene` engine.

A common place to store these indexes is the filesystem
which is the default for Hibernate Search;
however if your goal is to scale your NoSQL engine on multiple nodes
you need to share this index.
Network sharing file systems are a possibility but we don't recommended that.
Often the best option is to store the index
in whatever NoSQL database you are using (or a different dedicated one).

[TIP]
====
You might find this section useful even if you don't intend to store your data in Infinispan.
====

The Infinispan project provides an adaptor to plug into Apache Lucene,
so that it writes the indexes in Infinispan and searches data in it.
Since Infinispan can be used as an application cache to other NoSQL storage engines
by using a CacheStore (see <<ogm-infinispan-storage>>)
you can use this adaptor to store the Lucene indexes
in any NoSQL store supported by Infinispan:

* JDBC databases
* Cassandra
* Filesystem (but locked correctly at the Infinispan level)
* MongoDB
* HBase
* LevelDB
* A secondary (independent) Infinispan grid

How to configure it? Here is a simple cheat sheet to get you started with this type of setup:

* Add `org.infinispan:infinispan-directory-provider:{infinispanVersion}` to your dependencies
* set these configuration properties:

** `hibernate.search.default.directory_provider = infinispan`
** `hibernate.search.default.exclusive_index_use = false`
** `hibernate.search.infinispan.configuration_resourcename =` [infinispan configuration filename]

This configuration is simple and will work fine in most scenarios, but keep in mind that using
'exclusive_index_use' will be neither fast nor scalable.
For high performance, high concurrency or production use please refer to the
http://infinispan.org/documentation/[Infinispan documentation] for more advanced configuration options and tuning.

The referenced Infinispan configuration should define a `CacheStore`
to load/store the index in the NoSQL engine of choice.
It should also define three cache names:

.Infinispan caches used to store indexes
[cols="1,2,1", options="header"]
|===============
|Cache name|Description|Suggested cluster mode
|LuceneIndexesLocking|Transfers locking information. Does not need a cache
            store.|replication
|LuceneIndexesData|Contains the bulk of Lucene data. Needs a cache
            store.|distribution + L1
|LuceneIndexesMetadata|Stores metadata on the index segments. Needs a cache
            store.|replication
|===============

This configuration is not going to scale well on write operations:
to do that you should read about the master/slave and sharding options in Hibernate Search.
The complete explanation and configuration options can be found in the
https://docs.jboss.org/hibernate/search/{hibernate-search-major-minor-version}/reference/en-US/html_single/#infinispan-directories[Hibernate Search Reference Guide]

Some NoSQL support storage of Lucene indexes directly,
in which case you might skip the Infinispan Lucene integration
by implementing a custom `DirectoryProvider` for Hibernate Search.
You're very welcome to share the code
and have it merged in Hibernate Search for others to use, inspect, improve and maintain.

[[ogm-infinispan-remote]]

=== Hibernate OGM & Infinispan Server over Hot Rod

In this section we'll see how to configure Hibernate OGM to connect to
"Infinispan Server using the Hot Rod protocol", which we will call "Infinispan Remote"
for brevity and to differentiate it from "Infinispan Embedded".

In this mode Hibernate OGM can not boostrap or otherwise control the lifecycle
of Infinispan, so we will assume that you already have a cluster of Infinispan Server
nodes running.
For instructions on setting one up, see the http://infinispan.org/docs/stable/server_guide/server_guide.html[Infinispan Server Guide].

The good news is that - since it's a separate service - there won't be much to configure
in Hibernate OGM.

[CAUTION]
====
The Hibernate OGM support for Infinispan Remote is considered experimental.
In particular, the storage format is not set in stone.
====

==== Adding Infinispan Remote dependencies

To use Hibernate OGM to connect to an Infinispan Server using the Hot Rod protocol, you will need the following extension
and its transitive dependencies (which include, among others, the Hot Rod client):

[source, XML]
[subs="verbatim,attributes"]
----
<dependency>
    <groupId>org.hibernate.ogm</groupId>
    <artifactId>hibernate-ogm-infinispan-remote</artifactId>
    <version>{hibernate-ogm-version}</version>
</dependency>
----

==== Configuration properties for Infinispan Remote

First, let Hibernate know that you want to use the OGM Infinispan Remote datastore by setting the
`hibernate.ogm.datastore.provider` property to `infinispan_remote`.

The next step is to configure the Hot Rod client.
You have two options:

* either provide a resource file containing all Hot Rod client configuration properties
* or include all the Hot Rod client configuration properties with a custom prefix, as explained below.

To use an external configuration resource, set the `hibernate.ogm.infinispan_remote.configuration_resource_name`
configuration property to the resource name.

.Using a separate resource to configure the Hot Rod client
====
[source, XML]
----
<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
	version="2.0">

	<persistence-unit name="ogm-with-hotrod">
		<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider> # <1>
		<properties>
			<property name="hibernate.ogm.datastore.provider"
				value="infinispan_remote" /> # <2>
			<property name="hibernate.ogm.infinispan_remote.configuration_resource_name"
				value="hotrodclient.properties" /> # <3>
		</properties>
	</persistence-unit>
</persistence>
----
<1> Choose Hibernate OGM as JPA Provider
<2> pick `infinispan_remote` as datastore
<3> point to the Hot Rod configuration file

[source]
----
infinispan.client.hotrod.server_list = 127.0.0.1:11222
infinispan.client.hotrod.tcp_no_delay = true
infinispan.client.hotrod.tcp_keep_alive = false

## below is connection pooling config
maxActive=-1
maxTotal = -1
maxIdle = -1
whenExhaustedAction = 1
timeBetweenEvictionRunsMillis = 120000
minEvictableIdleTimeMillis = 300000
testWhileIdle = true
minIdle = 1
----
====

Alternatively you can embed the Hot Rod properties in your Hibernate (or JPA) configuration
file, but you'll have to replace the `infinispan.client.hotrod.` prefix with the custom
prefix `hibernate.ogm.infinispan_remote.client.`.

Some of the Hot Rod client configuration properties don't normally use a prefix - specifically
all properties relating to connection pooling as in the previous example - these will also
need to use the `hibernate.ogm.infinispan_remote.client.` prefix.

Properties set with the `hibernate.ogm.infinispan_remote.client.` prefix will override the same
properties configured using an external reosurce file.

.Embedding the Hot Rod client configuration properties in the Hibernate configuration
====
[source, XML]
----
<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
	version="2.0">

	<persistence-unit name="ogm-with-hotrod">
		<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider> # <1>
		<properties>
			<property name="hibernate.ogm.datastore.provider"
				value="infinispan_remote" /> # <2>
			<property name="hibernate.ogm.infinispan_remote.client.server_list"
				value="127.0.0.1:11222" /> # <3>
			<property name="hibernate.ogm.infinispan_remote.client.tcp_no_delay"
				value="true" />
			<property name="hibernate.ogm.infinispan_remote.client.tcp_keep_alive"
				value="false" />
			<property name="hibernate.ogm.infinispan_remote.client.maxActive"
				value="-1" />
			<property name="hibernate.ogm.infinispan_remote.client.maxTotal"
				value="-1" />
			<property name="hibernate.ogm.infinispan_remote.client.maxIdle"
				value="-1" />
			<property name="hibernate.ogm.infinispan_remote.client.whenExhaustedAction"
				value="1" />
			<property name="hibernate.ogm.infinispan_remote.client.timeBetweenEvictionRunsMillis"
				value="120000" />
			<property name="hibernate.ogm.infinispan_remote.client.minEvictableIdleTimeMillis"
				value="300000" />
			<property name="hibernate.ogm.infinispan_remote.client.testWhileIdle"
				value="true" />
			<property name="hibernate.ogm.infinispan_remote.client.minIdle"
				value="1" />
		</properties>
	</persistence-unit>
</persistence>
----
<1> Choose Hibernate OGM as JPA Provider
<2> pick `infinispan_remote` as datastore
<3> include Hot Rod configuration properties, just replacing/adding the OGM prefix.
====

In the next section we'll see a couple more advanced properties which might be of interest.

hibernate.ogm.infinispan_remote.schema_capture_service::
If you set this to an implementation of `org.hibernate.ogm.datastore.infinispanremote.schema.spi.SchemaCapture` you
can collect any generated Protobuf Schema. Could be useful for integrations with other tools.
You can either provide a fully qualified classname or a `SchemaCapture`, or pass an instance of a `SchemaCapture`
in the configuration properties, if you're booting Hibernate programmatically.

hibernate.ogm.infinispan_remote.schema_package_name::
Defines the package name of the generated Protobuf schema. Defaults to `HibernateOGMGenerated`.
Useful to isolate different applications using the same Infinispan Server instance.

==== Data encoding: Protobuf Schema

Using the _Infinispan Remote_ backend your data will be encoded using Protocol Buffers,
also known as Protobuf.

> Protocol Buffers are a language-neutral, platform-neutral
> extensible mechanism for serializing structured data
> -- https://developers.google.com/protocol-buffers/

This encoding strategy will be used both during _transmission_ to and from the datagrid, and
as a _storage format_ on the Infinispan Server.

Typical usage of Google's developer tools for Java would require you to download the `protoc`
compiler to generate Java stubs; you won't need that when using Hibernate OGM as the backend
will generate the encoding and decoding functions on the fly from your entities.

The benefit of having Hibernate OGM generate the schema for you will make it easier to get
started, but there's a drawback: you are not directly in control of the protobuf schema
It will deploy this schema - or expect a compatible schema to be deployed - as it will use
its generated codecs to read and write data to the Infinispan Server.

The protobuf technology is designed to allow evolution of your schema: you can deploy a
different schema on the Infinispan Server than the one OGM expects, but this is an advanced
topic and you'll have to make sure the deployed schema is compatible with the one OGM is
generating and using.

Another reason to make sure the deployed protobuf schema is a _compatible evolution_ of
a previous schema, is to make sure you can still read data which is already stored in
the datagrid.

[IMPORTANT]
====
Remember that the Protobuf schema is used both during _transmission_ and _storage_.
The fact that it's used also during _transmission_ of your data is a key difference to the
schema of a SQL database.

For example even if a property "A" is not nullable in terms of storage, you will still
want it to be flagged as `optional` in a protobuf schema to allow, for example, retrieving
a subset of data properties without having to always retrieve the property "A".
====

You don't need to do anything regarding the schema: Hibernate OGM will automatically
deploy it to the Infinispan datagrid at boostrap of Hibernate.
You might want to keep this in mind though, both to be able to evolve your schema
without data loss, and to be able to generate decoders for other Infinispan clients not
using Hibernate OGM.

The deployed schemas can be fetched from the Infinispan Server; Hibernate OGM also
logs the generated schemas at `INFO` level in the logging category
`org.hibernate.ogm.datastore.infinispanremote.impl.protobuf.SchemaDefinitions`.

==== Storage Principles of the Infinispan Remote dataprovider

This is actually very simple.

Imagine you were mapping your entities to a traditional, table based [acronym]`RDBMS`;
now instead of tables, you have caches. Each cache has a name, and a consistent schema,
and for each cache we define a key with some properties (the id, aka the primary key).

Relations are mapped by encoding a "foreign key"; these are used either as keys perform
a key lookup on another table, or can be used in queries on other tables to identify
relations which have a higher than one cardinality.

So let's highlight the differences with the relational world:

Referential integrity::
While we can use relations based on foreign keys, Infinispan has no notion of referential integrity.
Hibernate is able to maintain the integrity as it won't "forget" stale references, but since
the storage doesn't support transactions either it is possible to interrupt Hibernate OGM
during such maintenance and introduce breaks of integrity.

A key. And a Value.::
In a key/value store the two elements _key_ and _value_ are different, separate objects.
The schema - and consequentially all operations - generated by Hibernate OGM will treat
and encode these two objects separately. You will notice that the attributes of the key
are encoded in the value *as well*, as it is not possible to run e.g. range queries
on attributes of keys.

No Sequences, no auto-incrementing values::
Infinispan does not support sequences, yet allows concurrent "compare and set" operations;
Hibernate OGM makes use of such CAS operations to emulate the need of sequences or auto-incrementing
primary keys if your entity mapping uses them, however this solution might not work
under high load: make sure to use a different strategy, such as assigning IDs explicitly,
or using the `org.hibernate.id.UUIDGenerator` generator.
Hibernate OGM will log a warning if it detects excessive spinning on such CAS operations.

Not mapped to JDBC types, but to Protobuf types::
Rather than mapping your Java properties to corresponding JDBC (SQL) types, your Java
properties are mapped to Protobuf types.
See the https://developers.google.com/protocol-buffers/docs/proto#scalar[protobuf documentation]
for an overview of protocol buffer "primitive" types.

.Example auto-generated Protobuf Schema for a simple entity
====
[source, JAVA]
----
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Hypothesis {

	@Id String id;

	String description;

	@Column(name = "pos")
	int position;

}
----
[source]
----
package HibernateOGMGenerated; # <1>

message Hypothesis_id { # <2>
	required string id = 1;
}

message Hypothesis {
	required string id = 1;
	optional string description = 2;
	optional int32 pos = 3;  # <3>
}
----
<1> The default Protobuf package name.
<2> A dedicated message type for the Key of the Key/Value pair
<3> The `pos` attribute name respects the option of the `@Column` annotation
====

The above example shows how a Protobuf schema looks like, as automatically generated from a mapped entity.
Any property type supported by Hibernate ORM will be converted to a matching Protobuf type.

===== Each Table requires a Cache with the same name

In a relational database world, when Hibernate defines the schema this implicitly creates the tables;
this is not the case on Infinispan.

With Infinispan, the _Protobuf Schema_ just unlocks the capability to transmit messages with
such payloads (read/write), and allows the remote servers to process the fields, for example
to execute queries and extract projections out of the stored entries.
So this establishes a transmission and storage encoding contract, but doesn't actually
start or allocate any storing Cache.

Hibernate OGM by convention will write to several named ``Cache``s, mapping each "table name"
to a "cache name". In the above example, when having an `Hypothesis` entity this will
write to a Cache named `Hypothesis`.

The benefit is that you can tune each cache (each "table") independently; for example you could
configure the caches for the most important data to have a synchronous CacheStore which replicates
data to a relational database, and have less important entries use an asynchronous CacheStore,
or none at all, to favour performance over redundancy.

The drawback of this design choice is that each named cache must be pre-defined in the Infinispan
Server configuration: at this point, the Hot Rod protocol is not allowed to start missing caches
so Hibernate OGM can not define the missing tables automatically.
It generates the encoding protobuf, but you have to list the Cache names in the server configuration.

[WARNING]
====
For each "table name" your model would generate on a relational database, you have to define
a matching Cache on the Infinispan Server.

If any Cache is missing, Hibernate OGM will fail to start and list which table names were
expected, but not found. We plan to automate the creation of missing caches in the future.
====

==== Known Limitations & Future improvements

The Infinispan Remote dataprovider has some known limitations, some of which are
unsolvable without further development of Infinispan itself.

Transaction Support::
We're eagerly waiting for Infinispan to support transactions over Hot Rod, as it
already provides this feature in Embedded Mode.

Queries::
At this point the Hibernate OGM backend is able to run the queries it needs to materialize
relations, but does not yet translate JPQL queries nor Criteria queries to the
Infinispan remote queries.

Indexing::
Infinispan supports Hibernate Search annotations directly embedded within its protobuf
schema definitions; this would enable the queries on them to use indexes.
Hibernate OGM doesn't generate these annotations in the schemas it generates yet.

Native support for write skew checks::
The Hot Rod client has native support for versioning of datagrid entries, yet this is
not supported on all of the client APIs. For Hibernate OGM to be able to consistently
use versioning requires enhancements to the Hot Rod client API.

Enums::
Protobuf has native support for Enum types, yet the JPA annotations force to choose
between ordinal or string encoding. We might have to introduce a "native" encoding,
probably via a novel mapping annotation.
Hibernate OGM supports the native protobuf Encoding but the JPA metadata will always
force the ordinal or string representations.

Nesting and embedding::
The Protobuf schema could allow us to embed objects, including series of objects,
as nested elements. This could allow mappings similar to the document based NoSQL
stores, such as our MongoDB dialect, but is not supported yet.

Automatic creating of ``Cache``s::
When deploying the _Protobuf Schema_, we should also automatically define and start
the needed Caches if they are not defined.
This is currently not allowed over the Hot Rod protocol.