http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java new file mode 100644 index 0000000..e859284 --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheStrategySelfTest.java @@ -0,0 +1,570 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.cache.hibernate; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.cache.Cache; +import javax.persistence.Cacheable; +import javax.persistence.Id; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteKernal; +import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; +import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; +import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.hamcrest.core.Is; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.RootClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; +import static org.apache.ignite.cache.CacheMode.PARTITIONED; +import static org.apache.ignite.cache.hibernate.HibernateAccessStrategyFactory.REGION_CACHE_PROPERTY; +import static org.hibernate.cache.spi.RegionFactory.DEFAULT_QUERY_RESULTS_REGION_UNQUALIFIED_NAME; +import static org.hibernate.cache.spi.RegionFactory.DEFAULT_UPDATE_TIMESTAMPS_REGION_UNQUALIFIED_NAME; +import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE; +import static org.junit.Assert.assertThat; + +/** + * Tests Hibernate L2 cache configuration. + */ +@SuppressWarnings("unchecked") +@RunWith(JUnit4.class) +public class HibernateL2CacheStrategySelfTest extends GridCommonAbstractTest { + /** */ + private static final String ENTITY1_NAME = Entity1.class.getName(); + + /** */ + private static final String ENTITY2_NAME = Entity2.class.getName(); + + /** */ + private static final String ENTITY3_NAME = Entity3.class.getName(); + + /** */ + private static final String ENTITY4_NAME = Entity4.class.getName(); + + /** */ + private static final String CONNECTION_URL = "jdbc:h2:mem:example;DB_CLOSE_DELAY=-1"; + + /** */ + private SessionFactory sesFactory1; + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + startGrid(0); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + stopAllGrids(); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + for (IgniteCacheProxy<?, ?> cache : ((IgniteKernal)grid(0)).caches()) + cache.clear(); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(new TcpDiscoveryVmIpFinder(true)); + + cfg.setCacheConfiguration(cacheConfiguration(ENTITY3_NAME), + cacheConfiguration(ENTITY4_NAME), + cacheConfiguration("cache1"), + cacheConfiguration("cache2"), + cacheConfiguration(DEFAULT_UPDATE_TIMESTAMPS_REGION_UNQUALIFIED_NAME), + cacheConfiguration(DEFAULT_QUERY_RESULTS_REGION_UNQUALIFIED_NAME)); + + return cfg; + } + + /** + * @param cacheName Cache name. + * @return Cache configuration. + */ + private CacheConfiguration cacheConfiguration(String cacheName) { + CacheConfiguration cfg = new CacheConfiguration(); + + cfg.setName(cacheName); + cfg.setCacheMode(PARTITIONED); + cfg.setAtomicityMode(TRANSACTIONAL); + + return cfg; + } + + /** + * @throws Exception If failed. + */ + @Test + public void testEntityCacheReadWrite() throws Exception { + for (AccessType accessType : new AccessType[]{AccessType.READ_WRITE, AccessType.NONSTRICT_READ_WRITE}) + testEntityCacheReadWrite(accessType); + } + + /** + * @param accessType Cache access type. + * @throws Exception If failed. + */ + private void testEntityCacheReadWrite(AccessType accessType) throws Exception { + log.info("Test access type: " + accessType); + + sesFactory1 = startHibernate(accessType, getTestIgniteInstanceName(0)); + + try { + // 1 Adding. + Session ses = sesFactory1.openSession(); + + try { + Transaction tr = ses.beginTransaction(); + + ses.save(new Entity1(1, "entity-1#name-1")); + ses.save(new Entity2(1, "entity-2#name-1")); + + tr.commit(); + } + finally { + ses.close(); + } + + loadEntities(sesFactory1); + + assertEquals(1, grid(0).cache("cache1").size()); + assertEquals(1, grid(0).cache("cache2").size()); + assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 1), Is.is("entity-1#name-1")); + assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 1), Is.is("entity-2#name-1")); + + // 2. Updating and adding. + ses = sesFactory1.openSession(); + + try { + Transaction tx = ses.beginTransaction(); + + Entity1 e1 = (Entity1)ses.load(Entity1.class, 1); + + e1.setName("entity-1#name-1#UPDATED-1"); + + ses.update(e1); + + ses.save(new Entity2(2, "entity-2#name-2#ADDED")); + + tx.commit(); + } + finally { + ses.close(); + } + + loadEntities(sesFactory1); + + assertEquals(1, grid(0).cache("cache1").size()); + assertEquals(2, grid(0).cache("cache2").size()); + assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 1), Is.is("entity-1#name-1#UPDATED-1")); + assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 1), Is.is("entity-2#name-1")); + assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 2), Is.is("entity-2#name-2#ADDED")); + + // 3. Updating, adding, updating. + ses = sesFactory1.openSession(); + + try { + Transaction tx = ses.beginTransaction(); + + Entity2 e2_1 = (Entity2)ses.load(Entity2.class, 1); + + e2_1.setName("entity-2#name-1#UPDATED-1"); + + ses.update(e2_1); + + ses.save(new Entity1(2, "entity-1#name-2#ADDED")); + + Entity1 e1_1 = (Entity1)ses.load(Entity1.class, 1); + + e1_1.setName("entity-1#name-1#UPDATED-2"); + + ses.update(e1_1); + + tx.commit(); + + } + finally { + ses.close(); + } + + loadEntities(sesFactory1); + + assertEquals(2, grid(0).cache("cache1").size()); + assertEquals(2, grid(0).cache("cache2").size()); + assertThat(getEntityNameFromRegion(sesFactory1, "cache2", 1), Is.is("entity-2#name-1#UPDATED-1")); + assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 2), Is.is("entity-1#name-2#ADDED")); + assertThat(getEntityNameFromRegion(sesFactory1, "cache1", 1), Is.is("entity-1#name-1#UPDATED-2")); + + ses = sesFactory1.openSession(); + + sesFactory1.getStatistics().logSummary(); + + ses.close(); + } + finally { + cleanup(); + } + } + + /** + * @param sesFactory Session factory. + */ + private void loadEntities(SessionFactory sesFactory) { + Session ses = sesFactory.openSession(); + + try { + List<Entity1> list1 = ses.createCriteria(ENTITY1_NAME).list(); + + for (Entity1 e1 : list1) + assertNotNull(e1.getName()); + + List<Entity2> list2 = ses.createCriteria(ENTITY2_NAME).list(); + + for (Entity2 e2 : list2) + assertNotNull(e2.getName()); + } + finally { + ses.close(); + } + } + + /** + * @param sesFactory Session Factory. + * @param regionName Region Name. + * @param id Id. + * @return Entity Name. + */ + private String getEntityNameFromRegion(SessionFactory sesFactory, String regionName, int id) { + Session ses = sesFactory.openSession(); + + try { + for (Cache.Entry<Object, Object> entry : grid(0).cache(regionName)) { + if (((HibernateKeyWrapper)entry.getKey()).id().equals(id)) + return (String) ((HashMap) entry.getValue()).get("name"); + } + + return null; + } + finally { + ses.close(); + } + } + + /** + * @param accessType Cache access typr. + * @param igniteInstanceName Name of the grid providing caches. + * @return Session factory. + */ + private SessionFactory startHibernate(AccessType accessType, String igniteInstanceName) { + StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder(); + + builder.applySetting("hibernate.connection.url", CONNECTION_URL); + + for (Map.Entry<String, String> e : HibernateL2CacheSelfTest.hibernateProperties(igniteInstanceName, accessType.name()).entrySet()) + builder.applySetting(e.getKey(), e.getValue()); + + builder.applySetting(USE_STRUCTURED_CACHE, "true"); + builder.applySetting(REGION_CACHE_PROPERTY + ENTITY1_NAME, "cache1"); + builder.applySetting(REGION_CACHE_PROPERTY + ENTITY2_NAME, "cache2"); + builder.applySetting(REGION_CACHE_PROPERTY + DEFAULT_UPDATE_TIMESTAMPS_REGION_UNQUALIFIED_NAME, DEFAULT_UPDATE_TIMESTAMPS_REGION_UNQUALIFIED_NAME); + builder.applySetting(REGION_CACHE_PROPERTY + DEFAULT_QUERY_RESULTS_REGION_UNQUALIFIED_NAME, DEFAULT_QUERY_RESULTS_REGION_UNQUALIFIED_NAME); + + MetadataSources metadataSources = new MetadataSources(builder.build()); + + metadataSources.addAnnotatedClass(Entity1.class); + metadataSources.addAnnotatedClass(Entity2.class); + metadataSources.addAnnotatedClass(Entity3.class); + metadataSources.addAnnotatedClass(Entity4.class); + + Metadata metadata = metadataSources.buildMetadata(); + + for (PersistentClass entityBinding : metadata.getEntityBindings()) { + if (!entityBinding.isInherited()) + ((RootClass)entityBinding).setCacheConcurrencyStrategy(accessType.getExternalName()); + } + + return metadata.buildSessionFactory(); + } + + /** + * Test Hibernate entity1. + */ + @javax.persistence.Entity + @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"}) + @Cacheable + public static class Entity1 { + /** */ + private int id; + + /** */ + private String name; + + /** + * + */ + public Entity1() { + // No-op. + } + + /** + * @param id ID. + * @param name Name. + */ + Entity1(int id, String name) { + this.id = id; + this.name = name; + } + + /** + * @return ID. + */ + @Id + public int getId() { + return id; + } + + /** + * @param id ID. + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return Name. + */ + public String getName() { + return name; + } + + /** + * @param name Name. + */ + public void setName(String name) { + this.name = name; + } + } + + /** + * Test Hibernate entity2. + */ + @javax.persistence.Entity + @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"}) + @Cacheable + public static class Entity2 { + /** */ + private int id; + + /** */ + private String name; + + /** + * + */ + public Entity2() { + // No-op. + } + + /** + * @param id ID. + * @param name Name. + */ + Entity2(int id, String name) { + this.id = id; + this.name = name; + } + + /** + * @return ID. + */ + @Id + public int getId() { + return id; + } + + /** + * @param id ID. + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return Name. + */ + public String getName() { + return name; + } + + /** + * @param name Name. + */ + public void setName(String name) { + this.name = name; + } + } + + /** + * Test Hibernate entity3. + */ + @javax.persistence.Entity + @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"}) + @Cacheable + public static class Entity3 { + /** */ + private int id; + + /** */ + private String name; + + /** + * + */ + public Entity3() { + // No-op. + } + + /** + * @param id ID. + * @param name Name. + */ + public Entity3(int id, String name) { + this.id = id; + this.name = name; + } + + /** + * @return ID. + */ + @Id + public int getId() { + return id; + } + + /** + * @param id ID. + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return Name. + */ + public String getName() { + return name; + } + + /** + * @param name Name. + */ + public void setName(String name) { + this.name = name; + } + } + + /** + * Test Hibernate entity4. + */ + @javax.persistence.Entity + @SuppressWarnings({"PublicInnerClass", "UnnecessaryFullyQualifiedName"}) + @Cacheable + public static class Entity4 { + /** */ + private int id; + + /** */ + private String name; + + /** + * + */ + public Entity4() { + // No-op. + } + + /** + * @param id ID. + * @param name Name. + */ + public Entity4(int id, String name) { + this.id = id; + this.name = name; + } + + /** + * @return ID. + */ + @Id + public int getId() { + return id; + } + + /** + * @param id ID. + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return Name. + */ + public String getName() { + return name; + } + + /** + * @param name Name. + */ + public void setName(String name) { + this.name = name; + } + } + + /** + * Closes session factories and clears data from caches. + * + * @throws Exception If failed. + */ + private void cleanup() throws Exception { + if (sesFactory1 != null) + sesFactory1.close(); + + sesFactory1 = null; + + for (IgniteCacheProxy<?, ?> cache : ((IgniteKernal)grid(0)).caches()) + cache.clear(); + } +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheTransactionalSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheTransactionalSelfTest.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheTransactionalSelfTest.java new file mode 100644 index 0000000..5175292 --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheTransactionalSelfTest.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.cache.hibernate; + +import java.util.Collections; +import javax.cache.configuration.Factory; +import javax.transaction.Synchronization; +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; +import org.apache.commons.dbcp.managed.BasicManagedDataSource; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.h2.jdbcx.JdbcDataSource; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; +import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; +import org.jetbrains.annotations.Nullable; +import org.objectweb.jotm.Jotm; + +/** + * + * Tests Hibernate L2 cache with TRANSACTIONAL access mode (Hibernate and Cache are configured + * to used the same TransactionManager). + */ +public class HibernateL2CacheTransactionalSelfTest extends HibernateL2CacheSelfTest { + /** */ + private static Jotm jotm; + + /** + */ + private static class TestJtaPlatform extends AbstractJtaPlatform { + /** {@inheritDoc} */ + @Override protected TransactionManager locateTransactionManager() { + return jotm.getTransactionManager(); + } + + /** {@inheritDoc} */ + @Override protected UserTransaction locateUserTransaction() { + return jotm.getUserTransaction(); + } + } + + /** + */ + @SuppressWarnings("PublicInnerClass") + public static class TestTmFactory implements Factory<TransactionManager> { + /** */ + private static final long serialVersionUID = 0; + + /** {@inheritDoc} */ + @Override public TransactionManager create() { + return jotm.getTransactionManager(); + } + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + jotm = new Jotm(true, false); + + super.beforeTestsStarted(); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + super.afterTestsStopped(); + + if (jotm != null) + jotm.stop(); + + jotm = null; + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.getTransactionConfiguration().setTxManagerFactory(new TestTmFactory()); + cfg.getTransactionConfiguration().setUseJtaSynchronization(useJtaSynchronization()); + + return cfg; + } + + /** {@inheritDoc} */ + @Override protected CacheConfiguration transactionalRegionConfiguration(String regionName) { + CacheConfiguration cfg = super.transactionalRegionConfiguration(regionName); + + cfg.setNearConfiguration(null); + + return cfg; + } + + /** {@inheritDoc} */ + @Nullable @Override protected StandardServiceRegistryBuilder registryBuilder() { + StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder(); + + DatasourceConnectionProviderImpl connProvider = new DatasourceConnectionProviderImpl(); + + BasicManagedDataSource dataSrc = new BasicManagedDataSource(); // JTA-aware data source. + + dataSrc.setTransactionManager(jotm.getTransactionManager()); + + dataSrc.setDefaultAutoCommit(false); + + JdbcDataSource h2DataSrc = new JdbcDataSource(); + + h2DataSrc.setURL(CONNECTION_URL); + + dataSrc.setXaDataSourceInstance(h2DataSrc); + + connProvider.setDataSource(dataSrc); + + connProvider.configure(Collections.emptyMap()); + + builder.addService(ConnectionProvider.class, connProvider); + + builder.addService(JtaPlatform.class, new TestJtaPlatform()); + + builder.applySetting(Environment.TRANSACTION_COORDINATOR_STRATEGY, JtaTransactionCoordinatorBuilderImpl.class.getName()); + + return builder; + } + + /** {@inheritDoc} */ + @Override protected AccessType[] accessTypes() { + return new AccessType[]{AccessType.TRANSACTIONAL}; + } + + /** + * @return Whether to use {@link Synchronization}. + */ + protected boolean useJtaSynchronization() { + return false; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheTransactionalUseSyncSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheTransactionalUseSyncSelfTest.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheTransactionalUseSyncSelfTest.java new file mode 100644 index 0000000..44899f9 --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/hibernate/HibernateL2CacheTransactionalUseSyncSelfTest.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.cache.hibernate; + +import javax.transaction.Synchronization; + +/** + * Tests Hibernate L2 cache with TRANSACTIONAL access mode and {@link Synchronization} + * instead of XA resource. + */ +public class HibernateL2CacheTransactionalUseSyncSelfTest extends HibernateL2CacheTransactionalSelfTest { + /** {@inheritDoc} */ + @Override protected boolean useJtaSynchronization() { + return true; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreNodeRestartTest.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreNodeRestartTest.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreNodeRestartTest.java new file mode 100644 index 0000000..d5496af --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreNodeRestartTest.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.cache.store.hibernate; + +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.cache.store.CacheStore; +import org.apache.ignite.configuration.NearCacheConfiguration; +import org.apache.ignite.internal.processors.cache.integration.IgniteCacheStoreNodeRestartAbstractTest; + +public class CacheHibernateBlobStoreNodeRestartTest extends IgniteCacheStoreNodeRestartAbstractTest { + /** {@inheritDoc} */ + @Override protected CacheStore getStore() { + return new CacheHibernateBlobStore(); + } + + /** {@inheritDoc} */ + @Override protected CacheMode cacheMode() { + return CacheMode.PARTITIONED; + } + + /** {@inheritDoc} */ + @Override protected CacheAtomicityMode atomicityMode() { + return CacheAtomicityMode.ATOMIC; + } + + /** {@inheritDoc} */ + @Override protected NearCacheConfiguration nearConfiguration() { + return null; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreSelfTest.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreSelfTest.java new file mode 100644 index 0000000..8b75bb7 --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreSelfTest.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.cache.store.hibernate; + +import java.io.File; +import java.net.URL; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.testframework.junits.cache.GridAbstractCacheStoreSelfTest; +import org.hibernate.FlushMode; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.resource.transaction.spi.TransactionStatus; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Cache store test. + */ +@RunWith(JUnit4.class) +public class CacheHibernateBlobStoreSelfTest extends + GridAbstractCacheStoreSelfTest<CacheHibernateBlobStore<Object, Object>> { + /** + * @throws Exception If failed. + */ + public CacheHibernateBlobStoreSelfTest() throws Exception { + // No-op. + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + super.afterTest(); + + Session s = store.session(null); + + if (s == null) + return; + + try { + s.createQuery("delete from " + CacheHibernateBlobStoreEntry.class.getSimpleName()) + .setFlushMode(FlushMode.ALWAYS).executeUpdate(); + + Transaction hTx = s.getTransaction(); + + if (hTx != null && hTx.getStatus() == TransactionStatus.ACTIVE) + hTx.commit(); + } + finally { + s.close(); + } + } + + /** {@inheritDoc} */ + @Override protected CacheHibernateBlobStore<Object, Object> store() { + return new CacheHibernateBlobStore<>(); + } + + /** + * @throws Exception If failed. + */ + @Test + public void testConfigurationByUrl() throws Exception { + URL url = U.resolveIgniteUrl(CacheHibernateStoreFactorySelfTest.MODULE_PATH + + "/src/test/resources/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml"); + + assert url != null; + + store.setHibernateConfigurationPath(url.toString()); + + // Store will be implicitly initialized. + store.load("key"); + } + + /** + * @throws Exception If failed. + */ + @Test + public void testConfigurationByFile() throws Exception { + URL url = U.resolveIgniteUrl(CacheHibernateStoreFactorySelfTest.MODULE_PATH + + "/src/test/resources/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml"); + + assert url != null; + + File file = new File(url.toURI()); + + store.setHibernateConfigurationPath(file.getAbsolutePath()); + + // Store will be implicitly initialized. + store.load("key"); + } + + /** + * @throws Exception If failed. + */ + @Test + public void testConfigurationByResource() throws Exception { + store.setHibernateConfigurationPath("/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml"); + + // Store will be implicitly initialized. + store.load("key"); + } + +} http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreFactorySelfTest.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreFactorySelfTest.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreFactorySelfTest.java new file mode 100644 index 0000000..0a9a881 --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreFactorySelfTest.java @@ -0,0 +1,336 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.cache.store.hibernate; + +import java.sql.Connection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.persistence.EntityGraph; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceUnitUtil; +import javax.persistence.Query; +import javax.persistence.SynchronizationType; +import javax.persistence.criteria.CriteriaBuilder; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteException; +import org.apache.ignite.Ignition; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.hibernate.Cache; +import org.hibernate.HibernateException; +import org.hibernate.Metamodel; +import org.hibernate.Session; +import org.hibernate.SessionBuilder; +import org.hibernate.SessionFactory; +import org.hibernate.StatelessSession; +import org.hibernate.StatelessSessionBuilder; +import org.hibernate.TypeHelper; +import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.engine.spi.FilterDefinition; +import org.hibernate.metadata.ClassMetadata; +import org.hibernate.metadata.CollectionMetadata; +import org.hibernate.stat.Statistics; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for Cache jdbc blob store factory. + */ +@RunWith(JUnit4.class) +public class CacheHibernateStoreFactorySelfTest extends GridCommonAbstractTest { + /** Cache name. */ + private static final String CACHE_NAME = "test"; + + /** */ + static final String MODULE_PATH = "modules/hibernate-5.3/"; + + /** + * @throws Exception If failed. + */ + @Test + public void testCacheConfiguration() throws Exception { + try (Ignite ignite1 = startGrid(0)) { + IgniteCache<Integer, String> cache1 = ignite1.getOrCreateCache(cacheConfiguration()); + + checkStore(cache1); + } + } + + /** + * @throws Exception If failed. + */ + @Test + public void testXmlConfiguration() throws Exception { + try (Ignite ignite = Ignition.start(MODULE_PATH + "/src/test/config/factory-cache.xml")) { + try(Ignite ignite1 = Ignition.start(MODULE_PATH + "/src/test/config/factory-cache1.xml")) { + checkStore(ignite.<Integer, String>cache(CACHE_NAME), DummySessionFactoryExt.class); + + checkStore(ignite1.<Integer, String>cache(CACHE_NAME), DummySessionFactory.class); + } + } + } + + + /** + * @throws Exception If failed. + */ + @Test + public void testIncorrectBeanConfiguration() { + GridTestUtils.assertThrows(log, new Callable<Object>() { + @Override + public Object call() throws Exception { + String path = MODULE_PATH + "/src/test/config/factory-incorrect-store-cache.xml"; + try (Ignite ignite = Ignition.start(path)) { + ignite.cache(CACHE_NAME).getConfiguration(CacheConfiguration.class).getCacheStoreFactory().create(); + } + return null; + } + }, IgniteException.class, "Failed to load bean in application context"); + } + + /** + * @return Cache configuration with store. + */ + private CacheConfiguration<Integer, String> cacheConfiguration() { + CacheConfiguration<Integer, String> cfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME); + + CacheHibernateBlobStoreFactory<Integer, String> factory = new CacheHibernateBlobStoreFactory(); + + factory.setHibernateConfigurationPath("/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml"); + + cfg.setCacheStoreFactory(factory); + + return cfg; + } + + /** + * @param cache Ignite cache. + * @param dataSrcClass Data source class. + * @throws Exception If store parameters is not the same as in configuration xml. + */ + private void checkStore(IgniteCache<Integer, String> cache, Class<?> dataSrcClass) throws Exception { + CacheHibernateBlobStore store = (CacheHibernateBlobStore)cache + .getConfiguration(CacheConfiguration.class).getCacheStoreFactory().create(); + + assertEquals(dataSrcClass, + GridTestUtils.getFieldValue(store, CacheHibernateBlobStore.class, "sesFactory").getClass()); + } + + /** + * @param cache Ignite cache. + * @throws Exception If store parameters is not the same as in configuration xml. + */ + private void checkStore(IgniteCache<Integer, String> cache) throws Exception { + CacheHibernateBlobStore store = (CacheHibernateBlobStore)cache.getConfiguration(CacheConfiguration.class) + .getCacheStoreFactory().create(); + + assertEquals("/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml", + GridTestUtils.getFieldValue(store, CacheHibernateBlobStore.class, "hibernateCfgPath")); + } + + /** + * + */ + public static class DummySessionFactoryExt extends DummySessionFactory { + /** */ + public DummySessionFactoryExt() { + // No-op. + } + } + + /** + * + */ + public static class DummySessionFactory implements SessionFactory { + /** {@inheritDoc} */ + @Override public SessionFactoryOptions getSessionFactoryOptions() { + return null; + } + + /** {@inheritDoc} */ + @Override public SessionBuilder withOptions() { + return null; + } + + /** {@inheritDoc} */ + @Override public Session openSession() throws HibernateException { + return null; + } + + /** {@inheritDoc} */ + @Override public Session getCurrentSession() throws HibernateException { + return null; + } + + /** {@inheritDoc} */ + @Override public StatelessSessionBuilder withStatelessOptions() { + return null; + } + + /** {@inheritDoc} */ + @Override public StatelessSession openStatelessSession() { + return null; + } + + /** {@inheritDoc} */ + @Override public StatelessSession openStatelessSession(Connection conn) { + return null; + } + + /** {@inheritDoc} */ + @Override public ClassMetadata getClassMetadata(Class entityCls) { + return null; + } + + /** {@inheritDoc} */ + @Override public ClassMetadata getClassMetadata(String entityName) { + return null; + } + + /** {@inheritDoc} */ + @Override public CollectionMetadata getCollectionMetadata(String roleName) { + return null; + } + + /** {@inheritDoc} */ + @Override public Map<String, ClassMetadata> getAllClassMetadata() { + return null; + } + + /** {@inheritDoc} */ + @Override public Map getAllCollectionMetadata() { + return null; + } + + /** {@inheritDoc} */ + @Override public Statistics getStatistics() { + return null; + } + + /** {@inheritDoc} */ + @Override public void close() throws HibernateException { + } + + @Override + public Map<String, Object> getProperties() { + return null; + } + + /** {@inheritDoc} */ + @Override public boolean isClosed() { + return false; + } + + /** {@inheritDoc} */ + @Override public Cache getCache() { + return null; + } + + @Override + public PersistenceUnitUtil getPersistenceUnitUtil() { + return null; + } + + @Override + public void addNamedQuery(String name, Query query) { + + } + + @Override + public <T> T unwrap(Class<T> cls) { + return null; + } + + @Override + public <T> void addNamedEntityGraph(String graphName, EntityGraph<T> entityGraph) { + + } + + /** {@inheritDoc} */ + @Override public Set getDefinedFilterNames() { + return null; + } + + /** {@inheritDoc} */ + @Override public FilterDefinition getFilterDefinition(String filterName) throws HibernateException { + return null; + } + + /** {@inheritDoc} */ + @Override public boolean containsFetchProfileDefinition(String name) { + return false; + } + + /** {@inheritDoc} */ + @Override public TypeHelper getTypeHelper() { + return null; + } + + /** {@inheritDoc} */ + @Override public Reference getReference() throws NamingException { + return null; + } + + @Override + public <T> List<EntityGraph<? super T>> findEntityGraphsByType(Class<T> aClass) { + return null; + } + + @Override + public EntityManager createEntityManager() { + return null; + } + + @Override + public EntityManager createEntityManager(Map map) { + return null; + } + + @Override + public EntityManager createEntityManager(SynchronizationType synchronizationType) { + return null; + } + + @Override + public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map) { + return null; + } + + @Override + public CriteriaBuilder getCriteriaBuilder() { + return null; + } + + @Override + public Metamodel getMetamodel() { + return null; + } + + @Override + public boolean isOpen() { + return false; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreSessionListenerSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreSessionListenerSelfTest.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreSessionListenerSelfTest.java new file mode 100644 index 0000000..0010425 --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/CacheHibernateStoreSessionListenerSelfTest.java @@ -0,0 +1,242 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.cache.store.hibernate; + +import java.io.Serializable; +import java.util.Map; +import javax.cache.Cache; +import javax.cache.configuration.Factory; +import javax.cache.integration.CacheLoaderException; +import javax.cache.integration.CacheWriterException; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import org.apache.ignite.cache.store.CacheStore; +import org.apache.ignite.cache.store.CacheStoreAdapter; +import org.apache.ignite.cache.store.CacheStoreSession; +import org.apache.ignite.cache.store.CacheStoreSessionListener; +import org.apache.ignite.cache.store.CacheStoreSessionListenerAbstractSelfTest; +import org.apache.ignite.cache.store.jdbc.CacheJdbcStoreSessionListener; +import org.apache.ignite.lang.IgniteBiInClosure; +import org.apache.ignite.resources.CacheStoreSessionResource; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.resource.transaction.spi.TransactionStatus; + +/** + * Tests for {@link CacheJdbcStoreSessionListener}. + */ +public class CacheHibernateStoreSessionListenerSelfTest extends CacheStoreSessionListenerAbstractSelfTest { + /** {@inheritDoc} */ + @Override protected Factory<? extends CacheStore<Integer, Integer>> storeFactory() { + return new Factory<CacheStore<Integer, Integer>>() { + @Override public CacheStore<Integer, Integer> create() { + return new Store(); + } + }; + } + + /** {@inheritDoc} */ + @Override protected Factory<CacheStoreSessionListener> sessionListenerFactory() { + return new Factory<CacheStoreSessionListener>() { + @Override public CacheStoreSessionListener create() { + CacheHibernateStoreSessionListener lsnr = new CacheHibernateStoreSessionListener(); + + SessionFactory sesFactory = new Configuration(). + setProperty("hibernate.connection.url", URL). + addAnnotatedClass(Table1.class). + addAnnotatedClass(Table2.class). + buildSessionFactory(); + + lsnr.setSessionFactory(sesFactory); + + return lsnr; + } + }; + } + + /** + */ + private static class Store extends CacheStoreAdapter<Integer, Integer> { + /** */ + private static String SES_CONN_KEY = "ses_conn"; + + /** */ + @CacheStoreSessionResource + private CacheStoreSession ses; + + /** {@inheritDoc} */ + @Override public void loadCache(IgniteBiInClosure<Integer, Integer> clo, Object... args) { + loadCacheCnt.incrementAndGet(); + + checkSession(); + } + + /** {@inheritDoc} */ + @Override public Integer load(Integer key) throws CacheLoaderException { + loadCnt.incrementAndGet(); + + checkSession(); + + return null; + } + + /** {@inheritDoc} */ + @Override public void write(Cache.Entry<? extends Integer, ? extends Integer> entry) + throws CacheWriterException { + writeCnt.incrementAndGet(); + + checkSession(); + + if (write.get()) { + Session hibSes = ses.attachment(); + + switch (ses.cacheName()) { + case "cache1": + hibSes.save(new Table1(entry.getKey(), entry.getValue())); + + break; + + case "cache2": + if (fail.get()) + throw new CacheWriterException("Expected failure."); + + hibSes.save(new Table2(entry.getKey(), entry.getValue())); + + break; + + default: + throw new CacheWriterException("Wring cache: " + ses.cacheName()); + } + } + } + + /** {@inheritDoc} */ + @Override public void delete(Object key) throws CacheWriterException { + deleteCnt.incrementAndGet(); + + checkSession(); + } + + /** {@inheritDoc} */ + @Override public void sessionEnd(boolean commit) { + assertNull(ses.attachment()); + } + + /** + */ + private void checkSession() { + Session hibSes = ses.attachment(); + + assertNotNull(hibSes); + + assertTrue(hibSes.isOpen()); + + Transaction tx = hibSes.getTransaction(); + + assertNotNull(tx); + + if (ses.isWithinTransaction()) + assertEquals(TransactionStatus.ACTIVE, tx.getStatus()); + else + assertFalse("Unexpected status: " + tx.getStatus(), tx.getStatus() == TransactionStatus.ACTIVE); + + verifySameInstance(hibSes); + } + + /** + * @param hibSes Session. + */ + private void verifySameInstance(Session hibSes) { + Map<String, Session> props = ses.properties(); + + Session sesConn = props.get(SES_CONN_KEY); + + if (sesConn == null) + props.put(SES_CONN_KEY, hibSes); + else { + assertSame(hibSes, sesConn); + + reuseCnt.incrementAndGet(); + } + } + } + + /** + */ + @Entity + @Table(name = "Table1") + private static class Table1 implements Serializable { + /** */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + /** */ + @Column(name = "key") + private int key; + + /** */ + @Column(name = "value") + private int value; + + /** + * @param key Key. + * @param value Value. + */ + private Table1(int key, int value) { + this.key = key; + this.value = value; + } + } + + /** + */ + @Entity + @Table(name = "Table2") + private static class Table2 implements Serializable { + /** */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Integer id; + + /** */ + @Column(name = "key") + private int key; + + /** */ + @Column(name = "value") + private int value; + + /** + * @param key Key. + * @param value Value. + */ + private Table2(int key, int value) { + this.key = key; + this.value = value; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml new file mode 100644 index 0000000..6240599 --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + + +<!DOCTYPE hibernate-configuration PUBLIC + "-//Hibernate/Hibernate Configuration DTD 3.0//EN" + "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> + +<hibernate-configuration> + <session-factory> + <!-- Show SQL. --> + <property name="show_sql">true</property> + + <!-- Database connection settings (private in-memory database). --> + <property name="connection.url">jdbc:h2:mem:example;DB_CLOSE_DELAY=-1</property> + + <!-- Only validate the database schema on startup in production mode. --> + <property name="hbm2ddl.auto">update</property> + + <!-- H2 dialect. --> + <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property> + + <!-- Mappings. --> + <mapping resource="org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreEntry.hbm.xml"/> + </session-factory> +</hibernate-configuration> http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/package-info.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/package-info.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/package-info.java new file mode 100644 index 0000000..8af9886 --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/cache/store/hibernate/package-info.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * <!-- Package description. --> + * Contains internal tests or test related classes and interfaces. + */ +package org.apache.ignite.cache.store.hibernate; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate53TestSuite.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate53TestSuite.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate53TestSuite.java new file mode 100644 index 0000000..51842a8 --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteBinaryHibernate53TestSuite.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.testsuites; + +import junit.framework.TestSuite; +import org.apache.ignite.internal.binary.BinaryMarshaller; +import org.apache.ignite.testframework.config.GridTestProperties; + +/** + * + */ +public class IgniteBinaryHibernate53TestSuite extends TestSuite { + /** + * @return Test suite. + * @throws Exception If failed. + */ + public static TestSuite suite() throws Exception { + GridTestProperties.setProperty(GridTestProperties.MARSH_CLASS_NAME, BinaryMarshaller.class.getName()); + + return IgniteHibernate53TestSuite.suite(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteHibernate53TestSuite.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteHibernate53TestSuite.java b/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteHibernate53TestSuite.java new file mode 100644 index 0000000..794cffe --- /dev/null +++ b/modules/hibernate-5.3/src/test/java/org/apache/ignite/testsuites/IgniteHibernate53TestSuite.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.testsuites; + +import junit.framework.JUnit4TestAdapter; +import junit.framework.TestSuite; +import org.apache.ignite.cache.hibernate.HibernateL2CacheConfigurationSelfTest; +import org.apache.ignite.cache.hibernate.HibernateL2CacheMultiJvmTest; +import org.apache.ignite.cache.hibernate.HibernateL2CacheSelfTest; +import org.apache.ignite.cache.hibernate.HibernateL2CacheStrategySelfTest; +import org.apache.ignite.cache.hibernate.HibernateL2CacheTransactionalSelfTest; +import org.apache.ignite.cache.hibernate.HibernateL2CacheTransactionalUseSyncSelfTest; +import org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreNodeRestartTest; +import org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreSelfTest; +import org.apache.ignite.cache.store.hibernate.CacheHibernateStoreFactorySelfTest; +import org.apache.ignite.cache.store.hibernate.CacheHibernateStoreSessionListenerSelfTest; + +/** + * Hibernate integration tests. + */ +public class IgniteHibernate53TestSuite extends TestSuite { + /** + * @return Test suite. + */ + public static TestSuite suite() { + TestSuite suite = new TestSuite("Hibernate5 Integration Test Suite"); + + // Hibernate L2 cache. + suite.addTest(new JUnit4TestAdapter(HibernateL2CacheSelfTest.class)); + suite.addTest(new JUnit4TestAdapter(HibernateL2CacheTransactionalSelfTest.class)); + suite.addTest(new JUnit4TestAdapter(HibernateL2CacheTransactionalUseSyncSelfTest.class)); + suite.addTest(new JUnit4TestAdapter(HibernateL2CacheConfigurationSelfTest.class)); + suite.addTest(new JUnit4TestAdapter(HibernateL2CacheStrategySelfTest.class)); + suite.addTest(new JUnit4TestAdapter(HibernateL2CacheMultiJvmTest.class)); + + suite.addTest(new JUnit4TestAdapter(CacheHibernateBlobStoreSelfTest.class)); + + suite.addTest(new JUnit4TestAdapter(CacheHibernateBlobStoreNodeRestartTest.class)); + + suite.addTest(new JUnit4TestAdapter(CacheHibernateStoreSessionListenerSelfTest.class)); + + suite.addTest(new JUnit4TestAdapter(CacheHibernateStoreFactorySelfTest.class)); + + return suite; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-5.3/src/test/resources/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml ---------------------------------------------------------------------- diff --git a/modules/hibernate-5.3/src/test/resources/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml b/modules/hibernate-5.3/src/test/resources/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml new file mode 100644 index 0000000..6240599 --- /dev/null +++ b/modules/hibernate-5.3/src/test/resources/org/apache/ignite/cache/store/hibernate/hibernate.cfg.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + + +<!DOCTYPE hibernate-configuration PUBLIC + "-//Hibernate/Hibernate Configuration DTD 3.0//EN" + "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> + +<hibernate-configuration> + <session-factory> + <!-- Show SQL. --> + <property name="show_sql">true</property> + + <!-- Database connection settings (private in-memory database). --> + <property name="connection.url">jdbc:h2:mem:example;DB_CLOSE_DELAY=-1</property> + + <!-- Only validate the database schema on startup in production mode. --> + <property name="hbm2ddl.auto">update</property> + + <!-- H2 dialect. --> + <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property> + + <!-- Mappings. --> + <mapping resource="org/apache/ignite/cache/store/hibernate/CacheHibernateBlobStoreEntry.hbm.xml"/> + </session-factory> +</hibernate-configuration> http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyAdapter.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyAdapter.java b/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyAdapter.java index 557b018..44edf8e 100644 --- a/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyAdapter.java +++ b/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyAdapter.java @@ -100,7 +100,8 @@ public abstract class HibernateAccessStrategyAdapter { * @param cache Cache. * @param eConverter Exception converter. */ - protected HibernateAccessStrategyAdapter(Ignite ignite, + protected HibernateAccessStrategyAdapter( + Ignite ignite, HibernateCacheProxy cache, HibernateExceptionConverter eConverter) { this.cache = cache; @@ -124,7 +125,12 @@ public abstract class HibernateAccessStrategyAdapter { */ @Nullable public Object get(Object key) { try { - return cache.get(key); + Object val = cache.get(key); + + if (log.isDebugEnabled()) + log.debug("Get [cache=" + cache.name() + ", key=" + key + ", val=" + val + ']'); + + return val; } catch (IgniteCheckedException e) { throw convertException(e); @@ -147,6 +153,9 @@ public abstract class HibernateAccessStrategyAdapter { * @param val Value. */ public void putFromLoad(Object key, Object val) { + if (log.isDebugEnabled()) + log.debug("Put from load [cache=" + cache.name() + ", key=" + key + ", val=" + val + ']'); + try { cache.put(key, val); } @@ -225,6 +234,9 @@ public abstract class HibernateAccessStrategyAdapter { * Called to remove all data from cache without regard to transaction. */ public void evictAll() { + if (log.isDebugEnabled()) + log.debug("Evict all [cache=" + cache.name() + ']'); + try { evictAll(cache); } @@ -337,4 +349,4 @@ public abstract class HibernateAccessStrategyAdapter { cacheName = U.readString(in); } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/272858db/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyFactory.java ---------------------------------------------------------------------- diff --git a/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyFactory.java b/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyFactory.java index 0226c1c..c48d482 100644 --- a/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyFactory.java +++ b/modules/hibernate-core/src/main/java/org/apache/ignite/cache/hibernate/HibernateAccessStrategyFactory.java @@ -19,8 +19,9 @@ package org.apache.ignite.cache.hibernate; import java.util.HashMap; import java.util.Map; -import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; @@ -54,9 +55,6 @@ public class HibernateAccessStrategyFactory { /** Hibernate L2 cache Ignite instance name property name. */ public static final String IGNITE_INSTANCE_NAME_PROPERTY = "org.apache.ignite.hibernate.ignite_instance_name"; - /** Default cache property name. */ - public static final String DFLT_CACHE_NAME_PROPERTY = "org.apache.ignite.hibernate.default_cache"; - /** Property prefix used to specify region name to cache name mapping. */ public static final String REGION_CACHE_PROPERTY = "org.apache.ignite.hibernate.region_cache."; @@ -66,13 +64,16 @@ public class HibernateAccessStrategyFactory { /** */ public static final String GRID_CONFIG_PROPERTY = "org.apache.ignite.hibernate.grid_config"; + /** Disable atomicity check when caches are created lazily. */ + public static final String VERIFY_ATOMICITY = "org.apache.ignite.hibernate.verify_atomicity"; + + /** When set, all cache names in ignite will be fetched using the specified prefix. */ + public static final String CACHE_PREFIX = "org.apache.ignite.hibernate.cache_prefix"; + /** Grid providing caches. */ private Ignite ignite; - /** Default cache. */ - private HibernateCacheProxy dfltCache; - - /** Region name to cache name mapping. */ + /** Region name to cache name (without prefix) mapping. */ private final Map<String, String> regionCaches = new HashMap<>(); /** */ @@ -81,6 +82,12 @@ public class HibernateAccessStrategyFactory { /** */ private final ConcurrentHashMap<String, ThreadLocal> threadLocMap = new ConcurrentHashMap<>(); + /** */ + private String cachePrefix; + + /** */ + private boolean verifyAtomicity = true; + /** * @param keyTransformer Key transformer. * @param eConverter Exception converter. @@ -91,53 +98,45 @@ public class HibernateAccessStrategyFactory { } /** - * @param props Properties. + * @param cfgValues {@link Map} of config values. */ - public void start(Properties props) { - String gridCfg = props.getProperty(GRID_CONFIG_PROPERTY); - String igniteInstanceName = props.getProperty(IGNITE_INSTANCE_NAME_PROPERTY); + public void start(Map<Object, Object> cfgValues) { + cachePrefix = cfgValues.getOrDefault(CACHE_PREFIX, "").toString(); + + verifyAtomicity = Boolean.valueOf(cfgValues.getOrDefault(VERIFY_ATOMICITY, verifyAtomicity).toString()); - if (igniteInstanceName == null) - igniteInstanceName = props.getProperty(GRID_NAME_PROPERTY); + Object gridCfg = cfgValues.get(GRID_CONFIG_PROPERTY); + + Object igniteInstanceName = cfgValues.get(IGNITE_INSTANCE_NAME_PROPERTY); if (gridCfg != null) { try { - ignite = G.start(gridCfg); + ignite = G.start(gridCfg.toString()); } catch (IgniteException e) { throw eConverter.convert(e); } } else - ignite = Ignition.ignite(igniteInstanceName); + ignite = Ignition.ignite(igniteInstanceName == null ? null : igniteInstanceName.toString()); - for (Map.Entry<Object, Object> prop : props.entrySet()) { - String key = prop.getKey().toString(); + for (Map.Entry entry : cfgValues.entrySet()) { + String key = entry.getKey().toString(); if (key.startsWith(REGION_CACHE_PROPERTY)) { String regionName = key.substring(REGION_CACHE_PROPERTY.length()); - String cacheName = prop.getValue().toString(); + String cacheName = entry.getValue().toString(); - if (((IgniteKernal)ignite).getCache(cacheName) == null) + if (((IgniteKernal) ignite).getCache(cachePrefix + cacheName) == null) { throw new IllegalArgumentException("Cache '" + cacheName + "' specified for region '" + regionName + "' " + "is not configured."); + } regionCaches.put(regionName, cacheName); } } - String dfltCacheName = props.getProperty(DFLT_CACHE_NAME_PROPERTY); - - if (dfltCacheName != null) { - IgniteInternalCache<Object, Object> dfltCache = ((IgniteKernal)ignite).getCache(dfltCacheName); - - if (dfltCache == null) - throw new IllegalArgumentException("Cache specified as default is not configured: " + dfltCacheName); - - this.dfltCache = new HibernateCacheProxy(dfltCache, keyTransformer); - } - IgniteLogger log = ignite.log().getLogger(getClass()); if (log.isDebugEnabled()) @@ -158,19 +157,48 @@ public class HibernateAccessStrategyFactory { HibernateCacheProxy regionCache(String regionName) { String cacheName = regionCaches.get(regionName); - if (cacheName == null) { - if (dfltCache != null) - return dfltCache; - + if (cacheName == null) cacheName = regionName; + + cacheName = cachePrefix + cacheName; + + Supplier<IgniteInternalCache<Object, Object>> lazyCache = new LazyCacheSupplier(cacheName, regionName); + + return new HibernateCacheProxy(cacheName, lazyCache, keyTransformer); + } + + /** */ + private class LazyCacheSupplier implements Supplier<IgniteInternalCache<Object, Object>> { + /** */ + private final AtomicReference<IgniteInternalCache<Object, Object>> reference = new AtomicReference<>(); + + /** */ + private final String cacheName; + + /** */ + private final String regionName; + + /** */ + private LazyCacheSupplier(String cacheName, String regionName) { + this.cacheName = cacheName; + this.regionName = regionName; } - IgniteInternalCache<Object, Object> cache = ((IgniteKernal)ignite).getCache(cacheName); + /** {@inheritDoc} */ + @Override public IgniteInternalCache<Object, Object> get() { + IgniteInternalCache<Object, Object> cache = reference.get(); - if (cache == null) - throw new IllegalArgumentException("Cache '" + cacheName + "' for region '" + regionName + "' is not configured."); + if (cache == null) { + cache = ((IgniteKernal)ignite).getCache(cacheName); - return new HibernateCacheProxy(cache, keyTransformer); + if (cache == null) + throw new IllegalArgumentException("Cache '" + cacheName + "' for region '" + regionName + "' is not configured."); + + reference.compareAndSet(null, cache); + } + + return cache; + } } /** @@ -203,9 +231,12 @@ public class HibernateAccessStrategyFactory { * @return Access strategy implementation. */ HibernateAccessStrategyAdapter createReadWriteStrategy(HibernateCacheProxy cache) { - if (cache.configuration().getAtomicityMode() != TRANSACTIONAL) - throw new IllegalArgumentException("Hibernate READ-WRITE access strategy must have Ignite cache with " + - "'TRANSACTIONAL' atomicity mode: " + cache.name()); + if (verifyAtomicity) { + if (cache.configuration().getAtomicityMode() != TRANSACTIONAL) { + throw new IllegalArgumentException("Hibernate READ-WRITE access strategy must have Ignite cache with " + + "'TRANSACTIONAL' atomicity mode: " + cache.name()); + } + } return new HibernateReadWriteAccessStrategy(ignite, cache, threadLoc, eConverter); } @@ -215,19 +246,22 @@ public class HibernateAccessStrategyFactory { * @return Access strategy implementation. */ HibernateAccessStrategyAdapter createTransactionalStrategy(HibernateCacheProxy cache) { - if (cache.configuration().getAtomicityMode() != TRANSACTIONAL) - throw new IllegalArgumentException("Hibernate TRANSACTIONAL access strategy must have Ignite cache with " + - "'TRANSACTIONAL' atomicity mode: " + cache.name()); - - TransactionConfiguration txCfg = ignite.configuration().getTransactionConfiguration(); - - if (txCfg == null || - (txCfg.getTxManagerFactory() == null - && txCfg.getTxManagerLookupClassName() == null - && cache.configuration().getTransactionManagerLookupClassName() == null)) { - throw new IllegalArgumentException("Hibernate TRANSACTIONAL access strategy must have Ignite with " + - "Factory<TransactionManager> configured (see IgniteConfiguration." + - "getTransactionConfiguration().setTxManagerFactory()): " + cache.name()); + if (verifyAtomicity) { + if (cache.configuration().getAtomicityMode() != TRANSACTIONAL) { + throw new IllegalArgumentException("Hibernate TRANSACTIONAL access strategy must have Ignite cache with " + + "'TRANSACTIONAL' atomicity mode: " + cache.name()); + } + + TransactionConfiguration txCfg = ignite.configuration().getTransactionConfiguration(); + + if (txCfg == null || + (txCfg.getTxManagerFactory() == null + && txCfg.getTxManagerLookupClassName() == null + && cache.configuration().getTransactionManagerLookupClassName() == null)) { + throw new IllegalArgumentException("Hibernate TRANSACTIONAL access strategy must have Ignite with " + + "Factory<TransactionManager> configured (see IgniteConfiguration." + + "getTransactionConfiguration().setTxManagerFactory()): " + cache.name()); + } } return new HibernateTransactionalAccessStrategy(ignite, cache, eConverter);