├── .gitignore
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── net
│ └── daum
│ └── clix
│ └── hibernate
│ └── redis
│ ├── AbstractRedisRegionFactory.java
│ ├── RedisCache.java
│ ├── RedisRegionFactory.java
│ ├── jedis
│ └── JedisCacheImpl.java
│ ├── region
│ ├── RedisCollectionRegion.java
│ ├── RedisEntityRegion.java
│ ├── RedisQueryResultRegion.java
│ ├── RedisRegion.java
│ ├── RedisTimestampsRegion.java
│ └── RedisTransactionalRegion.java
│ └── strategy
│ ├── AbstractReadWriteRedisAccessStrategy.java
│ ├── AbstractRedisAccessStrategy.java
│ ├── NonStrictReadWriteRedisCollectionRegionAccessStrategy.java
│ ├── NonStrictReadWriteRedisEntityRegionAccessStrategy.java
│ ├── ReadOnlyRedisCollectionRegionAccessStrategy.java
│ ├── ReadOnlyRedisEntityRegionAccessStrategy.java
│ ├── ReadWriteRedisCollectionRegionAcessStrategy.java
│ ├── ReadWriteRedisEntityRegionAcessStrategy.java
│ ├── RedisAccessStrategyFactory.java
│ └── RedisAccessStrategyFactoryImpl.java
└── test
├── java
└── net
│ └── daum
│ └── clix
│ ├── Campaign.java
│ └── test
│ └── CampaignTest.java
└── resources
├── hibernate.cfg.xml
└── log4j.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | /db
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hibernate-redis
2 | A library for using Redis as a second level distributed cache in Hibernate.
3 | This is an open source project.
4 |
5 | version : 1.0.0-SNAPSHOT
6 |
7 | ## Feature
8 | * Implement hibernate entity & query results cache using redis
9 | * Implement read-write strategy locking with [SETNX](http://redis.io/commands/setnx)
10 |
11 | ## System Requirements
12 |
13 | JDK 1.6 or above.
14 |
15 | ## Using Hibernate-redis
16 |
17 | * checkout this source
18 |
19 | git clone git@github.com:Jongtae/hibernate-redis.git
20 |
21 | * install locally using maven' install commend:
22 |
23 | mvn install -DskipTests
24 |
25 | * add dependency in your project pom.xml:
26 |
27 |
28 | net.daum.clix
29 | hibernate-redis
30 |
31 |
32 | * configurate hibernate properties like this :
33 |
34 | true
35 | true
36 | net.daum.clix.hibernate.redis.RedisRegionFactory
37 |
38 | "redis.host"
39 |
40 | * set your additional redis properites optionally
41 |
42 | "redis.port"
43 | "redis.timeout"
44 | "redis.password"
45 |
46 | ## License
47 |
48 | This software is licensed under the Apache 2 license, quoted below.
49 |
50 | Licensed under the Apache License, Version 2.0 (the "License"); you may not
51 | use this file except in compliance with the License. You may obtain a copy of
52 | the License at
53 |
54 | http://www.apache.org/licenses/LICENSE-2.0
55 |
56 | Unless required by applicable law or agreed to in writing, software
57 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
58 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
59 | License for the specific language governing permissions and limitations under
60 | the License.
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | net.daum.clix
6 | hibernate-redis
7 | 1.0
8 | jar
9 |
10 | hibernate-redis
11 | https://github.com/Jongtae/hibernate-redis
12 | A library for using Redis as a second level distributed cache in Hibernate.
13 |
14 |
15 |
16 | Jongtae Lee
17 | jt.jongtae@gmail.com
18 |
19 |
20 | Jongjin Han
21 | 84june@gmail.com
22 |
23 |
24 |
25 |
26 | scm:git:git@github.com:jongtae/hibernate-redis.git
27 | scm:git:git@github.com:jongtae/hibernate-redis.git
28 | scm:git:git@github.com:jongtae/hibernate-redis.git
29 |
30 |
31 |
32 | UTF-8
33 |
34 |
35 |
36 |
37 | jboss
38 | https://repository.jboss.org/nexus/content/groups/public/
39 |
40 |
41 |
42 |
43 |
44 | redis.clients
45 | jedis
46 | 2.0.0
47 | jar
48 | compile
49 |
50 |
51 | org.hibernate
52 | hibernate-core
53 | 4.3.5.Final
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | org.aspectj
63 | aspectjrt
64 | 1.6.11
65 |
66 |
67 | org.aspectj
68 | aspectjtools
69 | 1.6.11
70 |
71 |
72 | org.aspectj
73 | aspectjweaver
74 | 1.6.11
75 |
76 |
77 |
78 |
79 | org.slf4j
80 | slf4j-api
81 | 1.5.6
82 |
83 |
84 | org.slf4j
85 | slf4j-log4j12
86 | 1.5.6
87 | test
88 |
89 |
90 |
91 |
92 | org.hibernate
93 | hibernate-annotations
94 | 3.5.6-Final
95 | test
96 |
97 |
98 | javassist
99 | javassist
100 | 3.12.1.GA
101 | test
102 |
103 |
104 | junit
105 | junit
106 | 4.4
107 | test
108 |
109 |
110 | org.hsqldb
111 | hsqldb
112 | 2.2.9
113 | test
114 |
115 |
116 |
117 |
118 | org.springframework
119 | spring-core
120 | 3.0.5.RELEASE
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | org.codehaus.mojo
129 | aspectj-maven-plugin
130 | 1.4
131 |
132 | 1.6
133 | 1.6
134 | utf-8
135 | 1.6
136 |
137 |
138 |
139 |
140 | compile
141 | test-compile
142 |
143 |
144 |
145 |
146 |
147 | org.apache.maven.plugins
148 | maven-compiler-plugin
149 | 2.3.1
150 |
151 | UTF-8
152 | 1.6
153 | 1.6
154 |
155 |
156 |
157 | org.apache.maven.plugins
158 | maven-surefire-plugin
159 | 2.12.2
160 |
161 |
162 | -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/1.6.11/aspectjweaver-1.6.11.jar"
163 |
164 |
165 |
166 |
167 | org.apache.maven.plugins
168 | maven-release-plugin
169 | 2.4
170 |
171 |
172 | org.kualigan.maven.plugins
173 | redis-maven-plugin
174 |
175 |
176 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/AbstractRedisRegionFactory.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis;
2 |
3 | import net.daum.clix.hibernate.redis.jedis.JedisCacheImpl;
4 | import net.daum.clix.hibernate.redis.region.RedisCollectionRegion;
5 | import net.daum.clix.hibernate.redis.region.RedisEntityRegion;
6 | import net.daum.clix.hibernate.redis.region.RedisQueryResultRegion;
7 | import net.daum.clix.hibernate.redis.region.RedisTimestampsRegion;
8 | import net.daum.clix.hibernate.redis.strategy.RedisAccessStrategyFactory;
9 | import net.daum.clix.hibernate.redis.strategy.RedisAccessStrategyFactoryImpl;
10 | import org.hibernate.cache.CacheException;
11 | import org.hibernate.cache.spi.*;
12 | import org.hibernate.cache.spi.access.AccessType;
13 | import org.hibernate.cfg.Settings;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 | import redis.clients.jedis.JedisPool;
17 |
18 | import java.util.Properties;
19 |
20 | /**
21 | * @author jtlee
22 | * @author 84june
23 | */
24 | abstract class AbstractRedisRegionFactory implements RegionFactory {
25 |
26 | private final Logger logger = LoggerFactory.getLogger(getClass());
27 |
28 | protected JedisPool pool;
29 |
30 | protected Properties properties;
31 |
32 | protected Settings settings;
33 |
34 | /**
35 | * {@link RedisAccessStrategyFactory} for creating various access strategies
36 | */
37 | private final RedisAccessStrategyFactory accessStrategyFactory = new RedisAccessStrategyFactoryImpl();
38 |
39 | @Override
40 | public boolean isMinimalPutsEnabledByDefault() {
41 | return true;
42 | }
43 |
44 | @Override
45 | public AccessType getDefaultAccessType() {
46 | return AccessType.READ_WRITE;
47 | }
48 |
49 | @Override
50 | public long nextTimestamp() {
51 | return System.currentTimeMillis() / 100;
52 | }
53 |
54 | @Override
55 | public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException {
56 | return new RedisEntityRegion(accessStrategyFactory, getRedisCache(regionName), properties, metadata, settings);
57 | }
58 |
59 | @Override
60 | public CollectionRegion buildCollectionRegion(String regionName, Properties properties, CacheDataDescription metadata)
61 | throws CacheException {
62 | return new RedisCollectionRegion(accessStrategyFactory, getRedisCache(regionName), properties, metadata, settings);
63 | }
64 |
65 | @Override
66 | public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
67 | return new RedisQueryResultRegion(accessStrategyFactory, getRedisCache(regionName), properties);
68 | }
69 |
70 | @Override
71 | public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
72 | return new RedisTimestampsRegion(accessStrategyFactory, getRedisCache(regionName), properties);
73 | }
74 |
75 | private RedisCache getRedisCache(String regionName) {
76 | return new JedisCacheImpl(pool, regionName);
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/RedisCache.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis;
2 |
3 | import org.hibernate.cache.CacheException;
4 |
5 | /**
6 | * An interface for Redis.
7 | *
8 | * @author jtlee
9 | * @author 84june
10 | */
11 | public interface RedisCache {
12 |
13 | String getRegionName();
14 |
15 | boolean exists(String key);
16 |
17 | Object get(Object key) throws CacheException;
18 |
19 | void put(Object key, Object value) throws CacheException;
20 |
21 | void remove(Object key) throws CacheException;
22 |
23 | void destory();
24 |
25 | boolean lock(Object key, Integer expireMsecs) throws InterruptedException;
26 |
27 | void unlock(Object key);
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/RedisRegionFactory.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis;
2 |
3 | import org.hibernate.cache.CacheException;
4 | import org.hibernate.cache.spi.CacheDataDescription;
5 | import org.hibernate.cache.spi.NaturalIdRegion;
6 | import org.hibernate.cfg.Settings;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import redis.clients.jedis.JedisPool;
10 | import redis.clients.jedis.JedisPoolConfig;
11 | import redis.clients.jedis.Protocol;
12 | import sun.reflect.generics.reflectiveObjects.NotImplementedException;
13 |
14 | import java.util.Properties;
15 |
16 | /**
17 | * @author jtlee
18 | * @author 84june
19 | */
20 | public class RedisRegionFactory extends AbstractRedisRegionFactory {
21 |
22 | private final Logger logger = LoggerFactory.getLogger(getClass());
23 |
24 | public RedisRegionFactory(Properties properties) {
25 | this.properties = properties;
26 | }
27 |
28 | @Override
29 | public void start(Settings settings, Properties properties) throws CacheException {
30 | this.settings = settings;
31 | this.properties = properties;
32 | logger.info("Initializing RedisClient(Jedis)...");
33 | this.pool = new JedisPool(new JedisPoolConfig(), properties.getProperty("redis.host", "localhost"),
34 | Integer.valueOf(properties.getProperty("redis.port", String.valueOf(Protocol.DEFAULT_PORT))),
35 | Integer.valueOf(properties.getProperty("redis.timeout",String.valueOf(Protocol.DEFAULT_TIMEOUT))),
36 | properties.getProperty("redis.password",null));
37 | }
38 |
39 | @Override
40 | public void stop() {
41 | this.pool.destroy();
42 | }
43 |
44 | @Override
45 | public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException {
46 | throw new NotImplementedException(); //TODO still not implemented
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/jedis/JedisCacheImpl.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.jedis;
2 |
3 | import net.daum.clix.hibernate.redis.RedisCache;
4 | import org.hibernate.cache.CacheException;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.core.serializer.support.DeserializingConverter;
8 | import org.springframework.core.serializer.support.SerializingConverter;
9 | import redis.clients.jedis.Jedis;
10 | import redis.clients.jedis.JedisPool;
11 | import redis.clients.jedis.exceptions.JedisConnectionException;
12 |
13 | /**
14 | * @author jtlee
15 | * @author 84june
16 | */
17 | public class JedisCacheImpl implements RedisCache {
18 |
19 | private JedisPool jedisPool;
20 |
21 | private Jedis jedis;
22 |
23 | private String regionName;
24 |
25 | private final Logger logger = LoggerFactory.getLogger(getClass());
26 |
27 | public JedisCacheImpl(JedisPool jedisPool, String regionName) {
28 | this.jedisPool = jedisPool;
29 | this.regionName = regionName;
30 | this.jedis = jedisPool.getResource();
31 | }
32 |
33 | @Override
34 | public Object get(Object key) throws CacheException {
35 | Object o = null;
36 |
37 | byte[] k = serializeObject(key.toString());
38 | try {
39 | byte[] v = jedis.get(k);
40 | if (v != null && v.length > 0) {
41 | o = deserializeObject(v);
42 | }
43 |
44 | return o;
45 | } catch (JedisConnectionException e) {
46 | logger.error(key.toString(), e);
47 | }
48 | return null;
49 | }
50 |
51 | @Override
52 | public void put(Object key, Object value) throws CacheException {
53 | byte[] k = serializeObject(key.toString());
54 | byte[] v = serializeObject(value);
55 |
56 | try {
57 | jedis.set(k, v);
58 | } catch (JedisConnectionException e) {
59 | logger.error(key.toString(), e);
60 | }
61 | }
62 |
63 | @Override
64 | public void remove(Object key) throws CacheException {
65 | try {
66 | jedis.del(serializeObject(key.toString()));
67 | } catch (JedisConnectionException e) {
68 | logger.error(key.toString(), e);
69 | }
70 | }
71 |
72 | @Override
73 | public boolean exists(String key) {
74 | try {
75 | return jedis.exists(serializeObject(key));
76 | } catch (JedisConnectionException e) {
77 | logger.error(key, e);
78 | }
79 | return false;
80 | }
81 |
82 | @Override
83 | public String getRegionName() {
84 | return this.regionName;
85 | }
86 |
87 | @Override
88 | public void destory() {
89 | jedisPool.returnResource(jedis);
90 | }
91 |
92 | private byte[] serializeObject(Object obj) {
93 | SerializingConverter sc = new SerializingConverter();
94 | return sc.convert(obj);
95 | }
96 |
97 | private Object deserializeObject(byte[] b) {
98 | DeserializingConverter dc = new DeserializingConverter();
99 | return dc.convert(b);
100 | }
101 |
102 | public boolean lock(Object key, Integer expireMsecs) throws InterruptedException {
103 |
104 | String lockKey = generateLockKey(key);
105 | long expires = System.currentTimeMillis() + expireMsecs + 1;
106 | String expiresStr = String.valueOf(expires);
107 | long timeout = expireMsecs;
108 |
109 | while (timeout >= 0) {
110 |
111 | try {
112 | if (jedis.setnx(lockKey, expiresStr) == 1) {
113 | return true;
114 | }
115 |
116 | String currentValueStr = jedis.get(lockKey);
117 | if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
118 | // lock is expired
119 |
120 | String oldValueStr = jedis.getSet(lockKey, expiresStr);
121 | if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
122 | // lock acquired
123 | return true;
124 | }
125 | }
126 | } catch (JedisConnectionException e) {
127 | logger.error(key.toString(), e);
128 | return false;
129 | }
130 | logger.info("{} is now locking and waiting for unlock", key.toString());
131 | timeout -= 100;
132 | Thread.sleep(100);
133 | }
134 | return false;
135 | }
136 |
137 | @Override
138 | public void unlock(Object key) {
139 | jedis.del(generateLockKey(key));
140 | }
141 |
142 | private String generateLockKey(Object key) {
143 |
144 | if (null == key) {
145 | throw new IllegalArgumentException("key must not be null");
146 | }
147 |
148 | return key.toString() + ".lock";
149 | }
150 |
151 |
152 | }
153 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/region/RedisCollectionRegion.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.region;
2 |
3 | import net.daum.clix.hibernate.redis.RedisCache;
4 | import net.daum.clix.hibernate.redis.strategy.RedisAccessStrategyFactory;
5 | import org.hibernate.cache.CacheException;
6 | import org.hibernate.cache.spi.CacheDataDescription;
7 | import org.hibernate.cache.spi.CollectionRegion;
8 | import org.hibernate.cache.spi.access.AccessType;
9 | import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
10 | import org.hibernate.cfg.Settings;
11 |
12 | import java.util.Properties;
13 |
14 | /**
15 | * @author jtlee
16 | * @author 84june
17 | */
18 | public class RedisCollectionRegion extends RedisTransactionalRegion implements CollectionRegion {
19 |
20 | public RedisCollectionRegion(RedisAccessStrategyFactory accessStrategyFactory, RedisCache cache, Properties properties, CacheDataDescription metadata, Settings settings) {
21 | super(accessStrategyFactory, cache, properties, metadata, settings);
22 | }
23 |
24 | @Override
25 | public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
26 | return accessStrategyFactory.createCollectionRegionAccessStrategy(this, accessType);
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/region/RedisEntityRegion.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.region;
2 |
3 | import net.daum.clix.hibernate.redis.RedisCache;
4 | import net.daum.clix.hibernate.redis.strategy.RedisAccessStrategyFactory;
5 | import org.hibernate.cache.CacheException;
6 | import org.hibernate.cache.spi.CacheDataDescription;
7 | import org.hibernate.cache.spi.EntityRegion;
8 | import org.hibernate.cache.spi.access.AccessType;
9 | import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
10 | import org.hibernate.cfg.Settings;
11 |
12 | import java.util.Properties;
13 |
14 | /**
15 | * @author jtlee
16 | * @author 84june
17 | */
18 | public class RedisEntityRegion extends RedisTransactionalRegion implements EntityRegion {
19 |
20 | public RedisEntityRegion(RedisAccessStrategyFactory accessStrategyFactory, RedisCache cache, Properties properties, CacheDataDescription metadata, Settings settings) {
21 | super(accessStrategyFactory, cache, properties, metadata, settings);
22 | }
23 |
24 | @Override
25 | public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
26 | return accessStrategyFactory.createEntityRegionAccessStrategy(this, accessType);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/region/RedisQueryResultRegion.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.region;
2 |
3 | import net.daum.clix.hibernate.redis.RedisCache;
4 | import net.daum.clix.hibernate.redis.strategy.RedisAccessStrategyFactory;
5 | import org.hibernate.cache.CacheException;
6 | import org.hibernate.cache.spi.QueryResultsRegion;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.util.Properties;
11 |
12 | /**
13 | * @author jtlee
14 | * @author 84june
15 | */
16 | public class RedisQueryResultRegion extends RedisRegion implements QueryResultsRegion {
17 |
18 | private final Logger LOG = LoggerFactory.getLogger(getClass());
19 |
20 | public RedisQueryResultRegion(RedisAccessStrategyFactory accessStrategyFactory, RedisCache cache, Properties properties) {
21 | super(accessStrategyFactory, cache, properties);
22 | }
23 |
24 | @Override
25 | public Object get(Object key) throws CacheException {
26 | return cache.get(key);
27 | }
28 |
29 | @Override
30 | public void put(Object key, Object value) throws CacheException {
31 | cache.put(key, value);
32 | }
33 |
34 | @Override
35 | public void evict(Object key) throws CacheException {
36 | cache.remove(key);
37 | }
38 |
39 | @Override
40 | public void evictAll() throws CacheException {
41 | throw new UnsupportedOperationException("RedisQueryResultRegion#evictAll has not implemented yet!!");
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/region/RedisRegion.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.region;
2 |
3 | import net.daum.clix.hibernate.redis.RedisCache;
4 | import net.daum.clix.hibernate.redis.strategy.RedisAccessStrategyFactory;
5 | import org.hibernate.cache.CacheException;
6 | import org.hibernate.cache.spi.Region;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 | import java.util.Properties;
11 |
12 | /**
13 | * @author jtlee
14 | * @author 84june
15 | */
16 | public abstract class RedisRegion implements Region {
17 |
18 | private static final String CACHE_LOCK_TIMEOUT_PROPERTY = "net.daum.clix.hibernate.redis.cache_lock_timeout";
19 | private static final int DEFAULT_CACHE_LOCK_TIMEOUT = 1000;
20 |
21 | /**
22 | * RedisCache instance backing this Hibernate data region.
23 | */
24 | protected final RedisCache cache;
25 |
26 | /**
27 | * The {@link net.daum.clix.hibernate.redis.strategy.RedisAccessStrategyFactory} used for creating various access strategies
28 | */
29 | protected final RedisAccessStrategyFactory accessStrategyFactory;
30 |
31 | private int cacheLockTimeout;
32 |
33 | /**
34 | * Create a Hibernate data region backed by the given Redis instance.
35 | */
36 | RedisRegion(RedisAccessStrategyFactory accessStrategyFactory, RedisCache cache, Properties properties) {
37 | this.accessStrategyFactory = accessStrategyFactory;
38 | this.cache = cache;
39 | String timeoutProperty = properties.getProperty(CACHE_LOCK_TIMEOUT_PROPERTY);
40 | this.cacheLockTimeout = timeoutProperty == null ? DEFAULT_CACHE_LOCK_TIMEOUT : Integer.parseInt(timeoutProperty);
41 | }
42 |
43 | /**
44 | * {@inheritDoc}
45 | */
46 | public String getName() {
47 | return cache.getRegionName();
48 | }
49 |
50 | /**
51 | * {@inheritDoc}
52 | */
53 | public void destroy() throws CacheException {
54 | cache.destory();
55 | }
56 |
57 | /**
58 | * {@inheritDoc}
59 | */
60 | public long getSizeInMemory() {
61 | return -1;
62 | }
63 |
64 | /**
65 | * {@inheritDoc}
66 | */
67 | public long getElementCountInMemory() {
68 | return -1;
69 | }
70 |
71 | /**
72 | * {@inheritDoc}
73 | */
74 | public long getElementCountOnDisk() {
75 | return -1;
76 | }
77 |
78 | /**
79 | * {@inheritDoc}
80 | */
81 | public Map toMap() {
82 | return new HashMap();
83 | }
84 |
85 | /**
86 | * {@inheritDoc}
87 | */
88 | public long nextTimestamp() {
89 | return System.currentTimeMillis() / 100;
90 | }
91 |
92 | /**
93 | * {@inheritDoc}
94 | */
95 | public int getTimeout() {
96 | return cacheLockTimeout;
97 | }
98 |
99 | /**
100 | * Return the RedisCache instance backing this Hibernate data region.
101 | */
102 | public RedisCache getRedisCache() {
103 | return cache;
104 | }
105 |
106 | /**
107 | * Returns true
if this region contains data for the given key.
108 | *
109 | * This is a Hibernate 3.5 method.
110 | */
111 | public boolean contains(Object key) {
112 | return cache.exists(key.toString());
113 | }
114 |
115 | public Object get(Object key){
116 | return cache.get(key);
117 | }
118 |
119 | public void put(Object key, Object value){
120 | cache.put(key, value);
121 | }
122 |
123 | public boolean writeLock(Object key){
124 | try {
125 | return cache.lock(key, getTimeout());
126 | } catch (InterruptedException e) {
127 | return false;
128 | }
129 | }
130 |
131 | public void releaseLock(Object key){
132 | cache.unlock(key);
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/region/RedisTimestampsRegion.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.region;
2 |
3 | import net.daum.clix.hibernate.redis.RedisCache;
4 | import net.daum.clix.hibernate.redis.strategy.RedisAccessStrategyFactory;
5 | import org.hibernate.cache.CacheException;
6 | import org.hibernate.cache.spi.TimestampsRegion;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.util.Properties;
11 |
12 | /**
13 | * @author jtlee
14 | * @author 84june
15 | */
16 | public class RedisTimestampsRegion extends RedisRegion implements TimestampsRegion {
17 |
18 | private final Logger LOG = LoggerFactory.getLogger(getClass());
19 |
20 | public RedisTimestampsRegion(RedisAccessStrategyFactory accessStrategyFactory, RedisCache cache, Properties properties) {
21 | super(accessStrategyFactory, cache, properties);
22 | }
23 |
24 | @Override
25 | public Object get(Object key) throws CacheException {
26 | LOG.debug("called get : {}", key);
27 | return cache.get(key);
28 | }
29 |
30 | @Override
31 | public void put(Object key, Object value) throws CacheException {
32 | LOG.debug("called put by K:{}, V:{}", key, value);
33 | cache.put(key, value);
34 | }
35 |
36 | @Override
37 | public void evict(Object key) throws CacheException {
38 | cache.remove(key);
39 | }
40 |
41 | @Override
42 | public void evictAll() throws CacheException {
43 | throw new UnsupportedOperationException("RedisTimestampsRegion#evictAll has not implemented yet!!");
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/region/RedisTransactionalRegion.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.region;
2 |
3 | import net.daum.clix.hibernate.redis.RedisCache;
4 | import net.daum.clix.hibernate.redis.strategy.RedisAccessStrategyFactory;
5 | import org.hibernate.cache.spi.CacheDataDescription;
6 | import org.hibernate.cache.spi.TransactionalDataRegion;
7 | import org.hibernate.cfg.Settings;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.util.Properties;
12 |
13 | /**
14 | * @author 84june
15 | */
16 | public class RedisTransactionalRegion extends RedisRegion implements TransactionalDataRegion {
17 |
18 | private final Logger LOG = LoggerFactory.getLogger(getClass());
19 |
20 | /**
21 | * Hibernate settings associated with the persistence unit.
22 | */
23 | protected final Settings settings;
24 |
25 | /**
26 | * Metadata associated with the objects stored in the region.
27 | */
28 | protected final CacheDataDescription metadata;
29 |
30 | RedisTransactionalRegion(RedisAccessStrategyFactory accessStrategyFactory, RedisCache cache, Properties properties,
31 | CacheDataDescription metadata, Settings settings) {
32 | super(accessStrategyFactory, cache, properties);
33 | this.metadata = metadata;
34 | this.settings = settings;
35 | }
36 |
37 | @Override
38 | public boolean isTransactionAware() {
39 | return false;
40 | }
41 |
42 | @Override
43 | public CacheDataDescription getCacheDataDescription() {
44 | return metadata;
45 | }
46 |
47 | public Settings getSettings() {
48 | return settings;
49 | }
50 |
51 | public final void remove(Object key) {
52 | cache.remove(key);
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/AbstractReadWriteRedisAccessStrategy.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.region.RedisTransactionalRegion;
4 | import org.hibernate.cache.CacheException;
5 | import org.hibernate.cache.spi.access.SoftLock;
6 | import org.hibernate.cfg.Settings;
7 |
8 | import java.io.Serializable;
9 | import java.util.Comparator;
10 |
11 |
12 | /**
13 | * Superclass for all Redis specific Hibernate AccessStrategy implementations.
14 | *
15 | * @param type of the enclosed region
16 | * @author 84june
17 | */
18 | abstract class AbstractReadWriteRedisAccessStrategy extends AbstractRedisAccessStrategy {
19 |
20 | private final Comparator versionComparator;
21 |
22 | /**
23 | * Create an access strategy wrapping the given region.
24 | */
25 | AbstractReadWriteRedisAccessStrategy(T region, Settings settings) {
26 | super(region, settings);
27 | this.versionComparator = region.getCacheDataDescription().getVersionComparator();
28 | }
29 |
30 | public Object get(Object key, long txTimestamp) throws CacheException {
31 | Item item = (Item) region.get(key);
32 | if (null != item && item.isReadable(txTimestamp)) {
33 | return item.getValue();
34 | }
35 | return null;
36 | }
37 |
38 | public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) throws CacheException {
39 |
40 | if (region.writeLock(key)) {
41 | try {
42 | if (region.contains(key)) {
43 | Item item = (Item) region.get(key);
44 | if (!item.isWriteable(version, versionComparator)) {
45 | return false;
46 | }
47 | }
48 | region.put(key, new Item(version, txTimestamp, value));
49 | } finally {
50 | region.releaseLock(key);
51 | }
52 | return true;
53 | }
54 | return false;
55 | }
56 |
57 | /**
58 | * Returns false
since this is a read/write cache access strategy
59 | */
60 | public boolean insert(Object key, Object value, Object version) throws CacheException {
61 | return false;
62 | }
63 |
64 | public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
65 | if (region.writeLock(key)) {
66 | try {
67 | Item item = (Item) region.get(key);
68 | if (null != item && !item.isWriteable(version, versionComparator)) {
69 | return false;
70 | }
71 | region.put(key, new Item(version, region.nextTimestamp(), value));
72 | } finally {
73 | region.releaseLock(key);
74 | }
75 | return true;
76 | }
77 | return false;
78 | }
79 |
80 | /**
81 | * Returns false
since this is a read/write cache access strategy
82 | */
83 | public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException {
84 | return false;
85 | }
86 |
87 | public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) throws CacheException {
88 | if (region.writeLock(key)) {
89 | try {
90 | Item item = (Item) region.get(key);
91 | if (null != item && !item.isWriteable(currentVersion, versionComparator)) {
92 | return false;
93 | }
94 | region.put(key, new Item(currentVersion, region.nextTimestamp(), value));
95 | } finally {
96 | region.releaseLock(key);
97 | }
98 | return true;
99 | }
100 | return false;
101 | }
102 |
103 | protected final static class Item implements Serializable {
104 |
105 | private static final long serialVersionUID = -9173693640486739767L;
106 |
107 | private final Object version;
108 |
109 | private final long txTimestamp;
110 |
111 | private final Object value;
112 |
113 | public Item(Object version, long txTimestamp, Object value) {
114 | this.version = version;
115 | this.txTimestamp = txTimestamp;
116 | this.value = value;
117 | }
118 |
119 | public boolean isReadable(long txTimestamp) {
120 | return txTimestamp > this.txTimestamp;
121 | }
122 |
123 | public boolean isWriteable(Object newVersion, Comparator versionComparator) {
124 | return version != null && versionComparator.compare(version, newVersion) < 0;
125 | }
126 |
127 | @Override
128 | public boolean equals(Object o) {
129 | if (this == o) return true;
130 | if (o == null || getClass() != o.getClass()) return false;
131 |
132 | Item item = (Item) o;
133 |
134 | if (txTimestamp != item.txTimestamp) return false;
135 | if (!value.equals(item.value)) return false;
136 | if (version != null ? !version.equals(item.version) : item.version != null) return false;
137 |
138 | return true;
139 | }
140 |
141 | @Override
142 | public int hashCode() {
143 | int result = version != null ? version.hashCode() : 0;
144 | result = 31 * result + (int) (txTimestamp ^ (txTimestamp >>> 32));
145 | result = 31 * result + value.hashCode();
146 | return result;
147 | }
148 |
149 | public Object getValue() {
150 | return value;
151 | }
152 |
153 | }
154 | }
155 |
156 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/AbstractRedisAccessStrategy.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.RedisCache;
4 | import net.daum.clix.hibernate.redis.region.RedisTransactionalRegion;
5 | import org.hibernate.cache.CacheException;
6 | import org.hibernate.cache.spi.access.SoftLock;
7 | import org.hibernate.cfg.Settings;
8 |
9 |
10 | /**
11 | * Superclass for all Redis specific Hibernate AccessStrategy implementations.
12 | *
13 | * @param type of the enclosed region
14 | * @author 84june
15 | */
16 | abstract class AbstractRedisAccessStrategy {
17 |
18 | /**
19 | * The wrapped Hibernate cache region.
20 | */
21 | protected final T region;
22 | /**
23 | * The settings for this persistence unit.
24 | */
25 | protected final Settings settings;
26 | /**
27 | * RedisCache client instance
28 | */
29 | protected final RedisCache cache;
30 |
31 | /**
32 | * Create an access strategy wrapping the given region.
33 | */
34 | AbstractRedisAccessStrategy(T region, Settings settings) {
35 | this.region = region;
36 | this.settings = settings;
37 | this.cache = region.getRedisCache();
38 | }
39 |
40 | /**
41 | * This method is a placeholder for method signatures supplied by interfaces pulled in further down the class
42 | * hierarchy.
43 | *
44 | */
45 | public final boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
46 | return putFromLoad(key, value, txTimestamp, version, settings.isMinimalPutsEnabled());
47 | }
48 |
49 | /**
50 | * This method is a placeholder for method signatures supplied by interfaces pulled in further down the class
51 | * hierarchy.
52 | *
53 | */
54 | public abstract boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
55 | throws CacheException;
56 |
57 | /**
58 | * Region locks are not supported.
59 | *
60 | * @return null
61 | */
62 | public final SoftLock lockRegion() {
63 | return null;
64 | }
65 |
66 | public final void unlockRegion(SoftLock lock) throws CacheException {
67 | }
68 |
69 | /**
70 | * A no-op since this is an asynchronous cache access strategy.
71 | *
72 | */
73 | public void remove(Object key) throws CacheException {
74 | }
75 |
76 | /**
77 | * Not supported yet!! Called to evict data from the entire region
78 | *
79 | */
80 | public final void removeAll() throws CacheException {
81 | // region.clear();
82 | }
83 |
84 | /**
85 | * Remove the given mapping without regard to transactional safety
86 | *
87 | */
88 | public final void evict(Object key) throws CacheException {
89 | region.remove(key);
90 | }
91 |
92 | /**
93 | * Not Supported yet!! Remove all mappings without regard to transactional safety
94 | *
95 | */
96 | public final void evictAll() throws CacheException {
97 | // region.clear();
98 | }
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/NonStrictReadWriteRedisCollectionRegionAccessStrategy.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.region.RedisCollectionRegion;
4 | import org.hibernate.cache.CacheException;
5 | import org.hibernate.cache.spi.CollectionRegion;
6 | import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
7 | import org.hibernate.cache.spi.access.SoftLock;
8 | import org.hibernate.cfg.Settings;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | /**
13 | * @author jtlee
14 | * @author 84june
15 | */
16 | public class NonStrictReadWriteRedisCollectionRegionAccessStrategy extends AbstractRedisAccessStrategy
17 | implements CollectionRegionAccessStrategy {
18 |
19 | private final Logger LOG = LoggerFactory.getLogger(getClass());
20 |
21 | public NonStrictReadWriteRedisCollectionRegionAccessStrategy(RedisCollectionRegion region, Settings settings) {
22 | super(region, settings);
23 | }
24 |
25 | @Override
26 | public CollectionRegion getRegion() {
27 | return region;
28 | }
29 |
30 | @Override
31 | public Object get(Object key, long txTimestamp) throws CacheException {
32 | LOG.debug("called get by K:{}", key);
33 | return cache.get(key);
34 | }
35 |
36 | /**
37 | * {@inheritDoc}
38 | */
39 | public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
40 | throws CacheException {
41 | LOG.debug("called putFromLoad by K:{}, V:{}", key, value);
42 | if (minimalPutOverride && region.contains(key)) {
43 | return false;
44 | } else {
45 | cache.put(key, value);
46 | return true;
47 | }
48 | }
49 |
50 | /**
51 | * Since this is a non-strict read/write strategy item locking is not used.
52 | */
53 | public SoftLock lockItem(Object key, Object version) throws CacheException {
54 | return null;
55 | }
56 |
57 | /**
58 | * Since this is a non-strict read/write strategy item locking is not used.
59 | */
60 | public void unlockItem(Object key, SoftLock lock) throws CacheException {
61 | // LOG.debug("called unlockItem K:{}", key);
62 | // region.remove(key);
63 | }
64 |
65 | /**
66 | * {@inheritDoc}
67 | */
68 | @Override
69 | public void remove(Object key) throws CacheException {
70 | LOG.debug("called remove K:{}", key);
71 | region.remove(key);
72 | }
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/NonStrictReadWriteRedisEntityRegionAccessStrategy.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.region.RedisEntityRegion;
4 | import org.hibernate.cache.CacheException;
5 | import org.hibernate.cache.spi.EntityRegion;
6 | import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
7 | import org.hibernate.cache.spi.access.SoftLock;
8 | import org.hibernate.cfg.Settings;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | /**
13 | * @author jtlee
14 | * @author 84june
15 | */
16 | public class NonStrictReadWriteRedisEntityRegionAccessStrategy extends AbstractRedisAccessStrategy
17 | implements EntityRegionAccessStrategy {
18 |
19 | private final Logger LOG = LoggerFactory.getLogger(getClass());
20 |
21 | public NonStrictReadWriteRedisEntityRegionAccessStrategy(RedisEntityRegion region, Settings settings) {
22 | super(region, settings);
23 | }
24 |
25 | @Override
26 | public EntityRegion getRegion() {
27 | return this.region;
28 | }
29 |
30 | @Override
31 | public Object get(Object key, long txTimestamp) throws CacheException {
32 | LOG.debug("called get K:{}", key);
33 | return cache.get(key);
34 | }
35 |
36 | @Override
37 | public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
38 | throws CacheException {
39 | LOG.debug("called putFromLoad by K:{}, V:{}", key, value);
40 | if (minimalPutOverride && region.contains(key)) {
41 | return false;
42 | } else {
43 | cache.put(key, value);
44 | return true;
45 | }
46 | }
47 |
48 | /**
49 | * Since this is a non-strict read/write strategy item locking is not used.
50 | */
51 | @Override
52 | public SoftLock lockItem(Object key, Object version) throws CacheException {
53 | return null;
54 | }
55 |
56 | /**
57 | * Since this is a non-strict read/write strategy item locking is not used.
58 | */
59 | @Override
60 | public void unlockItem(Object key, SoftLock lock) throws CacheException {
61 | region.remove(key);
62 | }
63 |
64 | /**
65 | * Returns false
since this is an asynchronous cache access strategy.
66 | */
67 | @Override
68 | public boolean insert(Object key, Object value, Object version) throws CacheException {
69 | return false;
70 | }
71 |
72 | /**
73 | * Returns false
since this is a non-strict read/write cache access strategy
74 | */
75 | @Override
76 | public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
77 | return false;
78 | }
79 |
80 | /**
81 | * Removes the entry since this is a non-strict read/write cache strategy.
82 | */
83 | @Override
84 | public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException {
85 | LOG.debug("called update by K:{}, V:{}", key, value);
86 | remove(key);
87 | return false;
88 | }
89 |
90 | /**
91 | * {@inheritDoc}
92 | */
93 | @Override
94 | public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) throws CacheException {
95 | return false;
96 | }
97 |
98 | /**
99 | * {@inheritDoc}
100 | */
101 | @Override
102 | public void remove(Object key) throws CacheException {
103 | cache.remove(key);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/ReadOnlyRedisCollectionRegionAccessStrategy.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.region.RedisCollectionRegion;
4 | import org.hibernate.cache.CacheException;
5 | import org.hibernate.cache.spi.CollectionRegion;
6 | import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
7 | import org.hibernate.cache.spi.access.SoftLock;
8 | import org.hibernate.cfg.Settings;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | /**
13 | * @author jtlee
14 | * @author 84june
15 | */
16 | public class ReadOnlyRedisCollectionRegionAccessStrategy extends AbstractRedisAccessStrategy
17 | implements CollectionRegionAccessStrategy {
18 |
19 | private final Logger LOG = LoggerFactory.getLogger(getClass());
20 |
21 | public ReadOnlyRedisCollectionRegionAccessStrategy(RedisCollectionRegion region, Settings settings) {
22 | super(region, settings);
23 | }
24 |
25 | /**
26 | * {@inheritDoc}
27 | */
28 | @Override
29 | public CollectionRegion getRegion() {
30 | return region;
31 | }
32 |
33 | /**
34 | * {@inheritDoc}
35 | */
36 | @Override
37 | public Object get(Object key, long txTimestamp) throws CacheException {
38 | LOG.debug("called get by K:{}", key);
39 | return cache.get(key);
40 | }
41 |
42 | /**
43 | * {@inheritDoc}
44 | */
45 | @Override
46 | public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
47 | throws CacheException {
48 | LOG.debug("called putFromLoad by K:{}, V:{}", key, value);
49 | if (minimalPutOverride && region.contains(key)) {
50 | return false;
51 | } else {
52 | cache.put(key, value);
53 | return true;
54 | }
55 | }
56 |
57 | /**
58 | * Throws UnsupportedOperationException since this cache is read-only
59 | *
60 | * @throws UnsupportedOperationException always
61 | */
62 | @Override
63 | public SoftLock lockItem(Object key, Object version) throws UnsupportedOperationException {
64 | throw new UnsupportedOperationException("Can't write to a readonly object");
65 | }
66 |
67 | /**
68 | * A no-op since this cache is read-only
69 | */
70 | @Override
71 | public void unlockItem(Object key, SoftLock lock) throws CacheException {
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/ReadOnlyRedisEntityRegionAccessStrategy.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.region.RedisEntityRegion;
4 | import org.hibernate.cache.CacheException;
5 | import org.hibernate.cache.spi.EntityRegion;
6 | import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
7 | import org.hibernate.cache.spi.access.SoftLock;
8 | import org.hibernate.cfg.Settings;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | /**
13 | * @author jtlee
14 | * @author 84june
15 | */
16 | public class ReadOnlyRedisEntityRegionAccessStrategy extends AbstractRedisAccessStrategy
17 | implements EntityRegionAccessStrategy {
18 |
19 | private final Logger LOG = LoggerFactory.getLogger(getClass());
20 |
21 | public ReadOnlyRedisEntityRegionAccessStrategy(RedisEntityRegion region, Settings settings) {
22 | super(region, settings);
23 | }
24 |
25 | /**
26 | * {@inheritDoc}
27 | */
28 | @Override
29 | public EntityRegion getRegion() {
30 | return region;
31 | }
32 |
33 | /**
34 | * {@inheritDoc}
35 | */
36 | @Override
37 | public Object get(Object key, long txTimestamp) throws CacheException {
38 | LOG.debug("called get by K:{}", key);
39 | return cache.get(key);
40 | }
41 |
42 | /**
43 | * {@inheritDoc}
44 | */
45 | @Override
46 | public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) throws CacheException {
47 | LOG.debug("called put by K:{}, V:{}", key, value);
48 | if (minimalPutOverride && region.contains(key)) {
49 | return false;
50 | } else {
51 | cache.put(key, value);
52 | return true;
53 | }
54 | }
55 |
56 | /**
57 | * Throws UnsupportedOperationException since this cache is read-only
58 | *
59 | * @throws UnsupportedOperationException always
60 | */
61 | @Override
62 | public SoftLock lockItem(Object key, Object version) throws UnsupportedOperationException {
63 | throw new UnsupportedOperationException("Can't write to a readonly object");
64 | }
65 |
66 | /**
67 | * A no-op since this cache is read-only
68 | */
69 | public void unlockItem(Object key, SoftLock lock) throws CacheException {
70 | //throw new UnsupportedOperationException("Can't write to a readonly object");
71 | }
72 |
73 | /**
74 | * This cache is asynchronous hence a no-op
75 | */
76 | public boolean insert(Object key, Object value, Object version) throws CacheException {
77 | return false;
78 | }
79 |
80 | /**
81 | * {@inheritDoc}
82 | */
83 | public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
84 | cache.put(key, value);
85 | return true;
86 | }
87 |
88 | /**
89 | * Throws UnsupportedOperationException since this cache is read-only
90 | *
91 | * @throws UnsupportedOperationException always
92 | */
93 | public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws UnsupportedOperationException {
94 | throw new UnsupportedOperationException("Can't write to a readonly object");
95 | }
96 |
97 | /**
98 | * Throws UnsupportedOperationException since this cache is read-only
99 | *
100 | * @throws UnsupportedOperationException always
101 | */
102 | public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
103 | throws UnsupportedOperationException {
104 | throw new UnsupportedOperationException("Can't write to a readonly object");
105 | }
106 | }
107 |
108 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/ReadWriteRedisCollectionRegionAcessStrategy.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.region.RedisCollectionRegion;
4 | import org.hibernate.cache.CacheException;
5 | import org.hibernate.cache.spi.CollectionRegion;
6 | import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
7 | import org.hibernate.cache.spi.access.SoftLock;
8 | import org.hibernate.cfg.Settings;
9 | import sun.reflect.generics.reflectiveObjects.NotImplementedException;
10 |
11 | /**
12 | * User: jtlee
13 | * Date: 3/5/13
14 | * Time: 1:50 PM
15 | */
16 | public class ReadWriteRedisCollectionRegionAcessStrategy extends AbstractReadWriteRedisAccessStrategy implements CollectionRegionAccessStrategy {
17 |
18 | /**
19 | * Create an access strategy wrapping the given region.
20 | */
21 | ReadWriteRedisCollectionRegionAcessStrategy(RedisCollectionRegion region, Settings settings) {
22 | super(region, settings);
23 | }
24 |
25 | @Override
26 | public CollectionRegion getRegion() {
27 | return region;
28 | }
29 |
30 | @Override
31 | public SoftLock lockItem(Object key, Object version) throws CacheException {
32 | //Do not support client-side locking
33 | return null;
34 | }
35 |
36 | @Override
37 | public void unlockItem(Object key, SoftLock lock) throws CacheException {
38 | //Do not support client-side locking
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/ReadWriteRedisEntityRegionAcessStrategy.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.region.RedisEntityRegion;
4 | import org.hibernate.cache.CacheException;
5 | import org.hibernate.cache.spi.EntityRegion;
6 | import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
7 | import org.hibernate.cache.spi.access.SoftLock;
8 | import org.hibernate.cfg.Settings;
9 |
10 | /**
11 | * User: jtlee
12 | * Date: 3/5/13
13 | * Time: 2:52 PM
14 | */
15 | public class ReadWriteRedisEntityRegionAcessStrategy extends AbstractReadWriteRedisAccessStrategy implements EntityRegionAccessStrategy {
16 |
17 | /**
18 | * Create an access strategy wrapping the given region.
19 | */
20 | ReadWriteRedisEntityRegionAcessStrategy(RedisEntityRegion region, Settings settings) {
21 | super(region, settings);
22 | }
23 |
24 |
25 |
26 | @Override
27 | public SoftLock lockItem(Object key, Object version) throws CacheException {
28 | //Do not support client side lock
29 | return null;
30 | }
31 |
32 | @Override
33 | public void unlockItem(Object key, SoftLock lock) throws CacheException {
34 | //Do not support client side lock
35 | }
36 |
37 | @Override
38 | public EntityRegion getRegion() {
39 | return region;
40 | }
41 |
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/RedisAccessStrategyFactory.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.region.RedisCollectionRegion;
4 | import net.daum.clix.hibernate.redis.region.RedisEntityRegion;
5 | import org.hibernate.cache.spi.access.AccessType;
6 | import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
7 | import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
8 |
9 | /**
10 | * Factory to create {@link EntityRegionAccessStrategy}
11 | *
12 | * @author 84june
13 | */
14 | public interface RedisAccessStrategyFactory {
15 |
16 | /**
17 | * Create {@link EntityRegionAccessStrategy} for the input {@link RedisEntityRegion} and {@link AccessType}
18 | *
19 | * @param entityRegion
20 | * @param accessType
21 | * @return the created {@link EntityRegionAccessStrategy}
22 | */
23 | public EntityRegionAccessStrategy createEntityRegionAccessStrategy(RedisEntityRegion entityRegion, AccessType accessType);
24 |
25 | /**
26 | * Create {@link CollectionRegionAccessStrategy} for the input {@link RedisCollectionRegion} and {@link AccessType}
27 | *
28 | * @param collectionRegion
29 | * @param accessType
30 | * @return the created {@link CollectionRegionAccessStrategy}
31 | */
32 | public CollectionRegionAccessStrategy createCollectionRegionAccessStrategy(RedisCollectionRegion collectionRegion,
33 | AccessType accessType);
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/net/daum/clix/hibernate/redis/strategy/RedisAccessStrategyFactoryImpl.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.hibernate.redis.strategy;
2 |
3 | import net.daum.clix.hibernate.redis.region.RedisCollectionRegion;
4 | import net.daum.clix.hibernate.redis.region.RedisEntityRegion;
5 | import org.hibernate.cache.spi.access.AccessType;
6 | import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
7 | import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | /**
12 | * An implementation of {@link RedisAccessStrategyFactory}
13 | *
14 | * @author 84june
15 | */
16 | public class RedisAccessStrategyFactoryImpl implements RedisAccessStrategyFactory {
17 |
18 | private final Logger LOG = LoggerFactory.getLogger(getClass());
19 |
20 | @Override
21 | public EntityRegionAccessStrategy createEntityRegionAccessStrategy(RedisEntityRegion entityRegion, AccessType accessType) {
22 | LOG.debug("called createEntityRegionAccessStrategy by accessType:{}", accessType);
23 |
24 | if (AccessType.READ_ONLY.equals(accessType)) {
25 | return new ReadOnlyRedisEntityRegionAccessStrategy(entityRegion, entityRegion.getSettings());
26 | } else if (AccessType.NONSTRICT_READ_WRITE.equals(accessType)) {
27 | return new NonStrictReadWriteRedisEntityRegionAccessStrategy(entityRegion, entityRegion.getSettings());
28 | } else if (AccessType.READ_WRITE.equals(accessType)){
29 | return new ReadWriteRedisEntityRegionAcessStrategy(entityRegion, entityRegion.getSettings());
30 | }
31 |
32 | throw new UnsupportedOperationException("Hibernate-redis supports READ_ONLY and NONSTRICT_READ_WRITE as concurrency strategies only.");
33 | }
34 |
35 | @Override
36 | public CollectionRegionAccessStrategy createCollectionRegionAccessStrategy(RedisCollectionRegion collectionRegion, AccessType accessType) {
37 | LOG.debug("called createCollectionRegionAccessStrategy by accessType:{}", accessType);
38 | if (AccessType.READ_ONLY.equals(accessType)) {
39 | return new ReadOnlyRedisCollectionRegionAccessStrategy(collectionRegion, collectionRegion.getSettings());
40 | } else if (AccessType.NONSTRICT_READ_WRITE.equals(accessType)) {
41 | return new NonStrictReadWriteRedisCollectionRegionAccessStrategy(collectionRegion, collectionRegion.getSettings());
42 | } else if (AccessType.READ_WRITE.equals(accessType)) {
43 | return new ReadWriteRedisCollectionRegionAcessStrategy(collectionRegion, collectionRegion.getSettings());
44 | }
45 |
46 | throw new UnsupportedOperationException("Hibernate-redis supports READ_ONLY and NONSTRICT_READ_WRITE as concurrency strategies only.");
47 | }
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/src/test/java/net/daum/clix/Campaign.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix;
2 |
3 | import org.hibernate.annotations.Cache;
4 | import org.hibernate.annotations.CacheConcurrencyStrategy;
5 |
6 | import javax.persistence.Cacheable;
7 | import javax.persistence.Entity;
8 | import javax.persistence.GeneratedValue;
9 | import javax.persistence.Id;
10 |
11 | /**
12 | * Created with IntelliJ IDEA.
13 | * User: jtlee
14 | * Date: 8/10/12
15 | * Time: 4:20 PM
16 | * To change this template use File | Settings | File Templates.
17 | */
18 | @Cacheable
19 | @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
20 | @Entity
21 | public class Campaign {
22 | private Long seq;
23 | private String name;
24 | private Long budget;
25 |
26 | @Id
27 | @GeneratedValue
28 | public Long getSeq() {
29 | return seq;
30 | }
31 |
32 | public void setSeq(Long seq) {
33 | this.seq = seq;
34 | }
35 |
36 | public String getName() {
37 | return name;
38 | }
39 |
40 | public void setName(String name) {
41 | this.name = name;
42 | }
43 |
44 | public Long getBudget() {
45 | return budget;
46 | }
47 |
48 | public void setBudget(Long budget) {
49 | this.budget = budget;
50 | }
51 |
52 | @Override
53 | public String toString() {
54 | return seq + ":\t" + name + ":\t" + budget;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/java/net/daum/clix/test/CampaignTest.java:
--------------------------------------------------------------------------------
1 | package net.daum.clix.test;
2 |
3 | import net.daum.clix.Campaign;
4 | import org.hibernate.Criteria;
5 | import org.hibernate.Session;
6 | import org.hibernate.SessionFactory;
7 | import org.hibernate.Transaction;
8 | import org.hibernate.cfg.Configuration;
9 | import org.hibernate.criterion.Order;
10 | import org.hibernate.criterion.Restrictions;
11 | import org.junit.AfterClass;
12 | import org.junit.Before;
13 | import org.junit.BeforeClass;
14 | import org.junit.Test;
15 | import org.junit.internal.runners.JUnit4ClassRunner;
16 | import org.junit.runner.RunWith;
17 | import redis.clients.jedis.Jedis;
18 | import redis.clients.jedis.JedisPool;
19 | import redis.clients.jedis.JedisPoolConfig;
20 |
21 | import java.util.List;
22 |
23 | import static junit.framework.Assert.assertFalse;
24 | import static org.junit.Assert.assertNotNull;
25 | import static org.junit.Assert.assertTrue;
26 |
27 | /**
28 | * User: jtlee
29 | * Date: 8/10/12
30 | * Time: 4:29 PM
31 | */
32 | @RunWith(JUnit4ClassRunner.class)
33 | public class CampaignTest {
34 |
35 | private static SessionFactory sessionFactory;
36 |
37 | @Test
38 | public void testSave() {
39 |
40 | Session session = sessionFactory.getCurrentSession();
41 |
42 | Transaction tx = session.beginTransaction();
43 |
44 | Campaign campaign = new Campaign();
45 | campaign.setName("campaign");
46 | campaign.setBudget(1000L);
47 | Long id = (Long) session.save(campaign);
48 |
49 | tx.commit();
50 |
51 | }
52 |
53 | @BeforeClass
54 | public static void setUp() {
55 |
56 | sessionFactory = new Configuration().configure().buildSessionFactory();
57 |
58 | Session session = sessionFactory.getCurrentSession();
59 |
60 | Transaction tx = session.beginTransaction();
61 |
62 | Campaign campaign = new Campaign();
63 | campaign.setName("campaign2");
64 | campaign.setBudget(1000L);
65 | Long id = (Long) session.save(campaign);
66 |
67 | tx.commit();
68 | }
69 |
70 | @Test
71 | public void testSelect() {
72 |
73 | Session session = sessionFactory.getCurrentSession();
74 |
75 | Transaction tx = session.beginTransaction();
76 |
77 | Campaign campaign = (Campaign) session.get(Campaign.class, 1L);
78 |
79 | tx.commit();
80 |
81 | assertNotNull(campaign);
82 |
83 | }
84 |
85 | @Test
86 | public void testQueryCache(){
87 | Session session = sessionFactory.getCurrentSession();
88 |
89 | Transaction tx = session.beginTransaction();
90 |
91 | Criteria criteria = session.createCriteria(Campaign.class);
92 | criteria.add(Restrictions.like("name", "campaign%"));
93 | criteria.addOrder(Order.asc("name"));
94 | criteria.setFirstResult(0);
95 | criteria.setMaxResults(10);
96 | criteria.setCacheable(true);
97 | // criteria.setCacheRegion("@Sorted_queryCache");
98 | List campaigns = criteria.list();
99 |
100 | tx.commit();
101 |
102 | assertFalse("It should not be empty",campaigns.isEmpty());
103 | }
104 |
105 | @Test
106 | public void testCachedQuery(){
107 | Session session = sessionFactory.getCurrentSession();
108 |
109 | Transaction tx = session.beginTransaction();
110 |
111 | Criteria criteria = session.createCriteria(Campaign.class);
112 | criteria.add(Restrictions.like("name", "campaign%"));
113 | criteria.addOrder(Order.asc("name"));
114 | criteria.setFirstResult(0);
115 | criteria.setMaxResults(10);
116 | criteria.setCacheable(true);
117 | // criteria.setCacheRegion("@Sorted_queryCache");
118 | List campaigns = criteria.list();
119 |
120 | tx.commit();
121 |
122 | assertFalse("It should not be empty",campaigns.isEmpty());
123 |
124 | }
125 |
126 | @Test
127 | public void testEvictCachedQuery(){
128 |
129 | Session session = sessionFactory.getCurrentSession();
130 |
131 | Transaction tx = session.beginTransaction();
132 |
133 | Campaign campaign = (Campaign) session.get(Campaign.class, 1L);
134 | campaign.setName("kampaign100");
135 | session.saveOrUpdate(campaign);
136 |
137 | Criteria criteria = session.createCriteria(Campaign.class);
138 | criteria.add(Restrictions.like("name", "campaign%"));
139 | criteria.addOrder(Order.asc("name"));
140 | criteria.setFirstResult(0);
141 | criteria.setMaxResults(10);
142 | criteria.setCacheable(true);
143 | // criteria.setCacheRegion("@Sorted_queryCache");
144 | List campaigns = criteria.list();
145 |
146 | tx.rollback();
147 |
148 | assertFalse("It should not be empty",campaigns.isEmpty());
149 | }
150 |
151 | @AfterClass
152 | public static void tearDown(){
153 | // JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");
154 | // Jedis jedis = pool.getResource();
155 | // jedis.flushDB();
156 | }
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/src/test/resources/hibernate.cfg.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | jdbc:hsqldb:file:db/hsqltestdb;shutdown=true
8 | sa
9 |
10 | org.hsqldb.jdbcDriver
11 | org.hibernate.dialect.HSQLDialect
12 |
13 | true
14 |
15 | true
16 | create
17 |
23 |
24 | 0
25 | thread
26 | true
27 | true
28 | 10000
29 | net.daum.clix.hibernate.redis.RedisRegionFactory
30 |
31 | localhost
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # Direct log messages to stdout
2 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
3 | log4j.appender.stdout.Target=System.out
4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
5 | log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
6 |
7 | # Root logger option
8 | log4j.rootLogger=INFO, stdout
9 |
10 | # Hibernate logging options (INFO only shows startup messages)
11 | log4j.logger.org.hibernate=INFO
12 |
13 | # Log JDBC bind parameter runtime arguments
14 | log4j.logger.org.hibernate.type=trace
--------------------------------------------------------------------------------