You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by je...@apache.org on 2016/02/08 17:51:58 UTC
[10/32] incubator-geode git commit: GEODE-14: Integration of GemFire
Session Replication and Hibernate modules
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/configuration-prompts.properties
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/configuration-prompts.properties b/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/configuration-prompts.properties
new file mode 100644
index 0000000..f109d82
--- /dev/null
+++ b/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/configuration-prompts.properties
@@ -0,0 +1,21 @@
+cache.configuration.file=Please enter the name of the GemFire cache configuration file. Default '${default}':
+critical.heap.percentage=Please enter the percentage of heap at which updates to the cache are refused. 0.0 means disabled. Default '${default}':
+enable.debug.listener=Please specify whether to enable a GemFire listener that logs session create, update, destroy and expiration events. Default '${default}':
+enable.gateway.replication=Please specify whether session modifications should be replicated across the WAN. Default '${default}':
+enable.local.cache=Please specify whether to maintain a local GemFire cache. Default '${default}':
+enable.commit.valve=Please specify whether to commit sessions once per request. Default '${default}':
+prefer.deserialized.form=Please specify whether to prefer keeping attributes in deserialized form. Default '${default}':
+eviction.heap.percentage=Please enter the percentage of heap at which sessions will be evicted from the local cache. Default '${default}':
+locators=Please enter the list of locators used by GemFire members to discover each other. The format is a comma-separated list of host[port]. Default '${default}':
+log.file=Please enter the name of the file used to log GemFire messages. Default '${default}':
+multicast.discovery.port=Please enter the port used by GemFire members to discover each other using multicast networking. Default '${default}':
+multicast.discovery.address=Please enter the address used by GemFire members to discover each other using multicast networking. Default '${default}':
+rebalance=Please specify whether to rebalance the GemFire cache at startup. Default '${default}':
+region.attributes.id=Please enter the id of the attributes of the GemFire region used to cache sessions. Default '${default}':
+region.name=Please enter the name of the GemFire region used to cache sessions. Default '${default}':
+statistic.archive.file=Please enter the name of the file used to store GemFire statistics. Default '${default}':
+statistic.sampling.enabled=Please specify whether GemFire statistic sampling should be enabled. Default '${default}':
+initial.vm.heap.size.mb=Please specify the initial VM heap size in MB (-Xms). Default '${default}':
+maximum.vm.heap.size.mb=Please specify the maximum VM heap size in MB (-Xmx). Default '${default}':
+cms.initiating.heap.percentage=Please specify the percentage of VM heap utilization before a concurrent collection is initiated (--XX:CMSInitiatingOccupancyFraction [Hotspot-only]). Default '${default}':
+tomcat.version=Please enter the major version of Tomcat you will be using (6, 7 or 8). Default '${default}':
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/context-fragment.xml
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/context-fragment.xml b/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/context-fragment.xml
new file mode 100644
index 0000000..2b3d25c
--- /dev/null
+++ b/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/context-fragment.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Context>
+
+ <add:Manager className="com.gemstone.gemfire.modules.session.catalina.Tomcat6DeltaSessionManager"
+ enableDebugListener="${enable.debug.listener:false}"
+ enableGatewayReplication="${enable.gateway.replication:false}"
+ enableLocalCache="${enable.local.cache:false}"
+ enableCommitValve="${enable.commit.valve:true}"
+ preferDeserializedForm="${prefer.deserialized.form:true}"
+ regionAttributesId="${region.attributes.id:REPLICATE}"
+ regionName="${region.name:gemfire_modules_sessions}"/>
+
+</Context>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/modules.env
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/modules.env b/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/modules.env
new file mode 100644
index 0000000..9c4c00a
--- /dev/null
+++ b/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/modules.env
@@ -0,0 +1 @@
+TOMCAT_MAJOR_VER=6
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/server-fragment.xml
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/server-fragment.xml b/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/server-fragment.xml
new file mode 100644
index 0000000..d1983c0
--- /dev/null
+++ b/extensions/gemfire-modules-assembly/release/tcserver/gemfire-p2p/server-fragment.xml
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='utf-8'?>
+<Server>
+
+ <add:Listener className="com.gemstone.gemfire.modules.session.catalina.PeerToPeerCacheLifecycleListener"
+ cache-xml-file="${cache.configuration.file:cache-peer.xml}"
+ criticalHeapPercentage="${critical.heap.percentage:0.0}"
+ evictionHeapPercentage="${eviction.heap.percentage:80.0}"
+ locators="${locators: }"
+ log-file="${log.file:gemfire_modules.log}"
+ mcast-port="${multicast.discovery.port:10334}"
+ mcast-address="${multicast.discovery.address:239.192.81.1}"
+ rebalance="${rebalance:false}"
+ statistic-archive-file="${statistic.archive.file:gemfire_modules.gfs}"
+ statistic-sampling-enabled="${statistic.sampling.enabled:false}"/>
+
+</Server>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/extensions/gemfire-modules-assembly/release/tomcat/readme.txt
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-assembly/release/tomcat/readme.txt b/extensions/gemfire-modules-assembly/release/tomcat/readme.txt
new file mode 100644
index 0000000..4830780
--- /dev/null
+++ b/extensions/gemfire-modules-assembly/release/tomcat/readme.txt
@@ -0,0 +1,14 @@
+Pivotal(TM) GemFire(R) HTTP Session Management Module @VERSION@ for Tomcat
+
+This module provides fast, scalable, and reliable HTTP session replication for Apache Tomcat.
+
+Access all Pivotal GemFire Documentation at:
+http://gemfire.docs.pivotal.io
+
+Pivotal Support Services can be accessed from the Pivotal or VMware website.
+Access varies by license type, support offering (contract or per-incident) and
+product. Please see the Pivotal page at http://www.pivotal.io/support or to
+file a VMware Support Request, please see the VMware page at
+https://www.vmware.com/support/policies/howto.html for information on "How to
+File a Support Request."
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/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..928e8bf
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/build.gradle
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+jar {
+ baseName = 'gemfire-modules-hibernate'
+}
+
+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'
+
+ 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/48552465/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..55b824c
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/EnumType.java
@@ -0,0 +1,58 @@
+/*
+* 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 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/48552465/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..7548061
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCache.java
@@ -0,0 +1,238 @@
+/*
+* 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 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/48552465/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..e684c7d
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheListener.java
@@ -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.
+*/
+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/48552465/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..9cd6c88
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireCacheProvider.java
@@ -0,0 +1,200 @@
+/*
+* 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 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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/48552465/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..c019436
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireQueryCacheFactory.java
@@ -0,0 +1,39 @@
+/*
+* 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 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/48552465/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..97e5fdf
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/GemFireRegionFactory.java
@@ -0,0 +1,237 @@
+/*
+* 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 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/48552465/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..86c6786
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/Access.java
@@ -0,0 +1,257 @@
+/*
+* 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 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/48552465/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..980e6ab
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/ClientServerRegionFactoryDelegate.java
@@ -0,0 +1,208 @@
+/*
+* 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 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/48552465/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..f1898d8
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/CollectionAccess.java
@@ -0,0 +1,224 @@
+/*
+* 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 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/48552465/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..5a4e5e1
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityRegionWriter.java
@@ -0,0 +1,87 @@
+/*
+* 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 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/48552465/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..abfb675
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersion.java
@@ -0,0 +1,28 @@
+/*
+* 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 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/48552465/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..ad160e4
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityVersionImpl.java
@@ -0,0 +1,51 @@
+/*
+* 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 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/48552465/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..ab92dea
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/EntityWrapper.java
@@ -0,0 +1,89 @@
+/*
+* 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 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/48552465/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..9e77a98
--- /dev/null
+++ b/extensions/gemfire-modules-hibernate/src/main/java/com/gemstone/gemfire/modules/hibernate/internal/GemFireBaseRegion.java
@@ -0,0 +1,166 @@
+/*
+* 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 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);
+ }
+
+}