Return-Path: X-Original-To: apmail-geode-commits-archive@minotaur.apache.org Delivered-To: apmail-geode-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 87C91189EC for ; Thu, 7 Jan 2016 21:22:26 +0000 (UTC) Received: (qmail 86826 invoked by uid 500); 7 Jan 2016 21:22:26 -0000 Delivered-To: apmail-geode-commits-archive@geode.apache.org Received: (qmail 86795 invoked by uid 500); 7 Jan 2016 21:22:26 -0000 Mailing-List: contact commits-help@geode.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@geode.incubator.apache.org Delivered-To: mailing list commits@geode.incubator.apache.org Received: (qmail 86786 invoked by uid 99); 7 Jan 2016 21:22:26 -0000 Received: from Unknown (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 07 Jan 2016 21:22:26 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id D0E70C0FF9 for ; Thu, 7 Jan 2016 21:22:25 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: 0.8 X-Spam-Level: X-Spam-Status: No, score=0.8 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, RP_MATCHES_RCVD=-0.001, URIBL_BLOCKED=0.001] autolearn=disabled Received: from mx1-us-west.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id YM2gBH58YiQH for ; Thu, 7 Jan 2016 21:22:11 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-us-west.apache.org (ASF Mail Server at mx1-us-west.apache.org) with SMTP id 70C5C231B8 for ; Thu, 7 Jan 2016 21:22:01 +0000 (UTC) Received: (qmail 85706 invoked by uid 99); 7 Jan 2016 21:22:01 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 07 Jan 2016 21:22:01 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 48011E3826; Thu, 7 Jan 2016 21:22:01 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: jensdeppe@apache.org To: commits@geode.incubator.apache.org Date: Thu, 07 Jan 2016 21:22:09 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [10/27] 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/3c04cd22/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/3c04cd22/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 @@ + + + + + + http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3c04cd22/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/3c04cd22/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 @@ + + + + + + http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3c04cd22/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/3c04cd22/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/3c04cd22/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: + *
+ * <property name="myEnum">
+ *   <type name="com.gemstone.gemfire.modules.hibernate.EnumType">
+ *     <param name="enumClass">com.mycompany.MyEntity$MyEnum</param>
+ *     <param name="type">12</param>
+ *   </type>
+ * </property>
+ * 
+ * @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 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/3c04cd22/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 null + * @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/3c04cd22/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/3c04cd22/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 + *
    + *
  1. gemfire.default-region-attributes-id: the default region type to + * create. (default value for this is REPLICATE) + *
  2. gemfire.region-attributes-for:fullyQualifiedRegionName when a region + * wants to override the default region type + *
+ * + * @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 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/3c04cd22/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/3c04cd22/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 gemfireAttributes; + + /** + * maps the entity to the region that stores it. + */ + private ConcurrentMap entityRegionMap = new ConcurrentHashMap(); + + 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 gemfireAttributes = getGemFireAttributesNames(); + return gemfireAttributes.contains(gfKey); + } + + private Set 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(); + 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 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 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/3c04cd22/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> createStatus = new ThreadLocal>() { + @Override + protected Map initialValue() { + return new HashMap(); + } + }; + + 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 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/3c04cd22/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 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 getLocatorsMap(String locatorsString) { + List retval = new ArrayList(); + 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 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 r = this.clientCache.getRegion(regionName); + if (r != null) { + return r; + } + String clientRegionType = getClientRegionType(regionName); + ClientRegionFactory 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 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 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/3c04cd22/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 getAllSet = new HashSet(); + 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 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/3c04cd22/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/3c04cd22/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/3c04cd22/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/3c04cd22/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/3c04cd22/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 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 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 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 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); + } + +}