diff --git a/documentation/src/main/asciidoc/user_guide/chapter-23_2-JPA_Persistence.adoc b/documentation/src/main/asciidoc/user_guide/chapter-23_2-JPA_Persistence.adoc
new file mode 100644
index 000000000000..a3038fb271ea
--- /dev/null
+++ b/documentation/src/main/asciidoc/user_guide/chapter-23_2-JPA_Persistence.adoc
@@ -0,0 +1,169 @@
+= JPA Cache Store
+The Infinispan Community
+:icons: font
+
+== Introduction
+The implementation depends on JPA 2.0 specification to access entity meta model.
+
+In normal use cases, it's recommended to leverage Infinispan for JPA second level cache and/or query cache.
+However, if you'd like to use only Infinispan API and you want Infinispan to persist into a cache store using a common format (e.g., a database with well defined schema), then JPA Cache Store could be right for you.
+
+.Things to note
+* When using JPA Cache Store, the key should be the ID of the entity, while the value should be the entity object.
+* Only a single `@Id` or `@EmbeddedId` annotated property is allowed.
+* Auto-generated ID is not supported.
+* Lastly, all entries will be stored as immortal entries.
+
+=== Sample Usage
+For example, given a persistence unit "myPersistenceUnit", and a JPA entity User:
+
+.persistence.xml
+[source,xml]
+----
+
+
+ ...
+
+
+----
+
+User entity class
+
+.User.java
+[source,java]
+----
+
+@Entity
+public class User implements Serializable {
+ @Id
+ private String username;
+ private String firstName;
+ private String lastName;
+
+ ...
+}
+
+----
+
+Then you can configure a cache "usersCache" to use JPA Cache Store, so that when you put data into the cache, the data would be persisted into the database based on JPA configuration.
+
+[source,java]
+----
+
+EmbeddedCacheManager cacheManager = ...;
+
+
+Configuration cacheConfig = new ConfigurationBuilder().loaders()
+ .addLoader(JpaCacheStoreConfigurationBuilder.class)
+ .persistenceUnitName("myPersistenceUnit")
+ .entityClass(User.class)
+ .build();
+cacheManager.defineCache("usersCache", cacheConfig);
+
+Cache usersCache = cacheManager.getCache("usersCache");
+usersCache.put("raytsang", new User(...));
+
+----
+
+Normally a single Infinispan cache can store multiple types of key/value pairs, for example:
+
+[source,java]
+----
+
+Cache usersCache = cacheManager.getCache("myCache");
+usersCache.put("raytsang", new User());
+Cache teachersCache = cacheManager.getCache("myCache");
+teachersCache.put(1, new Teacher());
+
+----
+
+It's important to note that, when a cache is configured to use a JPA Cache Store, that cache would only be able to store ONE type of data.
+
+[source,java]
+----
+
+Cache usersCache = cacheManager.getCache("myJPACache"); // configured for User entity class
+usersCache.put("raytsang", new User());
+Cache teachersCache = cacheManager.getCache("myJPACache"); // cannot do this when this cache is configured to use a JPA cache store
+teachersCache.put(1, new Teacher());
+
+----
+
+Use of `@EmbeddedId` is supported so that you can also use composite keys.
+
+[source,java]
+----
+
+@Entity
+public class Vehicle implements Serializable {
+ @EmbeddedId
+ private VehicleId id;
+ private String color; ...
+}
+
+@Embeddable
+public class VehicleId implements Serializable
+{
+ private String state;
+ private String licensePlate;
+ ...
+}
+
+----
+
+Lastly, auto-generated IDs (e.g., `@GeneratedValue`) is not supported.
+When putting things into the cache with a JPA cache store, the key should be the ID value!
+
+== Configuration
+=== Sample Programatic Configuration
+
+[source,java]
+----
+
+Configuration cacheConfig = new ConfigurationBuilder().loaders()
+ .addLoader(JpaCacheStoreConfigurationBuilder.class)
+ .persistenceUnitName("org.infinispan.loaders.jpa.configurationTest")
+ .entityClass(User.class)
+ .build();
+
+----
+
+[options="header"]
+|===============
+|Parameter|Description
+|persistenceUnitName| JPA persistence unit name in JPA configuration (persistence.xml) that contains the JPA entity class
+|entityClass| JPA entity class that is expected to be stored in this cache. Only one class is allowed.
+|===============
+
+=== Sample XML Configuration
+
+[source,xml]
+----
+
+
+
+
+
+
+
+----
+
+[options="header"]
+|===============
+|Parameter|Description
+|persistenceUnitName| JPA persistence unit name in JPA configuration (persistence.xml) that contains the JPA entity class
+|entityClassName|Fully qualified JPA entity class name that is expected to be stored in this cache. Only one class is allowed.
+
+|===============
+
+== Additional References
+Refer to the link:$$https://github.com/infinispan/infinispan-cachestore-jpa/tree/master/src/test/java/org/infinispan/loaders/jpa/config/ConfigurationTest.java$$[test case] for code samples in action.
+
+Refer to link:$$https://github.com/infinispan/infinispan-cachestore-jpa/tree/master/src/test/resources/config/jpa-config-53.xml$$[test configurations] for configuration samples.
+
+== Javadoc
+
+*TODO*
diff --git a/documentation/src/main/asciidoc/user_guide/user_guide.adoc b/documentation/src/main/asciidoc/user_guide/user_guide.adoc
index ea0cc36dfec6..a44d0eb79ea5 100644
--- a/documentation/src/main/asciidoc/user_guide/user_guide.adoc
+++ b/documentation/src/main/asciidoc/user_guide/user_guide.adoc
@@ -24,6 +24,7 @@ include::chapter-43-Eviction.adoc[]
include::chapter-23-Persistence.adoc[]
include::chapter-23_0-LevelDB_Persistence.adoc[]
include::chapter-23_1-REST_Persistence.adoc[]
+include::chapter-23_2-JPA_Persistence.adoc[]
include::chapter-26-Infinispan_transactions.adoc[]
include::chapter-19-Locking_and_Concurrency.adoc[]
include::chapter-32-Clustering_modes.adoc[]
diff --git a/parent/pom.xml b/parent/pom.xml
index c8f53602e94e..96a7e46c96a2 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -111,13 +111,14 @@
11.0.2
1.3.166
3.5.6-Final
+ 4.2.2.Final
+ ${version.hibernate.core}
1.0.0.Alpha6
1.0.1.Final
4.2.4
1.9.2
1.0.0-PFD
0.11
- 1.0
2.5
4.17.13.Final
1.1.0.Final
@@ -381,11 +382,6 @@
cdi-api
${version.cdi}
-
- javax.persistence
- persistence-api
- ${version.javax.persistence}
-
javax.servlet
jstl
@@ -471,6 +467,16 @@
hibernate-annotations
${version.hibernate.annotations}
+
+ org.hibernate
+ hibernate-entitymanager
+ ${version.hibernate.entitymanager}
+
+
+ org.hibernate.javax.persistence
+ hibernate-jpa-2.0-api
+ ${version.hibernate.javax.persistence}
+
org.hibernate.hql
hibernate-hql-parser
diff --git a/persistence/jpa/pom.xml b/persistence/jpa/pom.xml
new file mode 100644
index 000000000000..577d79865e80
--- /dev/null
+++ b/persistence/jpa/pom.xml
@@ -0,0 +1,105 @@
+
+
+ 4.0.0
+
+ org.infinispan
+ infinispan-persistence-parent
+ 7.0.0-SNAPSHOT
+ ../pom.xml
+
+
+ infinispan-cachestore-jpa
+ bundle
+ Infinispan JPA CacheStore
+ Infinispan JPA CacheStore module
+
+
+
+ 1
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+
+
+
+ ${project.groupId}.persistence.jpa.*;version=${project.version};-split-package:=error
+
+
+
+
+
+
+
+
+ org.hibernate.javax.persistence
+ hibernate-jpa-2.0-api
+ provided
+
+
+ com.h2database
+ h2
+ test
+
+
+ mysql
+ mysql-connector-java
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+ org.hibernate
+ hibernate-entitymanager
+ test
+
+
+
+
+
+ h2
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
+ org.h2.Driver
+
+
+
+
+
+
+
+ mysql
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ jdbc:mysql://localhost:3306/ispn_jpa_test
+ com.mysql.jdbc.Driver
+ root
+
+
+
+
+
+
+
+
+
diff --git a/main/java/org/infinispan/persistence/jpa/EntityManagerFactoryRegistry.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/EntityManagerFactoryRegistry.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/EntityManagerFactoryRegistry.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/EntityManagerFactoryRegistry.java
diff --git a/main/java/org/infinispan/persistence/jpa/JpaStore.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/JpaStore.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/JpaStore.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/JpaStore.java
diff --git a/main/java/org/infinispan/persistence/jpa/JpaStoreException.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/JpaStoreException.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/JpaStoreException.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/JpaStoreException.java
diff --git a/main/java/org/infinispan/persistence/jpa/JpaStoreLifecycleManager.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/JpaStoreLifecycleManager.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/JpaStoreLifecycleManager.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/JpaStoreLifecycleManager.java
diff --git a/main/java/org/infinispan/persistence/jpa/MetadataEntity.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/MetadataEntity.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/MetadataEntity.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/MetadataEntity.java
diff --git a/main/java/org/infinispan/persistence/jpa/Stats.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/Stats.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/Stats.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/Stats.java
diff --git a/main/java/org/infinispan/persistence/jpa/configuration/Attribute.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/Attribute.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/configuration/Attribute.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/Attribute.java
diff --git a/main/java/org/infinispan/persistence/jpa/configuration/Element.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/Element.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/configuration/Element.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/Element.java
diff --git a/main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfiguration.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfiguration.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfiguration.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfiguration.java
diff --git a/main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfigurationBuilder.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfigurationBuilder.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfigurationBuilder.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfigurationBuilder.java
diff --git a/main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfigurationParser60.java b/persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfigurationParser60.java
similarity index 100%
rename from main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfigurationParser60.java
rename to persistence/jpa/src/main/java/org/infinispan/persistence/jpa/configuration/JpaStoreConfigurationParser60.java
diff --git a/main/resources/META-INF/services/org.infinispan.configuration.parsing.ConfigurationParser b/persistence/jpa/src/main/resources/META-INF/services/org.infinispan.configuration.parsing.ConfigurationParser
similarity index 100%
rename from main/resources/META-INF/services/org.infinispan.configuration.parsing.ConfigurationParser
rename to persistence/jpa/src/main/resources/META-INF/services/org.infinispan.configuration.parsing.ConfigurationParser
diff --git a/main/resources/META-INF/services/org.infinispan.lifecycle.ModuleLifecycle b/persistence/jpa/src/main/resources/META-INF/services/org.infinispan.lifecycle.ModuleLifecycle
similarity index 100%
rename from main/resources/META-INF/services/org.infinispan.lifecycle.ModuleLifecycle
rename to persistence/jpa/src/main/resources/META-INF/services/org.infinispan.lifecycle.ModuleLifecycle
diff --git a/main/resources/schema/infinispan-cachestore-jpa-config-6.0.xsd b/persistence/jpa/src/main/resources/schema/infinispan-cachestore-jpa-config-6.0.xsd
similarity index 100%
rename from main/resources/schema/infinispan-cachestore-jpa-config-6.0.xsd
rename to persistence/jpa/src/main/resources/schema/infinispan-cachestore-jpa-config-6.0.xsd
diff --git a/test/java/org/infinispan/persistence/jpa/BaseJpaStoreTest.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/BaseJpaStoreTest.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/BaseJpaStoreTest.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/BaseJpaStoreTest.java
diff --git a/test/java/org/infinispan/persistence/jpa/JpaConfigurationTest.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaConfigurationTest.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/JpaConfigurationTest.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaConfigurationTest.java
diff --git a/test/java/org/infinispan/persistence/jpa/JpaStoreFunctionalTest.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStoreFunctionalTest.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/JpaStoreFunctionalTest.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStoreFunctionalTest.java
diff --git a/test/java/org/infinispan/persistence/jpa/JpaStorePersonEntityTest.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStorePersonEntityTest.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/JpaStorePersonEntityTest.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStorePersonEntityTest.java
diff --git a/test/java/org/infinispan/persistence/jpa/JpaStoreTest.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStoreTest.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/JpaStoreTest.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStoreTest.java
diff --git a/test/java/org/infinispan/persistence/jpa/JpaStoreUserEntityTest.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStoreUserEntityTest.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/JpaStoreUserEntityTest.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStoreUserEntityTest.java
diff --git a/test/java/org/infinispan/persistence/jpa/JpaStoreVehicleEntityTest.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStoreVehicleEntityTest.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/JpaStoreVehicleEntityTest.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/JpaStoreVehicleEntityTest.java
diff --git a/test/java/org/infinispan/persistence/jpa/TestObject.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/TestObject.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/TestObject.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/TestObject.java
diff --git a/test/java/org/infinispan/persistence/jpa/entity/Address.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/Address.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/entity/Address.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/Address.java
diff --git a/test/java/org/infinispan/persistence/jpa/entity/Document.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/Document.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/entity/Document.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/Document.java
diff --git a/test/java/org/infinispan/persistence/jpa/entity/KeyValueEntity.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/KeyValueEntity.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/entity/KeyValueEntity.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/KeyValueEntity.java
diff --git a/test/java/org/infinispan/persistence/jpa/entity/Person.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/Person.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/entity/Person.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/Person.java
diff --git a/test/java/org/infinispan/persistence/jpa/entity/User.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/User.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/entity/User.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/User.java
diff --git a/test/java/org/infinispan/persistence/jpa/entity/Vehicle.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/Vehicle.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/entity/Vehicle.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/Vehicle.java
diff --git a/test/java/org/infinispan/persistence/jpa/entity/VehicleId.java b/persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/VehicleId.java
similarity index 100%
rename from test/java/org/infinispan/persistence/jpa/entity/VehicleId.java
rename to persistence/jpa/src/test/java/org/infinispan/persistence/jpa/entity/VehicleId.java
diff --git a/test/resources/META-INF/persistence.xml b/persistence/jpa/src/test/resources/META-INF/persistence.xml
similarity index 100%
rename from test/resources/META-INF/persistence.xml
rename to persistence/jpa/src/test/resources/META-INF/persistence.xml
diff --git a/test/resources/config/jpa-config-60.xml b/persistence/jpa/src/test/resources/config/jpa-config-60.xml
similarity index 100%
rename from test/resources/config/jpa-config-60.xml
rename to persistence/jpa/src/test/resources/config/jpa-config-60.xml
diff --git a/pom.xml b/pom.xml
index 8f3d827e268d..a04305dfcc83 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,6 +34,7 @@
lucene/lucene-v3
persistence
persistence/jdbc
+ persistence/jpa
persistence/remote
persistence/cli
persistence/leveldb
diff --git a/src/main/resources/assemblies/all.xml b/src/main/resources/assemblies/all.xml
index 50722825384b..1d6ea1baade7 100644
--- a/src/main/resources/assemblies/all.xml
+++ b/src/main/resources/assemblies/all.xml
@@ -57,6 +57,7 @@
org.infinispan:infinispan-cli-client
org.infinispan:infinispan-cli-server
org.infinispan:infinispan-cachestore-jdbc
+ org.infinispan:infinispan-cachestore-jpa
org.infinispan:infinispan-cachestore-remote
org.infinispan:infinispan-cachestore-cli
org.infinispan:infinispan-cachestore-rest
@@ -307,6 +308,7 @@
false
org.infinispan:infinispan-cachestore-jdbc
+ org.infinispan:infinispan-cachestore-jpa
org.infinispan:infinispan-cachestore-remote
org.infinispan:infinispan-cachestore-cli
org.infinispan:infinispan-cachestore-leveldb