From 9f09f58f717e6e76ebd64cf6a99a33c860e6eb5a Mon Sep 17 00:00:00 2001 From: "joe.fialli" Date: Fri, 13 Dec 2024 06:29:01 -0500 Subject: [PATCH] Enh 37238346 - [37238325->25.03] Move JpaCacheLoader/Store from TopLink to Coherence produced coherence-jpa module (main->ce-main) Remote remote.full on coherence-ce/main success, changes 112912, synced @112913, job.9.20241213013337.16468 [git-p4: depot-paths = "//dev/coherence-ce/main/": change = 112917] --- prj/coherence-bom/pom.xml | 5 + prj/coherence-dependencies/pom.xml | 28 ++ prj/coherence-javadoc/pom.xml | 17 +- prj/coherence-jpa/pom.xml | 129 +++++++ .../oracle/coherence/jpa/JpaCacheLoader.java | 198 +++++++++++ .../oracle/coherence/jpa/JpaCacheStore.java | 197 +++++++++++ .../oracle/coherence/jpa/package-info.java | 18 + prj/coverage/pom.xml | 5 + prj/pom.xml | 2 + prj/test/distribution/osgi/pom.xml | 22 +- .../tangosol/coherence/osgi/JpaOsgiTest.java | 59 ++++ .../CoherenceJpaOsgiTestBundleActivator.java | 99 ++++++ .../coherence-jpa-osgi-test.properties | 16 + prj/test/functional/jpa/pom.xml | 97 ++++++ .../jpa/jpatest/AbstractPersistenceTest.java | 283 ++++++++++++++++ .../jpa/jpatest/JpaCacheStoreTest.java | 45 +++ .../JpaCacheStoreWithEmbeddedIdTest.java | 44 +++ .../jpatest/JpaCacheStoreWithIdClassTest.java | 44 +++ .../java/orm/AbstractPersistenceTests.java | 320 ++++++++++++++++++ .../src/main/java/orm/JpaCacheStoreTests.java | 45 +++ .../orm/JpaCacheStoreWithEmbeddedIdTests.java | 45 +++ .../orm/JpaCacheStoreWithIdClassTests.java | 45 +++ .../jpa/src/main/resources/META-INF/orm.xml | 57 ++++ .../main/resources/META-INF/persistence.xml | 38 +++ .../src/main/resources/jpa-cache-config.xml | 80 +++++ prj/test/functional/pom.xml | 1 + 26 files changed, 1937 insertions(+), 2 deletions(-) create mode 100644 prj/coherence-jpa/pom.xml create mode 100644 prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/JpaCacheLoader.java create mode 100644 prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/JpaCacheStore.java create mode 100644 prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/package-info.java create mode 100644 prj/test/distribution/osgi/src/test/java/com/tangosol/coherence/osgi/JpaOsgiTest.java create mode 100644 prj/test/distribution/osgi/src/test/java/com/tangosol/coherence/osgi/jpaosgitest/CoherenceJpaOsgiTestBundleActivator.java create mode 100644 prj/test/distribution/osgi/src/test/resources/com/tangosol/coherence/osgi/jpaosgitest/coherence-jpa-osgi-test.properties create mode 100644 prj/test/functional/jpa/pom.xml create mode 100644 prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/AbstractPersistenceTest.java create mode 100644 prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreTest.java create mode 100644 prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreWithEmbeddedIdTest.java create mode 100644 prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreWithIdClassTest.java create mode 100644 prj/test/functional/jpa/src/main/java/orm/AbstractPersistenceTests.java create mode 100644 prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreTests.java create mode 100644 prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreWithEmbeddedIdTests.java create mode 100644 prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreWithIdClassTests.java create mode 100644 prj/test/functional/jpa/src/main/resources/META-INF/orm.xml create mode 100644 prj/test/functional/jpa/src/main/resources/META-INF/persistence.xml create mode 100644 prj/test/functional/jpa/src/main/resources/jpa-cache-config.xml diff --git a/prj/coherence-bom/pom.xml b/prj/coherence-bom/pom.xml index 37838f92cb467..dfb6a8df53a06 100644 --- a/prj/coherence-bom/pom.xml +++ b/prj/coherence-bom/pom.xml @@ -191,6 +191,11 @@ coherence-jcache ${project.version} + + ${coherence.group.id} + coherence-jpa + ${project.version} + ${coherence.group.id} coherence-json diff --git a/prj/coherence-dependencies/pom.xml b/prj/coherence-dependencies/pom.xml index 6fe77ec99fcdb..1881900480259 100644 --- a/prj/coherence-dependencies/pom.xml +++ b/prj/coherence-dependencies/pom.xml @@ -152,6 +152,7 @@ 3.1 4.0.1 + 3.0.4 5.1.1 8.5.14 @@ -214,6 +215,7 @@ 3.0.1 2.0.1 + 3.2.0 2.1.0 4.0.4 2.3.6 @@ -387,6 +389,20 @@ ${jhdf.version} + + + org.eclipse.persistence + eclipselink + ${eclipselink.version} + + + + + jakarta.persistence + jakarta.persistence-api + ${jakarta.persistence.version} + + org.eclipse.microprofile.config @@ -444,6 +460,13 @@ import + + + org.hsqldb + hsqldb + ${hsqldb.version} + + com.fasterxml.jackson.core @@ -813,6 +836,11 @@ jaxb-impl ${jaxb-impl.version} + + com.sun.xml.bind + jaxb-xjc + ${jaxb-impl.version} + jakarta.xml.bind jakarta.xml.bind-api diff --git a/prj/coherence-javadoc/pom.xml b/prj/coherence-javadoc/pom.xml index e237f2e570fac..de2e39d94ae95 100644 --- a/prj/coherence-javadoc/pom.xml +++ b/prj/coherence-javadoc/pom.xml @@ -101,6 +101,12 @@ ${project.version} + + ${coherence.group.id} + coherence-jpa + ${project.version} + + ${coherence.group.id} coherence-discovery @@ -480,7 +486,10 @@ ../coherence-java-client/src/main/java - + + ../coherence-jpa/src/main/java + + ../coherence-discovery/src/main/java @@ -537,6 +546,8 @@ com/oracle/coherence/concurrent/**/*.java + com/oracle/coherence/jpa/**/*.java + com/oracle/coherence/mp/**/*.java com/oracle/coherence/grpc/**/*.java @@ -794,6 +805,10 @@ gRPC com.oracle.coherence.grpc* + + JPA Integration + com.oracle.coherence.jpa* + Repository API com.oracle.coherence.repository* diff --git a/prj/coherence-jpa/pom.xml b/prj/coherence-jpa/pom.xml new file mode 100644 index 0000000000000..5c3d37727ba22 --- /dev/null +++ b/prj/coherence-jpa/pom.xml @@ -0,0 +1,129 @@ + + + + 4.0.0 + + + com.oracle.coherence.ce + main + ${revision} + ../pom.xml + + + coherence-jpa + Coherence JPA Integration + + + com.oracle.coherence.jpa + + + false + + + + + ${coherence.group.id} + coherence + ${project.version} + + + jakarta.persistence + jakarta.persistence-api + + + + + + + maven-compiler-plugin + + + compile-java21 + compile + + compile + + + 21 + + ${project.basedir}/src/main/java21 + + true + + + + + + + + org.codehaus.mojo + flatten-maven-plugin + + + + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + org.apache.felix + maven-bundle-plugin + + + manifest + process-classes + + manifest + + + + com.oracle.coherence.jpa.* + + com.tangosol.net.cache;version="[${project.version.short},${project.version.next.short})",com.tangosol.util;version="[${project.version.short},${project.version.next.short})",jakarta.persistence;version="[3.1.0,4.0)" + + + + + + + + + + com.oracle.coherence.moditect + moditect-maven-plugin + + + add-module-info + package + + add-module-info + + + + + ${module.name} + true + + *; + + + + + + + + + + + + \ No newline at end of file diff --git a/prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/JpaCacheLoader.java b/prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/JpaCacheLoader.java new file mode 100644 index 0000000000000..46d908415cdb3 --- /dev/null +++ b/prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/JpaCacheLoader.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ +package com.oracle.coherence.jpa; + +import com.tangosol.net.cache.CacheLoader; + +import com.tangosol.util.Base; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.Persistence; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * JPA implementation of the {@link CacheLoader} interface. + *

+ * Use this class as a load-only implementation that uses any JPA + * implementation to load entities from a data store. The entities must be + * mapped to the data store and a JPA persistence unit configuration must + * exist. + *

+ * Use the {@link JpaCacheStore} class for a full load and store implementation. + * + * @author mlk 2007.04.20, jh 2007.05.18 + * @see JpaCacheStore + */ +public class JpaCacheLoader + extends Base + implements CacheLoader + { + // ----- constructors --------------------------------------------------- + + /** + * Constructor which accepts an entity name, class name, and persistence + * unit name. + * + * @param sEntityName the JPA name of the entity + * @param sEntityClassName the fully-qualified class name of the entity + * @param sUnitName the name of the persistence unit + */ + public JpaCacheLoader(String sEntityName, String sEntityClassName, String sUnitName) + { + initialize(sEntityName, sEntityClassName, sUnitName, null); + } + + /** + * Constructor which accepts an entity name, class name, persistence unit + * name, and classloader. + * + * @param sEntityName the JPA name of the entity + * @param sEntityClassName the fully-qualified class name of the entity + * @param sUnitName the name of the persistence unit + * @param loader the ClassLoader used to load the entity class + */ + public JpaCacheLoader(String sEntityName, String sEntityClassName, String sUnitName, ClassLoader loader) + { + initialize(sEntityName, sEntityClassName, sUnitName, loader); + } + + // ----- CacheLoader interface ------------------------------------------ + + @SuppressWarnings({"unchecked"}) + @Override + public V load(K oKey) + { + EntityManager em = getEntityManager(); + try + { + return (V) em.find(m_sEntityClass, oKey); + } + finally + { + em.close(); + } + } + + @Override + public Map loadAll(Collection colKeys) + { + EntityManager em = getEntityManager(); + try + { + Map mapResult = new HashMap<>(); + for (Iterator iter = colKeys.iterator(); iter.hasNext();) + { + K oKey = iter.next(); + @SuppressWarnings({"unchecked"}) + V oValue = (V) em.find(m_sEntityClass, oKey); + + if (oValue != null) + { + mapResult.put(oKey, oValue); + } + } + + return mapResult; + } + finally + { + em.close(); + } + } + + // ----- helper methods ------------------------------------------------- + + /** + * Initialize this instance with the relevant metadata for the entity + * being stored. + * + * @param sEntityName the JPA name of the entity + * @param sEntityClassName the fully-qualified class name of the entity + * @param sUnitName the name of the persistence unit + * @param loader the ClassLoader used to load the entity class + */ + protected void initialize(String sEntityName, String sEntityClassName, String sUnitName, ClassLoader loader) + { + // non-null validity check + if ((sEntityName == null) | (sEntityClassName == null) | (sUnitName == null)) + { + throw new IllegalArgumentException("Entity name, fully-qualified entity" + + " class name, and persistence unit name must be specified"); + } + this.m_sEntityName = sEntityName; + + // ensure that we have ClassLoader + if (loader == null) + { + loader = getContextClassLoader(); + } + + try + { + this.m_sEntityClass = loader.loadClass(sEntityClassName); + } + catch (ClassNotFoundException e) + { + throw ensureRuntimeException(e, "Class " + sEntityClassName + + " could not be loaded"); + } + + // obtain the EntityManagerFactory + synchronized (s_mapFactories) + { + m_emf = s_mapFactories.get(sUnitName); + + // if an EntityManagerFactory has not been created, do so and + // store it for other instances to use + if (m_emf == null) + { + s_mapFactories.put(sUnitName, + m_emf = Persistence.createEntityManagerFactory(sUnitName)); + } + } + } + + /** + * Creates and returns an EntityManager. A new instance is created each + * time this method is called. + * + * @return a new EntityManager to use for a subsequent operation + */ + protected EntityManager getEntityManager() + { + return m_emf.createEntityManager(); + } + + // ----- constants ------------------------------------------------------ + + /** + * Map of all shared entity manager factories for all persistence units. + */ + protected static final Map s_mapFactories = new HashMap<>(); + + // ----- data members --------------------------------------------------- + + /** + * Name of the entity that this CacheLoader is managing. + */ + protected String m_sEntityName; + + /** + * The entity class that this CacheLoader is managing. + */ + protected Class m_sEntityClass; + + /** + * The EntityManagerFactory from which EntityManager instances are obtained. + */ + protected EntityManagerFactory m_emf; + } \ No newline at end of file diff --git a/prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/JpaCacheStore.java b/prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/JpaCacheStore.java new file mode 100644 index 0000000000000..d8034012d7c92 --- /dev/null +++ b/prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/JpaCacheStore.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ +package com.oracle.coherence.jpa; + +import com.tangosol.net.cache.CacheStore; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityTransaction; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; + +/** + * JPA implementation of the {@link CacheStore} interface. + *

+ * Use this class as a full load and store implementation that uses any JPA + * implementation to load and store entities to and from a data store. The + * entities must be mapped to the data store and a JPA persistence unit + * configuration must exist. + *

+ * NOTE: The persistence unit is assumed to be set to use RESOURCE_LOCAL + * transactions. + * + * @author mlk 2007.04.20, jh 2007.05.18 + */ +public class JpaCacheStore + extends JpaCacheLoader + implements CacheStore + { + // ----- constructors --------------------------------------------------- + + /** + * Constructor which accepts an entity name, class name, and persistence + * unit name. + * + * @param sEntityName the JPA name of the entity + * @param sEntityClassName the fully-qualified class name of the entity + * @param sUnitName the name of the persistence unit + */ + public JpaCacheStore(String sEntityName, String sEntityClassName, String sUnitName) + { + super(sEntityName, sEntityClassName, sUnitName); + } + + /** + * Constructor which accepts an entity name, class name, persistence unit + * name, and classloader. + * + * @param sEntityName the JPA name of the entity + * @param sEntityClassName the fully-qualified class name of the entity + * @param sUnitName the name of the persistence unit + * @param loader the ClassLoader used to load the entity class + */ + public JpaCacheStore(String sEntityName, String sEntityClassName, String sUnitName, ClassLoader loader) + { + super(sEntityName, sEntityClassName, sUnitName, loader); + } + + + // ----- CacheStore interface ------------------------------------------- + + @Override + public void store(K oKey, V oValue) + { + EntityManager em = getEntityManager(); + EntityTransaction tx = null; + try + { + tx = em.getTransaction(); + + tx.begin(); + em.merge(oValue); + tx.commit(); + } + catch (RuntimeException e) + { + rollback(tx); + throw e; + } + finally + { + em.close(); + } + } + + @Override + public void storeAll(Map mapEntries) + { + EntityManager em = getEntityManager(); + EntityTransaction tx = null; + try + { + tx = em.getTransaction(); + + tx.begin(); + for (Iterator iter = mapEntries.values().iterator(); iter.hasNext();) + { + em.merge(iter.next()); + } + tx.commit(); + } + catch (RuntimeException e) + { + rollback(tx); + throw e; + } + finally + { + em.close(); + } + } + + @Override + public void erase(K oKey) + { + EntityManager em = getEntityManager(); + EntityTransaction tx = null; + try + { + tx = em.getTransaction(); + + tx.begin(); + Object oValue = em.find(m_sEntityClass, oKey); + if (oValue != null) + { + em.remove(oValue); + } + tx.commit(); + } + catch (RuntimeException e) + { + rollback(tx); + throw e; + } + finally + { + em.close(); + } + } + + @Override + public void eraseAll(Collection colKeys) + { + EntityManager em = getEntityManager(); + EntityTransaction tx = null; + try + { + tx = em.getTransaction(); + + tx.begin(); + for (Iterator iter = colKeys.iterator(); iter.hasNext();) + { + K oKey = iter.next(); + Object oValue = em.find(m_sEntityClass, oKey); + if (oValue != null) + { + em.remove(oValue); + } + } + tx.commit(); + } + catch (RuntimeException e) + { + rollback(tx); + throw e; + } + finally + { + em.close(); + } + } + + + // ----- helper methods ------------------------------------------------- + + /** + * Rollback the given EntityTransaction if it is not null and is active. + * + * @param tx the EntityTransaction; may be null + */ + protected void rollback(EntityTransaction tx) + { + try + { + if (tx != null && tx.isActive()) + { + tx.rollback(); + } + } + catch (RuntimeException e) {} + } + } \ No newline at end of file diff --git a/prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/package-info.java b/prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/package-info.java new file mode 100644 index 0000000000000..34e2f62762dcd --- /dev/null +++ b/prj/coherence-jpa/src/main/java/com/oracle/coherence/jpa/package-info.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +/** + * A JPA implementation of the Coherence CacheLoader and CacheStore interface. + * Use these classes as a full load and store implementation. + * It can use any JPA implementation to load and store entities to and from a data store. + *

+ * Note: The persistence unit is assumed to be set to use RESOURCE_LOCAL transactions. + * + * @author jf 2024.12.04 + * @since 25.03 + */ +package com.oracle.coherence.jpa; \ No newline at end of file diff --git a/prj/coverage/pom.xml b/prj/coverage/pom.xml index a99d5051e172f..13ad95153f20b 100644 --- a/prj/coverage/pom.xml +++ b/prj/coverage/pom.xml @@ -155,6 +155,11 @@ coherence-jcache ${project.version} + + ${coherence.group.id} + coherence-jpa + ${project.version} + ${coherence.group.id} coherence-json diff --git a/prj/pom.xml b/prj/pom.xml index 6cd4dc28195e8..ed1c6b4926bd8 100644 --- a/prj/pom.xml +++ b/prj/pom.xml @@ -393,6 +393,7 @@ coherence-docker coherence-javadoc coherence-jcache + coherence-jpa coherence-json coherence-login coherence-management @@ -461,6 +462,7 @@ coherence-bom coherence-docker coherence-jcache + coherence-jpa coherence-json coherence-login coherence-management diff --git a/prj/test/distribution/osgi/pom.xml b/prj/test/distribution/osgi/pom.xml index 838088cd64bd5..305b3ba6c4910 100644 --- a/prj/test/distribution/osgi/pom.xml +++ b/prj/test/distribution/osgi/pom.xml @@ -1,6 +1,6 @@ + + org.eclipse.persistence + eclipselink + ${eclipselink.version} + + + + + jakarta.persistence + jakarta.persistence-api + ${jakarta.persistence.version} + + ${coherence.group.id} coherence-bedrock-testing-support diff --git a/prj/test/distribution/osgi/src/test/java/com/tangosol/coherence/osgi/JpaOsgiTest.java b/prj/test/distribution/osgi/src/test/java/com/tangosol/coherence/osgi/JpaOsgiTest.java new file mode 100644 index 0000000000000..8686d8472f888 --- /dev/null +++ b/prj/test/distribution/osgi/src/test/java/com/tangosol/coherence/osgi/JpaOsgiTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ +package com.tangosol.coherence.osgi; + +import com.oracle.coherence.jpa.JpaCacheLoader; + +import com.tangosol.coherence.osgi.jpaosgitest.CoherenceJpaOsgiTestBundleActivator; + +import com.tangosol.net.CacheFactory; + +import jakarta.persistence.Persistence; + +import org.junit.Ignore; +import org.junit.Test; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; + +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * JpaOsgiTest tests the deployment and execution of the + * coherence-jpa.jar within an OSGi container. + * + * @author hr 2012.01.29 + * @since Coherence 12.1.2 + */ +public class JpaOsgiTest + extends AbstractOsgiTest + { + @Test + public void testDeployBundle() throws BundleException + { + Container container = m_container; + String sPackage = CoherenceJpaOsgiTestBundleActivator.class.getPackage().getName().replace('.','/'); + + listBundles(); + + // deploy dependencies + deployDependency(CacheFactory.class); + deployDependency(Persistence.class); + deployDependency(JpaCacheLoader.class); + + // deploy this test as a bundle + container.packageAndDeploy("/" + sPackage + "/coherence-jpa-osgi-test.properties"); + + listBundles(); + + // ensure all known bundles are deployed and active + assertThat(container.getBundle("Coherence"), hasState(Bundle.ACTIVE)); + assertThat(container.getBundle("Jakarta Persistence API jar"), hasState(Bundle.ACTIVE)); + assertThat(container.getBundle("Coherence JPA Integration"), hasState(Bundle.ACTIVE)); + assertThat(container.getBundle("CoherenceJpaOsgiTest"), hasState(Bundle.ACTIVE)); + } + } diff --git a/prj/test/distribution/osgi/src/test/java/com/tangosol/coherence/osgi/jpaosgitest/CoherenceJpaOsgiTestBundleActivator.java b/prj/test/distribution/osgi/src/test/java/com/tangosol/coherence/osgi/jpaosgitest/CoherenceJpaOsgiTestBundleActivator.java new file mode 100644 index 0000000000000..e81c0b0b68623 --- /dev/null +++ b/prj/test/distribution/osgi/src/test/java/com/tangosol/coherence/osgi/jpaosgitest/CoherenceJpaOsgiTestBundleActivator.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ +package com.tangosol.coherence.osgi.jpaosgitest; + +import com.oracle.coherence.jpa.JpaCacheStore; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +import java.util.Dictionary; + +/** + * CoherenceJpaOsgiTestBundleActivator is a part of a bundle that has a + * dependency on Coherence and Coherence JPA and will exercise some basic + * functionality. The failure of this bundle will result in this bundle being + * in an inactive state. Subsequently this will result in the failure of the + * {@link com.tangosol.coherence.osgi.JpaOsgiTest} as it asserts the + * state of this bundle. + * + * @author hr 2012.01.27 + * @since Coherence 12.1.2 + */ +public class CoherenceJpaOsgiTestBundleActivator + implements BundleActivator + { + + // ----- BundleActivator methods ---------------------------------------- + + /** + * {@inheritDoc} + */ + @Override + public void start(BundleContext context) throws Exception + { + m_ctxBundle = context; + Bundle bundle = getBundle("Coherence JPA Integration"); + + if (bundle == null) + { + throw new IllegalStateException("A dependent bundle (Coherence JPA) was not resolved."); + } + + ClassLoader cl = getClass().getClassLoader(); + Thread.currentThread().setContextClassLoader(cl); + + // introduce a compile-time dependency to JpaCacheStore to ensure + // the dependency is resolved and valid within this bundle's class + // space + Class clzJpaStore = JpaCacheStore.class; + } + + /** + * {@inheritDoc} + */ + @Override + public void stop(BundleContext context) throws Exception + { + m_ctxBundle = null; + } + + // ----- helpers -------------------------------------------------------- + + /** + * Convenience method to return a {@link Bundle} known by the container + * as the name specified. + * + * @param sBundleName the name of the bundle + * + * @return a bundle if a name is matched or null + */ + protected Bundle getBundle(String sBundleName) + { + Bundle match = null; + for (Bundle proposedBundle : m_ctxBundle.getBundles()) + { + Dictionary dictHeaders = proposedBundle.getHeaders(); + String sName = dictHeaders.get("Bundle-Name"); + + if (sName.equalsIgnoreCase(sBundleName)) + { + match = proposedBundle; + break; + } + } + return match; + } + + // ----- data members --------------------------------------------------- + + /** + * The {@link BundleContext} associated with this Bundle. + */ + private BundleContext m_ctxBundle; + } diff --git a/prj/test/distribution/osgi/src/test/resources/com/tangosol/coherence/osgi/jpaosgitest/coherence-jpa-osgi-test.properties b/prj/test/distribution/osgi/src/test/resources/com/tangosol/coherence/osgi/jpaosgitest/coherence-jpa-osgi-test.properties new file mode 100644 index 0000000000000..919ef6d098a34 --- /dev/null +++ b/prj/test/distribution/osgi/src/test/resources/com/tangosol/coherence/osgi/jpaosgitest/coherence-jpa-osgi-test.properties @@ -0,0 +1,16 @@ +# +# Copyright (c) 2000, 2024, Oracle and/or its affiliates. +# +# Licensed under the Universal Permissive License v 1.0 as shown at +# https://oss.oracle.com/licenses/upl. +# + +Bundle-Version: 1.0.1 +Bundle-Name: CoherenceJpaOsgiTest +Bundle-SymbolicName: com.tangosol.coherence.osgi.jpaosgitest +Bundle-Vendor: Oracle +Bundle-Activator: com.tangosol.coherence.osgi.jpaosgitest.CoherenceJpaOsgiTestBundleActivator +Export-Package: com.tangosol.coherence.osgi.jpaosgitest.* +Import-Package: com.oracle.coherence.jpa.*;version="[15.1.1,${project.version.next})",!data.*,* +Private-Package: data.persistence.* +Include-Resource: META-INF/**/*.xml \ No newline at end of file diff --git a/prj/test/functional/jpa/pom.xml b/prj/test/functional/jpa/pom.xml new file mode 100644 index 0000000000000..0dbf44143931e --- /dev/null +++ b/prj/test/functional/jpa/pom.xml @@ -0,0 +1,97 @@ + + + + 4.0.0 + + + com.oracle.coherence.ce.tests + coherence-functional-tests + ${revision} + ../pom.xml + + + jpa + Coherence JPA Tests + + + + stage5 + + false + + + + + + + ${project.build.outputDirectory} + jpa.tests + + + + + ${coherence.group.id} + coherence-testing-support + ${project.version} + + + ${coherence.group.id} + coherence-testing-data + ${project.version} + + + ${coherence.group.id} + coherence + ${project.version} + + + + ${coherence.group.id} + coherence-jpa + ${project.version} + + + + + jakarta.persistence + jakarta.persistence-api + ${jakarta.persistence.version} + + + org.eclipse.persistence + eclipselink + + + jakarta.xml.bind + jakarta.xml.bind-api + + + + com.sun.xml.bind + jaxb-core + + + + com.sun.xml.bind + jaxb-impl + + + + com.sun.xml.bind + jaxb-xjc + + + + + org.hsqldb + hsqldb + + + diff --git a/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/AbstractPersistenceTest.java b/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/AbstractPersistenceTest.java new file mode 100644 index 0000000000000..232e84d11864c --- /dev/null +++ b/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/AbstractPersistenceTest.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ +package com.oracle.coherence.jpa.jpatest; + +import com.tangosol.net.cache.CacheLoader; +import com.tangosol.net.cache.CacheStore; + +import com.tangosol.util.Base; + +import data.persistence.CompoundPerson1; +import data.persistence.CompoundPerson2; +import data.persistence.DomainClassPolicy; +import data.persistence.Person; + +import org.eclipse.persistence.internal.jpa.EntityManagerImpl; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.Persistence; +import jakarta.persistence.Query; + +import static org.junit.Assert.*; + +/** +* Abstract class for persistent CacheStore unit tests. JPA is used to create +* the initial data set. +*/ +public abstract class AbstractPersistenceTest + extends Base + { + // ----- test lifecycle ------------------------------------------------- + + @Before + public void setUp() + throws Exception + { + initDomainClassPolicy(); + + // create and use JPA to persist a sufficient amount of entity data + m_emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT); + EntityManager em = m_emf.createEntityManager(); + try + { + em.getTransaction().begin(); + em.persist(new Person(1, "John Wayne")); + em.persist(new Person(2, "Joe Strummer")); + em.persist(new Person(3, "Count Basie")); + em.persist(new CompoundPerson1(1, "1", "John Wayne")); + em.persist(new CompoundPerson1(2, "2", "Joe Strummer")); + em.persist(new CompoundPerson1(3, "3", "Count Basie")); + em.persist(new CompoundPerson2(1, "1", "John Wayne")); + em.persist(new CompoundPerson2(2, "2", "Joe Strummer")); + em.persist(new CompoundPerson2(3, "3", "Count Basie")); + em.getTransaction().commit(); + } + finally + { + em.close(); + } + } + + @After + public void tearDown() + throws Exception + { + // use JPA to clean up the entity data + EntityManager em = m_emf.createEntityManager(); + try + { + em.getTransaction().begin(); + Query q = em.createQuery("DELETE FROM Person p"); + q.executeUpdate(); + Query q2 = em.createQuery("DELETE FROM CompoundPerson1 p"); + q2.executeUpdate(); + Query q3 = em.createQuery("DELETE FROM CompoundPerson2 p"); + q3.executeUpdate(); + em.getTransaction().commit(); + } + finally + { + // need to clear the object cache because of bug #6006423 + ((EntityManagerImpl) em).getServerSession() + .getIdentityMapAccessor() + .initializeIdentityMaps(); + + em.close(); + m_emf.close(); + } + } + + + // ----- test methods --------------------------------------------------- + + @Test + public void testLoadUnitTest() + throws Exception + { + Base.out("testLoadUnitTest begin"); + + Object oPk = createPk(3); + Object o = getLoader().load(oPk); + assertNotNull("Result should be a single non-null entity", o); + assertEquals( "Result should have a PK of 3", oPk, getPkFromEntity(o)); + + Base.out("testLoadUnitTest done"); + } + + @Test + public void testLoadAllUnitTest() + throws Exception + { + Base.out("testLoadAllUnitTest begin"); + + Object oPk2 = createPk(2); + Object oPk3 = createPk(3); + Collection col = new HashSet(); + col.add(oPk2); + col.add(oPk3); + + Map map = getLoader().loadAll(col); + assertEquals("Wrong number of results returned", 2, map.size()); + + Base.out("testLoadAllUnitTest done"); + } + + @Test + public void testStoreUnitTest() + throws Exception + { + Base.out("testStoreUnitTest begin"); + + Object oPk = createPk(4); + Object o = newEntity(4, "John Smith"); + + getStore().store(oPk, o); + assertNotNull("Should return Person instance", getLoader().load(oPk)); + + Base.out("testStoreUnitTest done"); + } + + @Test + public void testStoreAllUnitTest() + throws Exception + { + Base.out("testStoreAllUnitTest begin"); + + HashMap map = new HashMap(); + Object oPk4 = createPk(4); + Object oPk5 = createPk(5); + Object oPk6 = createPk(6); + map.put(oPk4, newEntity(4, "John Smith")); + map.put(oPk5, newEntity(5, "Jim Cassidy")); + map.put(oPk6, newEntity(6, "Brian Dowd")); + getStore().storeAll(map); + + Object o = getLoader().load(oPk4); + assertNotNull("Should return Person instance", o); + assertEquals("Result should have a PK of 4", oPk4, getPkFromEntity(o)); + + o = getLoader().load(oPk5); + assertNotNull("Should return Person instance", o); + assertEquals("Result should have a PK of 5", oPk5, getPkFromEntity(o)); + + o = getLoader().load(oPk6); + assertNotNull("Should return Person instance", o); + assertEquals("Result should have a PK of 6", oPk6, getPkFromEntity(o)); + + Base.out("testStoreAllUnitTest done"); + } + + @Test + public void testEraseUnitTest() + throws Exception + { + Base.out("testEraseUnitTest begin"); + + Object oPk1 = createPk(1); + Object oPk2 = createPk(2); + Object oPk3 = createPk(3); + getStore().erase(oPk3); + + assertNotNull("Should not have been deleted", getLoader().load(oPk1)); + assertNotNull("Should not have been deleted", getLoader().load(oPk2)); + assertNull("Should have been deleted", getLoader().load(oPk3)); + + Base.out("testEraseUnitTest done"); + } + + @Test + public void testEraseAllUnitTest() + throws Exception + { + Base.out("testEraseAllUnitTest begin"); + + Collection col = new HashSet(); + Object oPk1 = createPk(1); + Object oPk2 = createPk(2); + Object oPk3 = createPk(3); + col.add(oPk1); + col.add(oPk2); + getStore().eraseAll(col); + + assertNull("Should have been deleted", getLoader().load(oPk1)); + assertNull("Should have been deleted", getLoader().load(oPk2)); + assertNotNull("Should not have been deleted", getLoader().load(oPk3)); + + Base.out("testEraseAllUnitTest done"); + } + + + // ----- helper methods ------------------------------------------------- + + protected abstract void initDomainClassPolicy(); + + protected Object createPk(int nId) + { + return getDomainPolicy().createPk(nId); + } + + protected Object getPkFromEntity(Object o) + { + return getDomainPolicy().getPkFromEntity(o); + } + + protected Object newEntity(int nId, String sName) + { + return getDomainPolicy().newEntity(nId, sName); + } + + + // ------ accessors ----------------------------------------------------- + + protected DomainClassPolicy getDomainPolicy() + { + return m_policy; + } + + protected CacheLoader getLoader() + { + return m_loader; + } + + protected CacheStore getStore() + { + return m_store; + } + + + // ----- constants ------------------------------------------------------ + + /** + * See persistence.xml. + */ + public static String PERSISTENCE_UNIT = "TestUnit"; + + /** + * Entity names. + */ + public static String ENTITY_PERSON = "Person"; + public static String ENTITY_PERSON_ID_CLASS = "CompoundPerson1"; + public static String ENTITY_PERSION_ID_EMBEDDED = "CompoundPerson2"; + + + // ----- data members --------------------------------------------------- + + protected EntityManagerFactory m_emf; + protected DomainClassPolicy m_policy; + protected CacheLoader m_loader; + protected CacheStore m_store; + } \ No newline at end of file diff --git a/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreTest.java b/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreTest.java new file mode 100644 index 0000000000000..c117dad58111d --- /dev/null +++ b/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +package com.oracle.coherence.jpa.jpatest; + +import com.oracle.coherence.jpa.JpaCacheLoader; +import com.oracle.coherence.jpa.JpaCacheStore; + +import data.persistence.DomainClassPolicy; + +import org.junit.Before; + +public class JpaCacheStoreTest + extends AbstractPersistenceTest + { + // ----- test lifecycle ------------------------------------------------- + + @Before + public void setUp() + throws Exception + { + super.setUp(); + m_loader = new JpaCacheLoader(ENTITY_PERSON, ENTITY_CLASS_NAME, + PERSISTENCE_UNIT); + m_store = new JpaCacheStore(ENTITY_PERSON, ENTITY_CLASS_NAME, + PERSISTENCE_UNIT); + } + + + // ----- helper methods ------------------------------------------------- + + protected void initDomainClassPolicy() + { + m_policy = new DomainClassPolicy.PersonClass(); + } + + + // ----- constants ------------------------------------------------------ + + public static String ENTITY_CLASS_NAME = "data.persistence.Person"; + } \ No newline at end of file diff --git a/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreWithEmbeddedIdTest.java b/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreWithEmbeddedIdTest.java new file mode 100644 index 0000000000000..394b50bf7558e --- /dev/null +++ b/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreWithEmbeddedIdTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ +package com.oracle.coherence.jpa.jpatest; + +import com.oracle.coherence.jpa.JpaCacheLoader; +import com.oracle.coherence.jpa.JpaCacheStore; + +import data.persistence.DomainClassPolicy; + +import org.junit.Before; + +public class JpaCacheStoreWithEmbeddedIdTest + extends AbstractPersistenceTest + { + // ----- test lifecycle ------------------------------------------------- + + @Before + public void setUp() + throws Exception + { + super.setUp(); + m_loader = new JpaCacheLoader(ENTITY_PERSION_ID_EMBEDDED, + ENTITY_CLASS_NAME, PERSISTENCE_UNIT); + m_store = new JpaCacheStore(ENTITY_PERSION_ID_EMBEDDED, + ENTITY_CLASS_NAME, PERSISTENCE_UNIT); + } + + + // ----- helper methods ------------------------------------------------- + + protected void initDomainClassPolicy() + { + m_policy = new DomainClassPolicy.CompoundPerson2Class(); + } + + + // ----- constants ------------------------------------------------------ + + public static String ENTITY_CLASS_NAME = "data.persistence.CompoundPerson2"; + } \ No newline at end of file diff --git a/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreWithIdClassTest.java b/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreWithIdClassTest.java new file mode 100644 index 0000000000000..efdbd79881df1 --- /dev/null +++ b/prj/test/functional/jpa/src/main/java/com/oracle/coherence/jpa/jpatest/JpaCacheStoreWithIdClassTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ +package com.oracle.coherence.jpa.jpatest; + +import com.oracle.coherence.jpa.JpaCacheLoader; +import com.oracle.coherence.jpa.JpaCacheStore; + +import data.persistence.DomainClassPolicy; + +import org.junit.Before; + +public class JpaCacheStoreWithIdClassTest + extends AbstractPersistenceTest + { + // ----- test lifecycle ------------------------------------------------- + + @Before + public void setUp() + throws Exception + { + super.setUp(); + m_loader = new JpaCacheLoader(ENTITY_PERSON_ID_CLASS, + ENTITY_CLASS_NAME, PERSISTENCE_UNIT); + m_store = new JpaCacheStore(ENTITY_PERSON_ID_CLASS, + ENTITY_CLASS_NAME, PERSISTENCE_UNIT); + } + + + // ----- helper methods ------------------------------------------------- + + protected void initDomainClassPolicy() + { + m_policy = new DomainClassPolicy.CompoundPerson1Class(); + } + + + // ----- constants ------------------------------------------------------ + + public static String ENTITY_CLASS_NAME = "data.persistence.CompoundPerson1"; + } \ No newline at end of file diff --git a/prj/test/functional/jpa/src/main/java/orm/AbstractPersistenceTests.java b/prj/test/functional/jpa/src/main/java/orm/AbstractPersistenceTests.java new file mode 100644 index 0000000000000..9085fe2847485 --- /dev/null +++ b/prj/test/functional/jpa/src/main/java/orm/AbstractPersistenceTests.java @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +package orm; + + +import com.tangosol.net.NamedCache; + +import com.oracle.coherence.testing.AbstractFunctionalTest; + +import data.persistence.Person; +import data.persistence.CompoundPerson1; +import data.persistence.CompoundPerson2; +import data.persistence.DomainClassPolicy; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.Persistence; +import jakarta.persistence.Query; + +import org.eclipse.persistence.internal.jpa.EntityManagerImpl; + +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import static org.junit.Assert.*; + + +/** +* Abstract class for persistent CacheStore functional tests. JPA is used to +* create the initial data set. +*/ +public abstract class AbstractPersistenceTests + extends AbstractFunctionalTest + { + // ----- constructors --------------------------------------------------- + + /** + * Create a new AbstractPersistenceTests that will use the cache + * configuration file with the given path to instantiate NamedCache + * instances. + * + * @param sPath the configuration resource name or file path + */ + public AbstractPersistenceTests(String sPath) + { + super(sPath); + } + + + // ----- test lifecycle ------------------------------------------------- + + /** + * Initialize the test class. + */ + @BeforeClass + public static void _startup() + { + // this test requires local storage to be enabled + System.setProperty("coherence.distributed.localstorage", "true"); + + AbstractFunctionalTest._startup(); + } + + + // ----- test lifecycle ------------------------------------------------- + + @Before + public void setUp() + throws Exception + { + initDomainClassPolicy(); + + // create and use JPA to persist a sufficient amount of entity data + m_emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT); + EntityManager em = m_emf.createEntityManager(); + try + { + em.getTransaction().begin(); + em.persist(new Person(1, "John Wayne")); + em.persist(new Person(2, "Joe Strummer")); + em.persist(new Person(3, "Count Basie")); + em.persist(new CompoundPerson1(1, "1", "John Wayne")); + em.persist(new CompoundPerson1(2, "2", "Joe Strummer")); + em.persist(new CompoundPerson1(3, "3", "Count Basie")); + em.persist(new CompoundPerson2(1, "1", "John Wayne")); + em.persist(new CompoundPerson2(2, "2", "Joe Strummer")); + em.persist(new CompoundPerson2(3, "3", "Count Basie")); + em.getTransaction().commit(); + } + finally + { + em.close(); + } + + initCache(); + } + + @After + public void tearDown() + throws Exception + { + // use JPA to clean up the entity data + EntityManager em = m_emf.createEntityManager(); + try + { + em.getTransaction().begin(); + Query q = em.createQuery("DELETE FROM Person p"); + q.executeUpdate(); + Query q2 = em.createQuery("DELETE FROM CompoundPerson1 p"); + q2.executeUpdate(); + Query q3 = em.createQuery("DELETE FROM CompoundPerson2 p"); + q3.executeUpdate(); + em.getTransaction().commit(); + } + finally + { + // need to clear the object cache because of bug #6006423 + ((EntityManagerImpl) em).getServerSession() + .getIdentityMapAccessor() + .initializeIdentityMaps(); + + em.close(); + m_emf.close(); + } + + closeCache(); + } + + + // ----- test methods --------------------------------------------------- + + @Test + public void testLoad() + throws Exception + { + out("testLoad begin"); + + Object oPk3 = getDomainPolicy().createPk(3); + Object o = m_cache.get(oPk3); + + assertNotNull("Result should be a single non-null entity", o); + assertEquals("Should return Person instance with id 3", oPk3, + getDomainPolicy().getPkFromEntity(o)); + + out("testLoad done"); + } + + @Test + public void testLoadAll() + throws Exception + { + out("testLoadAll begin"); + + Collection col = new HashSet(); + Object oPk1 = createPk(1); + Object oPk3 = createPk(3); + col.add(oPk1); + col.add(oPk3); + + Map map = m_cache.getAll(col); + assertNotNull("Result should be a non-null map of entities", map); + assertTrue("Result should be a non-null map of 2 entities", + map.size() == 2); + + out("testLoadAll done"); + } + + @Test + public void testStore() + throws Exception + { + out("testStore begin"); + + Object oPerson = newEntity(4, "John Smith"); + Object oPk4 = createPk(4); + m_cache.put(oPk4, oPerson); + + Object o = m_cache.get(oPk4); + assertNotNull("Should return Person instance", o); + assertEquals("Should return Person instance with id 4", oPk4, + getPkFromEntity(o)); + + out("testStore done"); + } + + @Test + public void testStoreAll() + throws Exception + { + out("testStoreAll begin"); + + HashMap map = new HashMap(); + Object oPk4 = createPk(4); + Object oPk5 = createPk(5); + Object oPk6 = createPk(6); + map.put(oPk4, newEntity(4, "John Smith")); + map.put(oPk5, newEntity(5, "Jim Cassidy")); + map.put(oPk6, newEntity(6, "Brian Dowd")); + m_cache.putAll(map); + + Object o = m_cache.get(oPk4); + assertNotNull("Should return Person instance", o); + assertEquals("Should return Person instance with id 4", oPk4, + getPkFromEntity(o)); + + o = m_cache.get(oPk5); + assertNotNull("Should return Person instance", o); + assertEquals("Should return Person instance with id 5", oPk5, + getPkFromEntity(o)); + + o = m_cache.get(oPk6); + assertNotNull("Should return Person instance", o); + assertEquals("Should return Person instance with id 6", oPk6, + getPkFromEntity(o)); + + out("testStoreAll done"); + } + + @Test + public void testErase() + throws Exception + { + out("testErase begin"); + + Object oPk4 = createPk(4); + Object oPk5 = createPk(5); + m_cache.put(oPk4, newEntity(4, "John Smith")); + m_cache.put(oPk5, newEntity(5, "Jim Cassidy")); + + Object o = m_cache.get(oPk4); + assertNotNull("Should return Person instance", o); + assertEquals("Should return Person instance with id 4", oPk4, + getPkFromEntity(o)); + + m_cache.remove(oPk4); + o = m_cache.get(oPk4); + assertNull("Should not return Person instance", o); + + o = m_cache.get(oPk5); + assertNotNull("Should return Person instance", o); + assertEquals("Should return Person instance with id 5", oPk5, + getPkFromEntity(o)); + + out("testErase done"); + } + + + // ----- helper methods ------------------------------------------------- + + protected abstract void initDomainClassPolicy(); + + protected Object createPk(int nId) + { + return getDomainPolicy().createPk(nId); + } + + protected Object getPkFromEntity(Object o) + { + return getDomainPolicy().getPkFromEntity(o); + } + + protected Object newEntity(int nId, String sName) + { + return getDomainPolicy().newEntity(nId, sName); + } + + protected abstract void initCache() + throws Exception; + + protected void closeCache() + throws Exception + { + if (m_cache != null) + { + m_cache.destroy(); + } + } + + + // ----- accessors ------------------------------------------------------ + + protected DomainClassPolicy getDomainPolicy() + { + return m_policy; + } + + + // ----- constants ------------------------------------------------------ + + /** + * See persistence.xml. + */ + public static String PERSISTENCE_UNIT = "TestUnit"; + + /** + * Entity names. + */ + public static String ENTITY_PERSON = "Person"; + public static String ENTITY_PERSON_ID_CLASS = "CompoundPerson1"; + public static String ENTITY_PERSION_ID_EMBEDDED = "CompoundPerson2"; + + + // ----- data members --------------------------------------------------- + + protected EntityManagerFactory m_emf; + protected DomainClassPolicy m_policy; + protected NamedCache m_cache; + } \ No newline at end of file diff --git a/prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreTests.java b/prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreTests.java new file mode 100644 index 0000000000000..bcaa2cd93027f --- /dev/null +++ b/prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreTests.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +package orm; + + +import data.persistence.DomainClassPolicy; + + +public class JpaCacheStoreTests + extends AbstractPersistenceTests + { + // ----- constructors --------------------------------------------------- + + /** + * Default constructor. + */ + public JpaCacheStoreTests() + { + super(CONFIG_FILE_NAME); + } + + + // ----- AbstractPersistenceTests methods ------------------------------- + + protected void initCache() + throws Exception + { + m_cache = getNamedCache(ENTITY_PERSON); + } + + protected void initDomainClassPolicy() + { + m_policy = new DomainClassPolicy.PersonClass(); + } + + + // ----- constants ------------------------------------------------------ + + public static String CONFIG_FILE_NAME = "jpa-cache-config.xml"; + } \ No newline at end of file diff --git a/prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreWithEmbeddedIdTests.java b/prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreWithEmbeddedIdTests.java new file mode 100644 index 0000000000000..31c7752b61363 --- /dev/null +++ b/prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreWithEmbeddedIdTests.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +package orm; + + +import data.persistence.DomainClassPolicy; + + +public class JpaCacheStoreWithEmbeddedIdTests + extends AbstractPersistenceTests + { + // ----- constructors --------------------------------------------------- + + /** + * Default constructor. + */ + public JpaCacheStoreWithEmbeddedIdTests() + { + super(CONFIG_FILE_NAME); + } + + + // ----- AbstractPersistenceTests methods ------------------------------- + + protected void initCache() + throws Exception + { + m_cache = getNamedCache(ENTITY_PERSION_ID_EMBEDDED); + } + + protected void initDomainClassPolicy() + { + m_policy = new DomainClassPolicy.CompoundPerson2Class(); + } + + + // ----- constants ------------------------------------------------------ + + public static String CONFIG_FILE_NAME = "jpa-cache-config.xml"; + } \ No newline at end of file diff --git a/prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreWithIdClassTests.java b/prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreWithIdClassTests.java new file mode 100644 index 0000000000000..60b73af78b4d4 --- /dev/null +++ b/prj/test/functional/jpa/src/main/java/orm/JpaCacheStoreWithIdClassTests.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. + * + * Licensed under the Universal Permissive License v 1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +package orm; + + +import data.persistence.DomainClassPolicy; + + +public class JpaCacheStoreWithIdClassTests + extends AbstractPersistenceTests + { + // ----- constructors --------------------------------------------------- + + /** + * Default constructor. + */ + public JpaCacheStoreWithIdClassTests() + { + super(CONFIG_FILE_NAME); + } + + + // ----- AbstractPersistenceTests methods ------------------------------- + + protected void initCache() + throws Exception + { + m_cache = getNamedCache(ENTITY_PERSON_ID_CLASS); + } + + protected void initDomainClassPolicy() + { + m_policy = new DomainClassPolicy.CompoundPerson1Class(); + } + + + // ----- constants ------------------------------------------------------ + + public static String CONFIG_FILE_NAME = "jpa-cache-config.xml"; + } diff --git a/prj/test/functional/jpa/src/main/resources/META-INF/orm.xml b/prj/test/functional/jpa/src/main/resources/META-INF/orm.xml new file mode 100644 index 0000000000000..977d828b5cead --- /dev/null +++ b/prj/test/functional/jpa/src/main/resources/META-INF/orm.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + FIELD + + + + + + + + data.persistence + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/prj/test/functional/jpa/src/main/resources/META-INF/persistence.xml b/prj/test/functional/jpa/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000000000..9a701e322b72b --- /dev/null +++ b/prj/test/functional/jpa/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,38 @@ + + + + + data.persistence.Person + data.persistence.CompoundPerson1 + data.persistence.CompoundPerson2 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/prj/test/functional/jpa/src/main/resources/jpa-cache-config.xml b/prj/test/functional/jpa/src/main/resources/jpa-cache-config.xml new file mode 100644 index 0000000000000..3db2660022881 --- /dev/null +++ b/prj/test/functional/jpa/src/main/resources/jpa-cache-config.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + Person + jpa-distributed + + + + CompoundPerson1 + jpa-distributed + + + + CompoundPerson2 + jpa-distributed + + + + + + + + jpa-distributed + JpaDistributedCache + + + + + + + + + + + com.oracle.coherence.jpa.JpaCacheStore + + + java.lang.String + {cache-name} + + + java.lang.String + data.persistence.{cache-name} + + + java.lang.String + TestUnit + + + + + + + + + + + + + \ No newline at end of file diff --git a/prj/test/functional/pom.xml b/prj/test/functional/pom.xml index bdde590f347f5..1a12960407734 100644 --- a/prj/test/functional/pom.xml +++ b/prj/test/functional/pom.xml @@ -155,6 +155,7 @@ io jcache jmx + jpa lambda logging management