GEODE-14: Add Hibernate module
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/0c89797b Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/0c89797b Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/0c89797b Branch: refs/heads/feature/GEODE-14 Commit: 0c89797b0c2a243a9a6f226e04b7b1f002df7191 Parents: b98a7ad Author: Jens Deppe <[email protected]> Authored: Mon Dec 28 06:57:06 2015 -0800 Committer: Jens Deppe <[email protected]> Committed: Mon Dec 28 06:57:06 2015 -0800 ---------------------------------------------------------------------- .../gemfire-modules-hibernate/build.gradle | 54 +++ extensions/gemfire-modules-hibernate/pom.xml | 109 +++++ .../gemfire/modules/hibernate/EnumType.java | 49 +++ .../gemfire/modules/hibernate/GemFireCache.java | 229 ++++++++++ .../modules/hibernate/GemFireCacheListener.java | 45 ++ .../modules/hibernate/GemFireCacheProvider.java | 191 +++++++++ .../hibernate/GemFireQueryCacheFactory.java | 30 ++ .../modules/hibernate/GemFireRegionFactory.java | 228 ++++++++++ .../modules/hibernate/internal/Access.java | 248 +++++++++++ .../ClientServerRegionFactoryDelegate.java | 199 +++++++++ .../hibernate/internal/CollectionAccess.java | 215 ++++++++++ .../hibernate/internal/EntityRegionWriter.java | 78 ++++ .../hibernate/internal/EntityVersion.java | 12 + .../hibernate/internal/EntityVersionImpl.java | 42 ++ .../hibernate/internal/EntityWrapper.java | 80 ++++ .../hibernate/internal/GemFireBaseRegion.java | 157 +++++++ .../internal/GemFireCollectionRegion.java | 50 +++ .../hibernate/internal/GemFireEntityRegion.java | 178 ++++++++ .../internal/GemFireQueryResultsRegion.java | 104 +++++ .../modules/hibernate/internal/KeyWrapper.java | 84 ++++ .../internal/NonStrictReadWriteAccess.java | 74 ++++ .../hibernate/internal/ReadOnlyAccess.java | 46 ++ .../hibernate/internal/ReadWriteAccess.java | 27 ++ .../internal/RegionFactoryDelegate.java | 144 +++++++ .../hibernate/internal/TransactionalAccess.java | 10 + .../src/test/hydra/hibe/Event.hbm.xml | 16 + .../src/test/hydra/hibe/Event.java | 58 +++ .../src/test/hydra/hibe/HibernateBB.java | 63 +++ .../src/test/hydra/hibe/HibernatePrms.java | 44 ++ .../src/test/hydra/hibe/HibernateTest.java | 418 +++++++++++++++++++ .../src/test/hydra/hibe/HibernateTest2.java | 155 +++++++ .../src/test/hydra/hibe/Person.hbm.xml | 21 + .../src/test/hydra/hibe/Person.java | 63 +++ .../src/test/hydra/hibe/hibe.bt | 33 ++ .../src/test/hydra/hibe/hibe.inc | 128 ++++++ .../src/test/hydra/hibe/hibe1.conf | 12 + .../src/test/hydra/hibe/hibernate.bt | 8 + .../src/test/hydra/readme.txt | 48 +++ .../com/gemstone/gemfire/modules/Event.java | 58 +++ .../gemfire/modules/HibernateJUnitTest.java | 401 ++++++++++++++++++ .../com/gemstone/gemfire/modules/Owner.java | 177 ++++++++ .../com/gemstone/gemfire/modules/Person.java | 63 +++ .../gemstone/gemfire/modules/SecondVMTest.java | 79 ++++ .../com/gemstone/gemfire/modules/Event.hbm.xml | 16 + .../com/gemstone/gemfire/modules/Person.hbm.xml | 20 + .../src/test/resources/log4j.properties | 16 + .../test/resources/tomcat/conf/tomcat-users.xml | 3 + extensions/gemfire-modules-tomcat7/build.gradle | 18 +- extensions/gemfire-modules/build.gradle | 5 + .../modules/session/TestSessionsBase.java | 4 +- modules/gemfire-modules-hibernate/build.gradle | 18 - modules/gemfire-modules-hibernate/pom.xml | 109 ----- .../gemfire/modules/hibernate/EnumType.java | 49 --- .../gemfire/modules/hibernate/GemFireCache.java | 229 ---------- .../modules/hibernate/GemFireCacheListener.java | 45 -- .../modules/hibernate/GemFireCacheProvider.java | 191 --------- .../hibernate/GemFireQueryCacheFactory.java | 30 -- .../modules/hibernate/GemFireRegionFactory.java | 228 ---------- .../modules/hibernate/internal/Access.java | 248 ----------- .../ClientServerRegionFactoryDelegate.java | 199 --------- .../hibernate/internal/CollectionAccess.java | 215 ---------- .../hibernate/internal/EntityRegionWriter.java | 78 ---- .../hibernate/internal/EntityVersion.java | 12 - .../hibernate/internal/EntityVersionImpl.java | 42 -- .../hibernate/internal/EntityWrapper.java | 80 ---- .../hibernate/internal/GemFireBaseRegion.java | 157 ------- .../internal/GemFireCollectionRegion.java | 50 --- .../hibernate/internal/GemFireEntityRegion.java | 178 -------- .../internal/GemFireQueryResultsRegion.java | 104 ----- .../modules/hibernate/internal/KeyWrapper.java | 84 ---- .../internal/NonStrictReadWriteAccess.java | 74 ---- .../hibernate/internal/ReadOnlyAccess.java | 46 -- .../hibernate/internal/ReadWriteAccess.java | 27 -- .../internal/RegionFactoryDelegate.java | 144 ------- .../hibernate/internal/TransactionalAccess.java | 10 - .../src/test/hydra/hibe/Event.hbm.xml | 16 - .../src/test/hydra/hibe/Event.java | 58 --- .../src/test/hydra/hibe/HibernateBB.java | 63 --- .../src/test/hydra/hibe/HibernatePrms.java | 44 -- .../src/test/hydra/hibe/HibernateTest.java | 418 ------------------- .../src/test/hydra/hibe/HibernateTest2.java | 155 ------- .../src/test/hydra/hibe/Person.hbm.xml | 21 - .../src/test/hydra/hibe/Person.java | 63 --- .../src/test/hydra/hibe/hibe.bt | 33 -- .../src/test/hydra/hibe/hibe.inc | 128 ------ .../src/test/hydra/hibe/hibe1.conf | 12 - .../src/test/hydra/hibe/hibernate.bt | 8 - .../src/test/hydra/readme.txt | 48 --- .../com/gemstone/gemfire/modules/Event.java | 58 --- .../gemfire/modules/HibernateTestCase.java | 390 ----------------- .../com/gemstone/gemfire/modules/Owner.java | 177 -------- .../com/gemstone/gemfire/modules/Person.java | 63 --- .../gemstone/gemfire/modules/SecondVMTest.java | 80 ---- .../com/gemstone/gemfire/modules/Event.hbm.xml | 16 - .../com/gemstone/gemfire/modules/Person.hbm.xml | 20 - .../src/test/resources/log4j.properties | 16 - .../tomcat/conf/tomcat-users.xml | 3 - settings.gradle | 1 + 98 files changed, 4608 insertions(+), 4540 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/build.gradle ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/build.gradle b/extensions/gemfire-modules-hibernate/build.gradle new file mode 100644 index 0000000..8361cee --- /dev/null +++ b/extensions/gemfire-modules-hibernate/build.gradle @@ -0,0 +1,54 @@ +/* + * 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. + */ + +test { + doFirst { + copy { + from 'build/resources/test/tomcat' + into 'build/test/tomcat/' + } + } + + testLogging { + events 'passed', 'skipped', 'failed' + exceptionFormat = 'full' + } + +// include '**/HibernateTestCase.class' +// include '**/SecondVMTest.class' +// +// testLogging { +// exceptionFormat = 'full' +// } +} + +dependencies { + compile project(':extensions/gemfire-modules') + compile 'org.hibernate:hibernate-core:3.5.0-Final' + compile 'org.hibernate:hibernate-annotations:3.5.5-Final' + compile 'javax.persistence:persistence-api:1.0.2' + + runtime 'dom4j:dom4j:1.6.1' +// runtime 'org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.0.Final' + + testRuntime 'org.hibernate:hibernate-annotations:3.5.5-Final' + testRuntime 'org.slf4j:slf4j-jdk14:1.7.7' + testRuntime 'org.hsqldb:hsqldb:2.0.0' + testRuntime 'org.javassist:javassist:3.13.0-GA' + + provided project(path: ':gemfire-junit', configuration: 'testOutput') +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/pom.xml ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/pom.xml b/extensions/gemfire-modules-hibernate/pom.xml new file mode 100644 index 0000000..19241b7 --- /dev/null +++ b/extensions/gemfire-modules-hibernate/pom.xml @@ -0,0 +1,109 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>com.gemstone</groupId> + <artifactId>gemfire-modules-hibernate</artifactId> + <version>${gemfire.modules.version}</version> + <packaging>jar</packaging> + + <name>gemfire-modules-hibernate</name> + <url>http://maven.apache.org</url> + + <parent> + <groupId>com.gemstone</groupId> + <artifactId>gemfire-modules-parent</artifactId> + <version>1.0-SNAPSHOT</version> + </parent> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>catalina</artifactId> + </dependency> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>catalina-ha</artifactId> + <version>${tomcat.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.gemstone.gemfire</groupId> + <artifactId>gemfire</artifactId> + </dependency> + <dependency> + <groupId>com.gemstone</groupId> + <artifactId>gemfire-modules</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-core</artifactId> + <version>3.5.0-Final</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.hsqldb</groupId> + <artifactId>hsqldb</artifactId> + <version>2.0.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.javassist</groupId> + <artifactId>javassist</artifactId> + <version>3.13.0-GA</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-jdk14</artifactId> + </dependency> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>coyote</artifactId> + </dependency> + <dependency> + <groupId>org.httpunit</groupId> + <artifactId>httpunit</artifactId> + </dependency> + <dependency> + <groupId>rhino</groupId> + <artifactId>js</artifactId> + </dependency> + <dependency> + <groupId>org.hibernate</groupId> + <artifactId>hibernate-annotations</artifactId> + <version>3.5.5-Final</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.7.2</version> + <configuration> + <includes> + <include>**/HibernateTestCase.java</include> + <include>**/SecondVMTest.java</include> + </includes> + <runOrder>alphabetical</runOrder> + </configuration> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/EnumType.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/EnumType.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/EnumType.java new file mode 100644 index 0000000..86153ed --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/EnumType.java @@ -0,0 +1,49 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate; + +import java.io.Serializable; + +import org.hibernate.HibernateException; + +/** + * Extends {@link org.hibernate.type.EnumType} so as to + * override methods responsible for cached representation + * of enums in hibernate. + * This class must be used in place of {@link org.hibernate.type.EnumType} + * in client-server topology when the application classes are + * not available on the server. + * e.g. a typical enum configuration should look like this: + * <pre> + * <property name="myEnum"> + * <type name="<b>com.gemstone.gemfire.modules.hibernate.EnumType</b>"> + * <param name="enumClass">com.mycompany.MyEntity$MyEnum</param> + * <param name="type">12</param> + * </type> + * </property> + * </pre> + * @author sbawaska + */ +public class EnumType extends org.hibernate.type.EnumType { + + private static final long serialVersionUID = 3414902482639744676L; + + @Override + public Object assemble(Serializable cached, Object owner) + throws HibernateException { + String name = (String) cached; + Class<? extends Enum> clazz = returnedClass(); + return Enum.valueOf(clazz, name); + } + + @Override + public Serializable disassemble(Object value) throws HibernateException { + return ((Enum)value).name(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCache.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCache.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCache.java new file mode 100644 index 0000000..119e137 --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCache.java @@ -0,0 +1,229 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate; + +import java.util.Map; + +import org.hibernate.cache.Cache; +import org.hibernate.cache.CacheException; +import org.hibernate.cache.Timestamper; + +import com.gemstone.gemfire.cache.EntryNotFoundException; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.Scope; +import com.gemstone.gemfire.distributed.DistributedLockService; +import com.gemstone.gemfire.internal.cache.LocalRegion; + +public class GemFireCache implements Cache { + private Region region; + + private boolean clientRegion = false; + + private final DistributedLockService distributedLockService; + + public GemFireCache(Region region, DistributedLockService lockService) { + this.region = region; + this.distributedLockService = lockService; + this.clientRegion = isClient(region); + } + + private boolean isClient(Region region) { + return region.getAttributes().getPoolName() != null; + } + + /** + * Clear the cache + */ + public void clear() throws CacheException { + GemFireCacheProvider.getLogger().info("GemFireCache: clear called"); + region.clear(); + } + + /** + * Clean up + */ + public void destroy() throws CacheException { + GemFireCacheProvider.getLogger().info("GemFireCache: destroy called"); + region.localDestroyRegion(); + } + + /** + * Get an item from the cache + * + * @param key + * @return the cached object or <tt>null</tt> + * @throws CacheException + */ + public Object get(Object key) throws CacheException { + GemFireCacheProvider.getLogger().debug( + "GemFireCache: get called for: " + key); + try { + Object value = region.get(key); + GemFireCacheProvider.getLogger().debug( + "GemFireCache: retrieved: " + key + "-->" + value); + return value; + } + catch (com.gemstone.gemfire.cache.CacheException e) { + throw new CacheException(e); + } + } + + /** + * The count of entries currently contained in the regions in-memory store. + * + * @return The count of entries in memory; -1 if unknown or unsupported. + */ + public long getElementCountInMemory() { + return ((LocalRegion)region).entryCount(); + } + + /** + * The count of entries currently contained in the regions disk store. + * + * @return The count of entries on disk; -1 if unknown or unsupported. + */ + public long getElementCountOnDisk() { + return -1; + } + + /** + * Get the name of the cache region + */ + public String getRegionName() { + return region.getName(); + } + + /** + * The number of bytes is this cache region currently consuming in memory. + * + * @return The number of bytes consumed by this region; -1 if unknown or + * unsupported. + */ + public long getSizeInMemory() { + return -1; + } + + /** + * Return the lock timeout for this cache. + */ + public int getTimeout() { + GemFireCacheProvider.getLogger().debug("GemFireCache: getTimeout"); + return Timestamper.ONE_MS * 60000; + } + + /** + * If this is a clustered cache, lock the item + */ + public void lock(Object key) throws CacheException { + GemFireCacheProvider.getLogger().info( + "GemFireCache: lock called for: " + key); + + if (!clientRegion) { + // If we're using GLOBAL scope, we don't have to worry about + // locking. + if (!Scope.GLOBAL.equals(region.getAttributes().getScope())) { + this.distributedLockService.lock(key, -1, -1); + } + } + else { + // We assume the server region is GLOBAL for now. Else, use command + // pattern to acquire lock on the server + GemFireCacheProvider.getLogger().info( + "GemFireCache: client region, ignoring lock : " + key); + } + } + + /** + * Generate the next timestamp + */ + public long nextTimestamp() { + GemFireCacheProvider.getLogger().debug("GemFireCache: nextTimestamp called"); + // TODO : Need a counter, cache-wide + return Timestamper.next(); + } + + /** + * Add an item to the cache + * + * @param key + * @param value + * @throws CacheException + */ + public void put(Object key, Object value) throws CacheException { + GemFireCacheProvider.getLogger().debug( + "GemFireCache: put called for key: " + key + "value: " + value); + try { + region.put(key, value); + GemFireCacheProvider.getLogger().debug( + "GemFireCache: put " + key + "-->" + value); + } + catch (com.gemstone.gemfire.cache.CacheException e) { + throw new CacheException(e); + } + } + + public Object read(Object key) throws CacheException { + GemFireCacheProvider.getLogger().info( + "GemFireCache: read called for: " + key); + return region.get(key); + } + + /** + * Remove an item from the cache + */ + public void remove(Object key) throws CacheException { + GemFireCacheProvider.getLogger().debug( + "GemFireCache: remove called for: " + key); + try { + region.destroy(key); + GemFireCacheProvider.getLogger().debug("GemFireCache: removed: " + key); + } + catch (EntryNotFoundException e) { + // We can silently ignore this + } + catch (com.gemstone.gemfire.cache.CacheException e) { + throw new CacheException(e); + } + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("Hibernate cache on GemFire region: "); + buffer.append(region); + return buffer.toString(); + } + + /** + * If this is a clustered cache, unlock the item + */ + public void unlock(Object key) throws CacheException { + GemFireCacheProvider.getLogger().info( + "GemFireCache: unlock called for: " + key); + + if (!clientRegion) { + // If we're using GLOBAL scope, we don't have to worry about locking. + if (!Scope.GLOBAL.equals(region.getAttributes().getScope())) { + this.distributedLockService.unlock(key); + } + } + else { + GemFireCacheProvider.getLogger().info( + "GemFireCache: client region, ignoring lock : " + key); + } + } + + public void update(Object key, Object value) throws CacheException { + GemFireCacheProvider.getLogger().info( + "GemFireCache: update called for: " + key); + this.region.put(key, value); + } + + public Map<?, ?> toMap() { + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheListener.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheListener.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheListener.java new file mode 100644 index 0000000..fb6db2d --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheListener.java @@ -0,0 +1,45 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate; + +import java.util.Properties; + +import com.gemstone.gemfire.cache.Declarable; +import com.gemstone.gemfire.cache.EntryEvent; +import com.gemstone.gemfire.cache.util.CacheListenerAdapter; + +public class GemFireCacheListener extends CacheListenerAdapter implements + Declarable { + + @Override + public void afterCreate(EntryEvent event) { + System.out.println("Create : " + event.getKey() + " / " + + event.getNewValue()); + } + + @Override + public void afterDestroy(EntryEvent event) { + System.out.println("Destroy : " + event.getKey()); + } + + @Override + public void afterInvalidate(EntryEvent event) { + System.out.println("Invalidate : " + event.getKey()); + } + + @Override + public void afterUpdate(EntryEvent event) { + System.out.println("Update : " + event.getKey() + " / " + + event.getNewValue()); + } + + public void init(Properties props) { + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheProvider.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheProvider.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheProvider.java new file mode 100644 index 0000000..9e38d7f --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheProvider.java @@ -0,0 +1,191 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate; + +import com.gemstone.gemfire.cache.CacheFactory; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.RegionShortcut; +import com.gemstone.gemfire.cache.execute.FunctionService; +import com.gemstone.gemfire.distributed.DistributedLockService; +import com.gemstone.gemfire.internal.logging.LogService; +import com.gemstone.gemfire.modules.util.CreateRegionFunction; +import com.gemstone.gemfire.modules.util.RegionConfiguration; +import org.apache.logging.log4j.Logger; +import org.hibernate.cache.Cache; +import org.hibernate.cache.CacheException; +import org.hibernate.cache.CacheProvider; +import org.hibernate.cache.Timestamper; + +import java.util.Iterator; +import java.util.Properties; + +@SuppressWarnings("deprecation") +public class GemFireCacheProvider implements CacheProvider { + + private static final Logger logger = LogService.getLogger(); + + protected com.gemstone.gemfire.cache.Cache _cache; + + private DistributedLockService distributedLockService; + + private Properties regionAttributes = new Properties(); + + private final String DEFAULT_REGION_TYPE = RegionShortcut.REPLICATE_HEAP_LRU + .name(); + + private final String HIBERNATE_DLOCK_SERVICE_NAME = "hibernate-cache-lock-service"; + /** + * Configure the cache + * + * @param regionName + * the name of the cache region + * @param properties + * configuration settings + * @throws CacheException + */ + public Cache buildCache(String regionName, Properties properties) + throws CacheException { + logger.info("GemFireCacheProvider: Creating cache: " + regionName); + Region region = retrieveOrCreateRegion(regionName); + Cache cache = null; + if (region == null) { + // Doh, blow up + throw new RuntimeException("Couldn't find cache region : " + regionName); + } + else { + cache = new GemFireCache(region, this.distributedLockService); + } + logger.info("GemFireCacheProvider: Created cache: " + regionName + "->" + cache); + return cache; + } + + public boolean isMinimalPutsEnabledByDefault() { + return false; + } + + /** + * Generate a timestamp + */ + public long nextTimestamp() { + return Timestamper.next(); + } + + /** + * Returns the region if already created, otherwise first tries to create it + * from cache.xml, if not specified in cache.xml, create the region from the + * properties specified in hibernate.cfg.xml. Two types of properties can be + * specified in hibernate.cfg.xml + * <ol> + * <li>gemfire.default-region-attributes-id: the default region type to + * create. (default value for this is REPLICATE) + * <li>gemfire.region-attributes-for:fullyQualifiedRegionName when a region + * wants to override the default region type + * </ol> + * + * @param regionName + * @return the region + */ + protected Region retrieveOrCreateRegion(String regionName) { + // TODO client regions + Region r = _cache.getRegion(regionName); + if (r == null) { + String regionType = getRegionType(regionName); + r = _cache.createRegionFactory(RegionShortcut.valueOf(regionType)) + .create(regionName); + RegionConfiguration regionConfig = new RegionConfiguration(); + regionConfig.setRegionName(regionName); + regionConfig.setRegionAttributesId(regionType); + FunctionService.onMembers(_cache.getDistributedSystem()) + .withArgs(regionConfig).execute(CreateRegionFunction.ID).getResult(); + } + return r; + } + + /** + * returns the type of region to create by consulting the properties specified + * in hibernate.cfg.xml + * + * @see #retrieveOrCreateRegion(String) + * @param regionName + * @return string representation of {@link RegionShortcut} + */ + private String getRegionType(String regionName) { + String rType = regionAttributes + .getProperty("gemfire.default-region-attributes-id"); + if (rType == null) { + rType = DEFAULT_REGION_TYPE; + } + // iterate to find overridden property for a region + Iterator<Object> it = regionAttributes.keySet().iterator(); + while (it.hasNext()) { + String current = (String)it.next(); + if (current.contains(regionName)) { + rType = regionAttributes.getProperty(current); + break; + } + } + return rType.toUpperCase(); + } + + /** + * Callback to perform any necessary initialization of the underlying cache + * implementation during SessionFactory construction. + * + * @param properties + * current configuration settings. + */ + public void start(Properties properties) throws CacheException { + logger.info("GemFireCacheProvider: Creating cache provider"); + + // We have to strip out any unknown properties, do so here + Properties gemfireOnlyProperties = new Properties(); + for (Object keyObj : properties.keySet()) { + String key = (String)keyObj; + if (key.contains("region-attributes")) { + regionAttributes.put(key, properties.get(key)); + } + else if (key.startsWith("gemfire.")) { + gemfireOnlyProperties.setProperty(key.replace("gemfire.", ""), + properties.getProperty(key)); + } + } + + // Create cache and d-lock service + try { + _cache = new CacheFactory(gemfireOnlyProperties).create(); + DistributedLockService existing = DistributedLockService.getServiceNamed(HIBERNATE_DLOCK_SERVICE_NAME); + if (existing == null) { + this.distributedLockService = DistributedLockService.create( + HIBERNATE_DLOCK_SERVICE_NAME, _cache.getDistributedSystem()); + } else { + this.distributedLockService = existing; + } + } + catch (com.gemstone.gemfire.cache.CacheException e) { + throw new CacheException(e); + } + + FunctionService.registerFunction(new CreateRegionFunction()); + + logger.info("GemFireCacheProvider: Done creating cache provider"); + } + + /** + * Callback to perform any necessary cleanup of the underlying cache + * implementation during SessionFactory.close(). + */ + public void stop() { + logger.info("GemFireCacheProvider: Stopping"); + _cache.close(); + logger.info("GemFireCacheProvider: Stopped"); + } + + public static Logger getLogger() { + return logger; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireQueryCacheFactory.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireQueryCacheFactory.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireQueryCacheFactory.java new file mode 100644 index 0000000..35a79ee --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireQueryCacheFactory.java @@ -0,0 +1,30 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate; + +import java.util.Properties; + +import org.hibernate.HibernateException; +import org.hibernate.cache.QueryCache; +import org.hibernate.cache.QueryCacheFactory; +import org.hibernate.cache.UpdateTimestampsCache; +import org.hibernate.cfg.Settings; + +/** + * Defines a factory for query cache instances. These factories are responsible + * for creating individual QueryCache instances. + * + */ +public class GemFireQueryCacheFactory implements QueryCacheFactory { + public QueryCache getQueryCache(String regionName, + UpdateTimestampsCache updateTimestampsCache, Settings settings, + Properties props) throws HibernateException { + return new org.hibernate.cache.StandardQueryCache(settings, props, + updateTimestampsCache, regionName); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireRegionFactory.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireRegionFactory.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireRegionFactory.java new file mode 100644 index 0000000..f2d1696 --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireRegionFactory.java @@ -0,0 +1,228 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate; + +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.hibernate.cache.CacheDataDescription; +import org.hibernate.cache.CacheException; +import org.hibernate.cache.CollectionRegion; +import org.hibernate.cache.EntityRegion; +import org.hibernate.cache.QueryResultsRegion; +import org.hibernate.cache.RegionFactory; +import org.hibernate.cache.Timestamper; +import org.hibernate.cache.TimestampsRegion; +import org.hibernate.cache.access.AccessType; +import org.hibernate.cfg.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.GemFireCache; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.RegionShortcut; +import com.gemstone.gemfire.cache.client.ClientCache; +import com.gemstone.gemfire.cache.client.ClientRegionShortcut; +import com.gemstone.gemfire.distributed.internal.DistributionConfig; +import com.gemstone.gemfire.distributed.internal.DistributionConfigImpl; +import com.gemstone.gemfire.modules.hibernate.internal.ClientServerRegionFactoryDelegate; +import com.gemstone.gemfire.modules.hibernate.internal.EntityWrapper; +import com.gemstone.gemfire.modules.hibernate.internal.GemFireCollectionRegion; +import com.gemstone.gemfire.modules.hibernate.internal.GemFireEntityRegion; +import com.gemstone.gemfire.modules.hibernate.internal.GemFireQueryResultsRegion; +import com.gemstone.gemfire.modules.hibernate.internal.RegionFactoryDelegate; +import com.gemstone.gemfire.modules.util.Banner; + +public class GemFireRegionFactory implements RegionFactory { + + + private static final String GEMFIRE_QUERY_RESULTS_REGION_NAME = "gemfire.hibernateQueryResults"; + + private static final String GEMFIRE_TIMESTAMPS_REGION_NAME = "gemfire.hibernateTimestamps"; + + private GemFireCache _cache; + + private RegionFactoryDelegate delegate; + + // TODO get rid of this + private boolean isClient; + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + + private Set<String> gemfireAttributes; + + /** + * maps the entity to the region that stores it. + */ + private ConcurrentMap<String, GemFireEntityRegion> entityRegionMap = new ConcurrentHashMap<String, GemFireEntityRegion>(); + + public GemFireRegionFactory(Properties props) { + log.debug("props:" + props); + } + + public ExecutorService getExecutorService() { + return this.executorService; + } + + @Override + public void start(Settings settings, Properties properties) + throws CacheException { + log.info("Initializing " + Banner.getString()); + extractGemFireProperties(properties); + _cache = delegate.startCache(); + } + + private void extractGemFireProperties(Properties properties) { + // We have to strip out any unknown properties, do so here + Properties gemfireProperties = new Properties(); + Properties regionProperties = new Properties(); + for (Object keyObj : properties.keySet()) { + String key = (String)keyObj; + if (key.contains("region-attributes")) { + regionProperties.put(key, properties.get(key)); + } + else if (key.equals("gemfire.cache-topology")) { + if (properties.getProperty(key).trim() + .equalsIgnoreCase("client-server")) { + isClient = true; + } + } + else if (key.startsWith("gemfire.") && isGemFireAttribute(key)) { + gemfireProperties.setProperty(key.replace("gemfire.", ""), + properties.getProperty(key)); + } + } + if (isClient) { + delegate = new ClientServerRegionFactoryDelegate(gemfireProperties, regionProperties); + } else { + delegate = new RegionFactoryDelegate(gemfireProperties, regionProperties); + } + } + + private boolean isGemFireAttribute(String key) { + String gfKey = key.replace("gemfire.", ""); + Set<String> gemfireAttributes = getGemFireAttributesNames(); + return gemfireAttributes.contains(gfKey); + } + + private Set<String> getGemFireAttributesNames() { + if (this.gemfireAttributes == null) { + //used only to get the list of all gemfire properties + DistributionConfig dConfig = new DistributionConfigImpl(new Properties()); + String[] gemfireAttributeNames = dConfig.getAttributeNames(); + gemfireAttributes = new HashSet<String>(); + for (String attrName : gemfireAttributeNames) { + gemfireAttributes.add(attrName); + } + } + return gemfireAttributes; + } + + @Override + public void stop() { + // we do not want to close the cache, as there may be other + // applications/webapps + // using this cache. TODO do we want to close the regions that are created + // by this application? + } + + @Override + public boolean isMinimalPutsEnabledByDefault() { + // minimal puts is better for clustered cache + return true; + } + + @Override + public AccessType getDefaultAccessType() { + return AccessType.NONSTRICT_READ_WRITE; + } + + @Override + public long nextTimestamp() { + log.debug("nextTimestamp called"); + // TODO use gemfire cache time here. (which tries to minimize clock skews) + return Timestamper.next(); + } + + @Override + public EntityRegion buildEntityRegion(String regionName, + Properties properties, CacheDataDescription metadata) + throws CacheException { + // create the backing region + log.debug("creating Entity region {} ", regionName); + Region<Object, EntityWrapper> region = delegate.createRegion(regionName); + GemFireEntityRegion r = new GemFireEntityRegion(region, isClient, metadata, this); + this.entityRegionMap.put(regionName, r); + return r; + } + + @Override + public CollectionRegion buildCollectionRegion(String regionName, + Properties properties, CacheDataDescription metadata) + throws CacheException { + log.debug("creating collection region {}",regionName); + Region<Object, EntityWrapper> region = delegate.createRegion(regionName); + return new GemFireCollectionRegion(region, isClient, metadata, this); + } + + @Override + public QueryResultsRegion buildQueryResultsRegion(String regionName, + Properties properties) throws CacheException { + log.debug("Creating a query results region"); + Region region = getLocalRegionForQueryCache(); + return new GemFireQueryResultsRegion(region); + } + + private Region getLocalRegionForQueryCache() { + return getLocalRegion(GEMFIRE_QUERY_RESULTS_REGION_NAME); + } + + private Region getLocalRegionForTimestampsCache() { + return getLocalRegion(GEMFIRE_TIMESTAMPS_REGION_NAME); + } + + private Region getLocalRegion(String regionName) { + Region region = _cache.getRegion(regionName); + if (region != null) { + return region; + } + if (isClient) { + ClientCache cc = (ClientCache)_cache; + region = cc.createClientRegionFactory(ClientRegionShortcut.LOCAL_HEAP_LRU).create(regionName); + } else { + Cache c = (Cache)_cache; + region = c.createRegionFactory(RegionShortcut.LOCAL_HEAP_LRU).create(regionName); + } + return region; + } + + @Override + public TimestampsRegion buildTimestampsRegion(String regionName, + Properties properties) throws CacheException { + Region region = getLocalRegionForTimestampsCache(); + return new GemFireQueryResultsRegion(region); + } + + /** + * Given an entity name, gets the region used to store + * that entity. + * @param name name of the entity + * @return the entity region for the given entity name + */ + public GemFireEntityRegion getEntityRegion(String name) { + return this.entityRegionMap.get(name); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/Access.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/Access.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/Access.java new file mode 100644 index 0000000..55abb6a --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/Access.java @@ -0,0 +1,248 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate.internal; + +import com.gemstone.gemfire.cache.CacheWriterException; +import com.gemstone.gemfire.cache.EntryExistsException; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.client.ServerOperationException; +import org.hibernate.cache.CacheException; +import org.hibernate.cache.EntityRegion; +import org.hibernate.cache.access.EntityRegionAccessStrategy; +import org.hibernate.cache.access.SoftLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +public abstract class Access implements EntityRegionAccessStrategy { + + private final GemFireEntityRegion region; + + /**Thread local to remember the status of insert, which can be returned in afterInsert*/ + private ThreadLocal<Map<Object, Boolean>> createStatus = new ThreadLocal<Map<Object, Boolean>>() { + @Override + protected Map<Object, Boolean> initialValue() { + return new HashMap<Object, Boolean>(); + } + }; + + private Logger log = LoggerFactory.getLogger(getClass()); + + public Access(GemFireEntityRegion region) { + this.region = region; + } + + @Override + public EntityRegion getRegion() { + return this.region; + } + + @Override + public Object get(Object key, long txTimestamp) throws CacheException { + KeyWrapper wKey = getWrappedKey(key); + if (this.region.isRegisterInterestRequired()) { + this.region.registerInterest(wKey); + } + // first check to see if we have pre-fetched this entity + EntityWrapper wrapper = this.region.get(wKey); + if (wrapper == null) { + wrapper = this.region.getGemFireRegion().get(wKey); + } + if (wrapper == null) { + this.region.getStats().incCacheMiss(); + log.debug("Cache miss for {} count: {}",wKey, this.region.getStats().getCacheMiss()); + return null; + } else { + this.region.getStats().incCacheHit(); + log.debug("cache hit {} count: {} ", wKey, this.region.getStats().getCacheHits()); + } + return wrapper.getEntity(); + } + + @Override + public boolean putFromLoad(Object key, Object value, long txTimestamp, + Object version) throws CacheException { + return putFromLoad(key, value, txTimestamp, version, true); + } + + @Override + public boolean putFromLoad(Object key, Object value, long txTimestamp, + Object version, boolean minimalPutOverride) throws CacheException { + return create(key, value); + } + + private boolean create(Object key, Object value) { + KeyWrapper wKey = getWrappedKey(key); + EntityWrapper wrapper = new EntityWrapper(value, 1L); + log.debug("putting a new entry from load {} value: {}",wKey, wrapper); + boolean remove = false; + try { + this.region.getGemFireRegion().create(wKey, wrapper); + } catch (EntryExistsException ee) { + log.debug("key {} exists in the cache already, destroying", wKey); + remove = true; + } catch (CacheWriterException writerEx) { + this.region.getStats().incHibernateDestroyJobsScheduled(); + log.debug("caught a CacheWriterException {} ",writerEx.getMessage()); + remove = true; + } catch (ServerOperationException serverEx) { + if (serverEx.getCause() instanceof CacheWriterException) { + this.region.getStats().incHibernateDestroyJobsScheduled(); + log.debug("caught a ServerOperationException caused by CacheWriterException {} ",serverEx.getMessage()); + } else { + throw serverEx; + } + remove = true; + } + if (remove) { + this.region.getGemFireRegion().remove(wKey); + return false; + } + return true; + } + + @Override + public SoftLock lockItem(Object key, Object version) throws CacheException { + KeyWrapper wKey = getWrappedKey(key); + EntityWrapper wrapper = this.region.getGemFireRegion().get(wKey); + Long ver = wrapper == null ? 0L : wrapper.getVersion(); + log.debug("lockItem:key: {} entityVersion: {}", new Object[] { wKey, ver }); + return new EntityVersionImpl(ver); + } + + @Override + public SoftLock lockRegion() throws CacheException { + return null; + } + + @Override + public void unlockItem(Object key, SoftLock lock) throws CacheException { + log.debug("unlockItem:key:" + key + " lock:" + lock); + } + + @Override + public void unlockRegion(SoftLock lock) throws CacheException { + } + + @Override + public boolean insert(Object key, Object value, Object version) + throws CacheException { + log.debug("insert:key:{} value:{} version:{}", + new Object[]{key, value, version}); + boolean retVal = create(key, value); + createStatus.get().put(key, retVal); + return retVal; + } + + @Override + public boolean afterInsert(Object key, Object value, Object version) + throws CacheException { + log.info("afterInsert:key:{} value:{} version:{}", + new Object[]{key, value, version}); + return createStatus.get().remove(key); + } + + @Override + public boolean update(Object key, Object value, Object currentVersion, + Object previousVersion) throws CacheException { + KeyWrapper wKey = getWrappedKey(key); + EntityWrapper oldWrapper = this.region.getGemFireRegion().get(wKey); + Long version = oldWrapper == null ? 1L : oldWrapper.getVersion() + 1; + EntityWrapper wrapper = new EntityWrapper(value, version); + log.debug("put:key:{} value:{} version:{}", new Object[] { wKey, value, + version }); + boolean remove = false; + try { + if (oldWrapper == null) { + remove = this.region.getGemFireRegion().putIfAbsent(wKey, wrapper) != null; + } else { + remove = !this.region.getGemFireRegion().replace(wKey, oldWrapper, wrapper); + } + } catch (CacheWriterException writerEx) { + this.region.getStats().incHibernateDestroyJobsScheduled(); + log.debug("caught a CacheWriterException {} ",writerEx.getMessage()); + remove = true; + } catch (ServerOperationException serverEx) { + if (serverEx.getCause() instanceof CacheWriterException) { + this.region.getStats().incHibernateDestroyJobsScheduled(); + log.debug("caught a ServerOperationException caused by CacheWriterException {} ",serverEx.getMessage()); + remove = true; + } else { + throw serverEx; + } + } + if (remove) { + this.region.getGemFireRegion().remove(wKey); + return false; + } + log.debug("put for key {} succeded", wKey); + return true; + } + + @Override + public boolean afterUpdate(Object key, Object value, Object currentVersion, + Object previousVersion, SoftLock lock) throws CacheException { + log.debug("afterUpdate:key:{} value:{} currVersion:{} previousVersion:{}", + new Object[] {key, value, currentVersion, previousVersion}); + KeyWrapper wKey = getWrappedKey(key); + EntityWrapper wrapper = this.region.getGemFireRegion().get(wKey); + if (wrapper == null) { + // this entry was destroyed during update + return false; + } + Long version = wrapper.getVersion(); + Long expectedVersion = ((EntityVersion)lock).getVersion() + 1; + log.debug("afterPut:key:{} value:{} version:{} expected: {}", + new Object[] { wKey, value, version, expectedVersion }); + if (wrapper.getVersion() != expectedVersion) { + log.debug( + "for key {} expected version to be {} but was {}, so destroying the key", + new Object[] { wKey, expectedVersion, version }); + this.region.getGemFireRegion().remove(wKey); + return false; + } + return true; + } + + @Override + public void remove(Object key) throws CacheException { + log.debug("removing key {} ",key); + this.region.getGemFireRegion().remove(getWrappedKey(key)); + } + + @Override + public void removeAll() throws CacheException { + log.debug("removing all keys"); + this.region.getGemFireRegion().clear(); + } + + @Override + public void evict(Object key) throws CacheException { + // TODO we should implement a method on Region to evict + // a particular entry, destroying is inefficient + log.debug("removing key {} ",key); + this.region.getGemFireRegion().remove(getWrappedKey(key)); + } + + @Override + public void evictAll() throws CacheException { + log.debug("removing all keys"); + this.region.getGemFireRegion().clear(); + } + + protected Region<Object, EntityWrapper> getGemFireRegion() { + return this.region.getGemFireRegion(); + } + + protected KeyWrapper getWrappedKey(Object key) { + return new KeyWrapper(key); + } +} + http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/ClientServerRegionFactoryDelegate.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/ClientServerRegionFactoryDelegate.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/ClientServerRegionFactoryDelegate.java new file mode 100644 index 0000000..c2fa3ba --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/ClientServerRegionFactoryDelegate.java @@ -0,0 +1,199 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate.internal; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.StringTokenizer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gemstone.gemfire.cache.GemFireCache; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.RegionShortcut; +import com.gemstone.gemfire.cache.client.ClientCache; +import com.gemstone.gemfire.cache.client.ClientCacheFactory; +import com.gemstone.gemfire.cache.client.ClientRegionFactory; +import com.gemstone.gemfire.cache.client.ClientRegionShortcut; +import com.gemstone.gemfire.cache.execute.FunctionService; +import com.gemstone.gemfire.modules.util.BootstrappingFunction; +import com.gemstone.gemfire.modules.util.CreateRegionFunction; +import com.gemstone.gemfire.modules.util.RegionConfiguration; + +public class ClientServerRegionFactoryDelegate extends RegionFactoryDelegate { + + private static final String DEFAULT_SERVER_REGION_TYPE = RegionShortcut.PARTITION.name(); + + private static final String DEFAULT_CLIENT_REGION_TYPE = ClientRegionShortcut.PROXY.name(); + + private ClientCache clientCache; + + public ClientServerRegionFactoryDelegate(Properties gemfireProperties, + Properties regionProperties) { + super(gemfireProperties, regionProperties); + } + + @Override + public GemFireCache startCache() { + log.info("Creating a GemFire client cache"); + String locatorsString = (String)gemfireProperties.remove("locators"); + checkExistingCache(); + ClientCacheFactory ccf = new ClientCacheFactory(gemfireProperties).setPoolSubscriptionEnabled(true); + List<LocatorHolder> locators = getLocatorsMap(locatorsString); + for (LocatorHolder locHolder : locators) { + log.debug("adding pool locator with host {} port {}", locHolder.host, locHolder.port); + ccf.addPoolLocator(locHolder.host, locHolder.port); + } + this.clientCache = ccf.create(); + + log.debug("GemFire client cache creation completed"); + // bootstrap the servers + FunctionService.onServers(this.clientCache).execute(new BootstrappingFunction()).getResult(); + FunctionService.registerFunction(new CreateRegionFunction(this.clientCache)); + return this.clientCache; + } + + private List<LocatorHolder> getLocatorsMap(String locatorsString) { + List<LocatorHolder> retval = new ArrayList<LocatorHolder>(); + if (locatorsString == null || locatorsString.isEmpty()) { + return retval; + } + StringTokenizer st = new StringTokenizer(locatorsString, ","); + while (st.hasMoreTokens()) { + String locator = st.nextToken(); + int portIndex = locator.indexOf('['); + if (portIndex < 1) { + portIndex = locator.lastIndexOf(':'); + } + // starting in 5.1.0.4 we allow '@' as the bind-addr separator + // to let people use IPv6 numeric addresses (which contain colons) + int bindAddrIdx = locator.lastIndexOf('@', portIndex - 1); + + if (bindAddrIdx < 0) { + bindAddrIdx = locator.lastIndexOf(':', portIndex - 1); + } + + String host = locator.substring(0, + bindAddrIdx > -1 ? bindAddrIdx : portIndex); + + if (host.indexOf(':') >= 0) { + bindAddrIdx = locator.lastIndexOf('@'); + host = locator.substring(0, bindAddrIdx > -1 ? bindAddrIdx : portIndex); + } + int lastIndex = locator.lastIndexOf(']'); + if (lastIndex == -1) { + if (locator.indexOf('[') >= 0) { + throw new IllegalArgumentException("Invalid locator"); + } else { + // Using host:port syntax + lastIndex = locator.length(); + } + } + String port = locator.substring(portIndex + 1, lastIndex); + int portVal = 0; + try { + portVal = Integer.parseInt(port); + if (portVal < 1 || portVal > 65535) { + throw new IllegalArgumentException("port should be grater than zero and less than 65536"); + } + } catch (NumberFormatException ex) { + throw new IllegalArgumentException("Invalid Locator"); + } + retval.add(new LocatorHolder(host, portVal)); + } + return retval; + } + + @Override + public Region<Object, EntityWrapper> createRegion(String regionName) { + // first create the region on the server + String serverRegionType = getServerRegionType(regionName); + RegionConfiguration regionConfig = new RegionConfiguration(); + regionConfig.setRegionName(regionName); + regionConfig.setRegionAttributesId(serverRegionType); + regionConfig.setCacheWriterName(EntityRegionWriter.class.getCanonicalName()); + FunctionService.onServer(this.clientCache).withArgs(regionConfig) + .execute(CreateRegionFunction.ID).getResult(); + // now create region on the client + Region<Object, EntityWrapper> r = this.clientCache.getRegion(regionName); + if (r != null) { + return r; + } + String clientRegionType = getClientRegionType(regionName); + ClientRegionFactory<Object, EntityWrapper> rf = this.clientCache + .createClientRegionFactory(ClientRegionShortcut + .valueOf(clientRegionType)); + r = rf.create(regionName); + return r; + } + + private String getClientRegionType(String regionName) { + String rType = getOverridenClientRegionType(regionName); + if (rType != null) { + return rType.toUpperCase(); + } + rType = regionProperties.getProperty("gemfire.default-client-region-attributes-id"); + if (rType == null) { + rType = DEFAULT_CLIENT_REGION_TYPE; + } + return rType.toUpperCase(); + } + + private String getServerRegionType(String regionName) { + String rType = getOverridenServerRegionType(regionName); + if (rType != null) { + return rType.toUpperCase(); + } + rType = regionProperties.getProperty("gemfire.default-region-attributes-id"); + if (rType == null) { + rType = DEFAULT_SERVER_REGION_TYPE; + } + return rType.toUpperCase(); + } + + private String getOverridenServerRegionType(String regionName) { + String rType = null; + Iterator<Object> it = regionProperties.keySet().iterator(); + while (it.hasNext()) { + String current = (String)it.next(); + if (current.contains(regionName) && !current.contains("client")) { + rType = regionProperties.getProperty(current); + break; + } + } + return rType; + } + + private String getOverridenClientRegionType(String regionName) { + String rType = null; + Iterator<Object> it = regionProperties.keySet().iterator(); + while (it.hasNext()) { + String current = (String)it.next(); + if (current.contains(regionName) && current.contains("client")) { + rType = regionProperties.getProperty(current); + break; + } + } + return rType; + } + + private static class LocatorHolder { + private String host; + private int port; + private LocatorHolder(String host, int port) { + this.host = host; + this.port = port; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/CollectionAccess.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/CollectionAccess.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/CollectionAccess.java new file mode 100644 index 0000000..c48a042 --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/CollectionAccess.java @@ -0,0 +1,215 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate.internal; + +import java.io.Serializable; +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Set; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.CollectionRegion; +import org.hibernate.cache.access.CollectionRegionAccessStrategy; +import org.hibernate.cache.access.SoftLock; +import org.hibernate.cache.entry.CollectionCacheEntry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gemstone.gemfire.cache.CacheWriterException; +import com.gemstone.gemfire.cache.EntryExistsException; +import com.gemstone.gemfire.cache.EntryNotFoundException; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.client.ServerOperationException; + +public class CollectionAccess implements + CollectionRegionAccessStrategy { + + private final GemFireCollectionRegion region; + + private Logger log = LoggerFactory.getLogger(getClass()); + + /** + * if we know the entity whose ids are stored in this + * collection, we can prefetch those entities using + * getAll. This field stores that child entity name. + */ + private String childEntityName; + + public CollectionAccess(GemFireCollectionRegion region) { + this.region = region; + String regionName = this.region.getGemFireRegion().getName().trim(); + regionName = regionName.replace("\\/", ""); + int lastPeriod = regionName.lastIndexOf('.'); + if (lastPeriod < 0) { + log.info("Eager prefetching disabled for region: {}", this.region.getName()); + return; + } + String entityName = regionName.substring(0, lastPeriod); + String collectionFieldName = regionName.substring(lastPeriod+1); + log.debug("entity name: {}, collectionFieldName: {}", entityName, collectionFieldName); + try { + Class parentClass = Class.forName(entityName); + Field[] fields = parentClass.getDeclaredFields(); + for (Field field : fields) { + log.debug("genericType: {}", field.getGenericType()); + if (field.getName().equals(collectionFieldName)) { + String genericString = field.toGenericString(); + log.debug("genericType: for required field name: {}", field.toGenericString()); + int startDependentEntityIndex = genericString.indexOf("<"); + if (startDependentEntityIndex != -1 && + genericString.indexOf("<", startDependentEntityIndex+1) == -1) { + int childDependentEntityIndex = genericString.indexOf(">"); + this.childEntityName = genericString.substring(startDependentEntityIndex+1, childDependentEntityIndex); + log.debug("For Collection {} using child entity: {}", this.region.getGemFireRegion().getName(), this.childEntityName); + } + } + } + } + catch (ClassNotFoundException e) { + //ok to ignore, we will not use pre-fetching + } + if (this.childEntityName == null) { + log.info("Eager prefetching disabled for region: {}", this.region.getName()); + } + } + + @Override + public CollectionRegion getRegion() { + return this.region; + } + + @Override + public Object get(Object key, long txTimestamp) throws CacheException { + EntityWrapper wrapper = this.region.getGemFireRegion().get(key); + if (wrapper == null) { + this.region.getStats().incCacheMiss(); + log.debug("Cache miss for {} ts: {}",key, txTimestamp); + return null; + } else { + this.region.getStats().incCacheHit(); + log.debug("cache hit {} count: {} ", key, this.region.getStats().getCacheHits()); + // do pre-fetching + if (isPrefetchPossible()) { + log.debug("for key: {} prefetching entries: {}", key, wrapper.getEntity()); + prefetchKeys((CollectionCacheEntry)wrapper.getEntity()); + } + } + return wrapper.getEntity(); + } + + private void prefetchKeys(CollectionCacheEntry entry) { + StringBuilder builder = new StringBuilder(this.childEntityName+"#"); + Serializable[] childEntityKeys = entry.getState(); + Set<String> getAllSet = new HashSet<String>(); + for (Serializable id : childEntityKeys) { + String key = builder.append(id).toString(); + log.debug("adding key {} to getAll set", key); + getAllSet.add(key); + } + GemFireEntityRegion childRegion = this.region.regionFactory.getEntityRegion(this.childEntityName); + log.debug("prefetching {} keys", getAllSet.size()); + if (!getAllSet.isEmpty() && childRegion != null) { + childRegion.getAll(getAllSet); + } + } + + private boolean isPrefetchPossible() { + return this.childEntityName != null; + } + + private void printRegionContents(Region<Object, EntityWrapper> r) { + log.debug("printing contents of {} ",r); + for (Object k : r.keySet()) { + log.debug("key {} value {} ",k,r.get(k)); + } + } + + @Override + public boolean putFromLoad(Object key, Object value, long txTimestamp, + Object version) throws CacheException { + return putFromLoad(key, value, txTimestamp, version, true); + } + + @Override + public boolean putFromLoad(Object key, Object value, long txTimestamp, + Object version, boolean minimalPutOverride) throws CacheException { + EntityWrapper wrapper = new EntityWrapper(value, 1L); + log.debug("putting a new collection entry from load {} value: {}",key, wrapper); + boolean remove = false; + try { + this.region.getGemFireRegion().create(key, wrapper); + } catch (EntryExistsException ee) { + log.debug("key {} exists in the cache already, destroying", key); + remove = true; + } catch (CacheWriterException writerEx) { + this.region.getStats().incHibernateDestroyJobsScheduled(); + log.debug("caught a CacheWriterException {} ",writerEx.getMessage()); + remove = true; + } catch (ServerOperationException serverEx) { + if (serverEx.getCause() instanceof CacheWriterException) { + this.region.getStats().incHibernateDestroyJobsScheduled(); + log.debug("caught a ServerOperationException caused by CacheWriterException {} ",serverEx.getMessage()); + } else { + throw serverEx; + } + remove = true; + } + if (remove) { + this.region.getGemFireRegion().remove(key); + return false; + } + return true; + } + + @Override + public SoftLock lockItem(Object key, Object version) throws CacheException { + // there are no updates to the collectionCache, + // so no need to lock/version + return null; + } + + @Override + public SoftLock lockRegion() throws CacheException { + return null; + } + + @Override + public void unlockItem(Object key, SoftLock lock) throws CacheException { + } + + @Override + public void unlockRegion(SoftLock lock) throws CacheException { + } + + @Override + public void remove(Object key) throws CacheException { + log.debug("removing key {}",key); + this.region.getGemFireRegion().remove(key); + } + + @Override + public void removeAll() throws CacheException { + log.debug("removing all keys"); + this.region.getGemFireRegion().clear(); + } + + @Override + public void evict(Object key) throws CacheException { + // TODO we should implement a method on Region to evict + // a particular entry, destroying is inefficient + log.debug("removing key {}", key); + this.region.getGemFireRegion().remove(key); + } + + @Override + public void evictAll() throws CacheException { + log.debug("removing all keys"); + this.region.getGemFireRegion().clear(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityRegionWriter.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityRegionWriter.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityRegionWriter.java new file mode 100644 index 0000000..bebe4cc --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityRegionWriter.java @@ -0,0 +1,78 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate.internal; + + +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gemstone.gemfire.cache.CacheWriterException; +import com.gemstone.gemfire.cache.Declarable; +import com.gemstone.gemfire.cache.EntryEvent; +import com.gemstone.gemfire.cache.util.CacheWriterAdapter; + +public class EntityRegionWriter extends CacheWriterAdapter implements Declarable { + + private Logger log = LoggerFactory.getLogger(getClass()); + +// @Override +// public void beforeCreate(EntryEvent event) { +// event.getRegion().getCache().getLogger().info("GFE:Writer invoked for beforeCreate:"+event); +// final Object key = event.getKey(); +// EntityWrapper val = (EntityWrapper)event.getNewValue(); +// EntityWrapper oldVal = (EntityWrapper)event.getOldValue(); +// log.debug("beforeCreate: key:"+key+" val:"+val.getEntity()+" ver:"+val.getVersion()+" region:"+event.getRegion().getName()+" oldVal:"+oldVal+" this:"+System.identityHashCode(this)); +// } + + @Override + public void beforeUpdate(EntryEvent event) { + log.debug("Writer invoked for beforeUpdate:{}",event); + final Object key = event.getKey(); + EntityWrapper val = (EntityWrapper)event.getNewValue(); + if (val.getVersion() < 0) { + // no need for version check for NonStrictReadWrite + // this is needed because CacheEntry does not implement equals + return; + } + EntityWrapper oldVal = (EntityWrapper)event.getOldValue(); + // if same entity was loaded from two different VMs, + // i.e. version same and entity equal then no need to destroy + // + if (oldVal.getVersion() == val.getVersion()) { + if (val.getEntity().equals(oldVal.getEntity())) { + // since CacheEntry does not override equals + // this check is probably of no use + return; + } + } else if (oldVal.getVersion() < val.getVersion()) { + return; + } + log.debug("For key {} old version was {} new version was {}", new Object[] {key, oldVal.getVersion(), val.getVersion()}); + throw new CacheWriterException("key "+key+" had a newer version"); + } + + @Override + public boolean equals(Object obj) { + // This method is only implemented so that RegionCreator.validateRegion works properly. + // The CacheWriter comparison fails because two of these instances are not equal. + if (this == obj) { + return true; + } + + if (obj == null || !(obj instanceof EntityRegionWriter)) { + return false; + } + return true; + } + + @Override + public void init(Properties arg0) { + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersion.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersion.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersion.java new file mode 100644 index 0000000..d805852 --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersion.java @@ -0,0 +1,12 @@ +package com.gemstone.gemfire.modules.hibernate.internal; + +import org.hibernate.cache.access.SoftLock; + +/** + * + * @author sbawaska + */ +public interface EntityVersion extends SoftLock { + + public Long getVersion(); +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersionImpl.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersionImpl.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersionImpl.java new file mode 100644 index 0000000..7a04e3f --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersionImpl.java @@ -0,0 +1,42 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate.internal; + +/** + * + * @author sbawaska + */ +public class EntityVersionImpl implements EntityVersion { + + private final Long version; + + public EntityVersionImpl(Long version) { + this.version = version; + } + + @Override + public Long getVersion() { + return this.version; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof EntityVersionImpl) { + EntityVersionImpl other = (EntityVersionImpl)obj; + if (this.version.equals(other.version)) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return this.version.hashCode(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityWrapper.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityWrapper.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityWrapper.java new file mode 100644 index 0000000..9535f7e --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityWrapper.java @@ -0,0 +1,80 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate.internal; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import com.gemstone.gemfire.DataSerializable; +import com.gemstone.gemfire.DataSerializer; + +public class EntityWrapper implements DataSerializable { + + private static final long serialVersionUID = 8616754027252339041L; + + private Object entity; + + private long version; + + public EntityWrapper(Object entity, long version) { + this.entity = entity; + this.version = version; + } + + /** + * for {@link DataSerializer} + */ + public EntityWrapper() { + } + + public long getVersion() { + return version; + } + + public Object getEntity() { + return entity; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof EntityWrapper) { + EntityWrapper other = (EntityWrapper)obj; + if (this.version == other.version) { + //CacheEntry does not override equals, hence cannot be used in this comparison + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return Long.valueOf(this.version).hashCode(); + } + + @Override + public String toString() { + return new StringBuilder() + .append("EntityWrapper@" + System.identityHashCode(this)) + .append(" Entity:" + this.entity).append(" version:" + this.version) + .toString(); + } + + @Override + public void toData(DataOutput out) throws IOException { + out.writeLong(this.version); + DataSerializer.writeObject(this.entity, out); + } + + @Override + public void fromData(DataInput in) throws IOException, ClassNotFoundException { + this.version = in.readLong(); + this.entity = DataSerializer.readObject(in); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/GemFireBaseRegion.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/GemFireBaseRegion.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/GemFireBaseRegion.java new file mode 100644 index 0000000..63db2d6 --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/GemFireBaseRegion.java @@ -0,0 +1,157 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate.internal; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; + +import org.hibernate.cache.CacheDataDescription; +import org.hibernate.cache.CacheException; +import org.hibernate.cache.Region; +import org.hibernate.cache.Timestamper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gemstone.gemfire.distributed.DistributedSystem; +import com.gemstone.gemfire.internal.cache.LocalRegion; +import com.gemstone.gemfire.modules.hibernate.GemFireRegionFactory; +import com.gemstone.gemfire.modules.util.ModuleStatistics; + +public class GemFireBaseRegion implements Region { + + /** + * the backing region + */ + protected final com.gemstone.gemfire.cache.Region<Object, EntityWrapper> region; + + /** + * to determine if the operation should be forwarded to server + */ + protected final boolean isClientRegion; + + protected final CacheDataDescription metadata; + + private final Logger log = LoggerFactory.getLogger(getClass()); + + protected final GemFireRegionFactory regionFactory; + + protected final ModuleStatistics stats; + + public GemFireBaseRegion(com.gemstone.gemfire.cache.Region<Object, EntityWrapper> region, + boolean isClient, CacheDataDescription metadata, GemFireRegionFactory regionFactory) { + this.region = region; + this.isClientRegion = isClient; + this.metadata = metadata; + this.regionFactory = regionFactory; + DistributedSystem system = ((LocalRegion)region).getSystem(); + this.stats = ModuleStatistics.getInstance(system); + + } + + public com.gemstone.gemfire.cache.Region<Object, EntityWrapper> getGemFireRegion() { + return this.region; + } + + public ModuleStatistics getStats() { + return this.stats; + } + + public ExecutorService getExecutorService() { + return this.regionFactory.getExecutorService(); + } + + @Override + public String getName() { + return this.region.getName(); + } + + @Override + public void destroy() throws CacheException { + if (!this.region.isDestroyed()) { + this.region.localDestroyRegion(); + } + } + + /* + * I did not see any useful callers from hibernate-core + */ + @Override + public boolean contains(Object key) { + log.debug("contains key called for :" + key); + if (isClientRegion) { + // TODO should this be done? + return this.region.containsKeyOnServer(key); + } + return this.region.containsKey(key); + } + + @Override + public long getSizeInMemory() { + return 0; + } + + @Override + public long getElementCountInMemory() { + return this.region.size(); + } + + @Override + public long getElementCountOnDisk() { + LocalRegion lr = (LocalRegion)this.region; + if (lr.getDiskRegion() != null) { + return lr.getDiskRegion().getNumOverflowOnDisk(); + } + return 0; + } + + @Override + public Map<Object, EntityWrapper> toMap() { + return Collections.unmodifiableMap(this.region); + } + + /* + * only used by updateTimestamps cache + */ + @Override + public long nextTimestamp() { + log.debug("nextTimestamp called"); + return Timestamper.next(); + } + + /* + * this is used by updateTimestamps cache only + */ + @Override + public int getTimeout() { + return 60*1000; // all other cache providers have same value + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof GemFireBaseRegion) { + GemFireBaseRegion other = (GemFireBaseRegion)obj; + if (this.region.getName().equals(other.region.getName()) + && this.isClientRegion == other.isClientRegion) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return this.region.hashCode() + (this.isClientRegion ? 1 : 0); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/0c89797b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/GemFireCollectionRegion.java ---------------------------------------------------------------------- diff --git a/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/GemFireCollectionRegion.java b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/GemFireCollectionRegion.java new file mode 100644 index 0000000..b6a6bc4 --- /dev/null +++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/GemFireCollectionRegion.java @@ -0,0 +1,50 @@ +/*========================================================================= + * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved. + * This product is protected by U.S. and international copyright + * and intellectual property laws. Pivotal products are covered by + * one or more patents listed at http://www.pivotal.io/patents. + *========================================================================= + */ +package com.gemstone.gemfire.modules.hibernate.internal; + +import org.hibernate.cache.CacheDataDescription; +import org.hibernate.cache.CacheException; +import org.hibernate.cache.CollectionRegion; +import org.hibernate.cache.access.AccessType; +import org.hibernate.cache.access.CollectionRegionAccessStrategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.modules.hibernate.GemFireRegionFactory; + +public class GemFireCollectionRegion extends GemFireBaseRegion implements CollectionRegion { + + private Logger log = LoggerFactory.getLogger(getClass()); + + public GemFireCollectionRegion(Region<Object, EntityWrapper> region, + boolean isClient, CacheDataDescription metadata, + GemFireRegionFactory regionFactory) { + super(region, isClient, metadata, regionFactory); + } + + @Override + public boolean isTransactionAware() { + // TODO Auto-generated method stub + return false; + } + + @Override + public CacheDataDescription getCacheDataDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + public CollectionRegionAccessStrategy buildAccessStrategy( + AccessType accessType) throws CacheException { + log.debug("creating collection access for region:"+this.region.getName()); + return new CollectionAccess(this); + } + +}
