1 /***
2 *
3 * Copyright 2004 Protique Ltd
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 **/
18 package org.codehaus.activespace.cache;
19
20 import org.codehaus.activespace.cache.impl.CompositeCacheCommand;
21 import org.codehaus.activespace.cache.impl.NullTransactionRegistration;
22 import org.codehaus.activespace.cache.impl.ThreadCache;
23 import org.codehaus.activespace.cache.impl.TransactionRegistration;
24
25 import javax.cache.Cache;
26 import javax.cache.CacheException;
27 import javax.cache.CacheManager;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.Map;
33
34 /***
35 * A {@link CacheManager} which returns {@link TransactionalCache} instances
36 * using some backing {@link Cache} instances. This class also acts as the transaciton
37 *
38 * @version $Revision: 1.12 $
39 */
40 public class TransactionalCacheManager extends CacheManager {
41
42 private Map caches = Collections.synchronizedMap(new HashMap());
43 private TransactionRegistration transactionRegistration = NullTransactionRegistration.getInstance();
44 private Map environment = new HashMap();
45
46
47 /***
48 * Shuts down this class, freeing any resources used up (such as open files or sockets).
49 * One this method has been called this class should not be used again.
50 */
51 public void stop() throws Exception {
52 }
53
54 /***
55 * Creates a new transactional cache
56 */
57 public TransactionalCache createTransactionalCache(String name) throws CacheException {
58 Cache backingCache = createBackingCache(name);
59 return registerCache(caches, backingCache, name);
60 }
61
62 /***
63 * Looks up a cache
64 */
65 public TransactionalCache getTransactionalCache(String name) {
66 TransactionalCache answer = (TransactionalCache) caches.get(name);
67 if (answer == null) {
68 Cache backingCache = getBackingCache(name);
69 if (backingCache != null) {
70 answer = registerCache(caches, backingCache, name);
71 }
72 }
73 return answer;
74 }
75
76 public Cache getCache(String cacheName) {
77 return getTransactionalCache(cacheName);
78 }
79
80 /***
81 * Performs a thread local commit of all operations on all the caches
82 * used in this tranaction.
83 *
84 * @throws TransactionException if the transaction could not be committed
85 * due to an optimistic transaction failure or deadlock.
86 */
87 public void commit() throws TransactionException {
88 Collection caches = getTransactionalCaches();
89 CompositeCacheCommand command = createCommitCommand(caches);
90 if (!command.isEmpty()) {
91 command.run(this);
92 resetLocalChanges(caches);
93 handleCommitException(caches);
94 }
95 }
96
97 /***
98 * Performs rollback of all pending transactions on all the caches
99 * accessed in the current thread.
100 */
101 public void rollback() {
102 Collection caches = getTransactionalCaches();
103 resetLocalChanges(caches);
104 }
105
106
107
108 public TransactionRegistration getTransactionRegistration() {
109 return transactionRegistration;
110 }
111
112 public void setTransactionRegistration(TransactionRegistration transactionRegistration) {
113 this.transactionRegistration = transactionRegistration;
114 }
115
116 public Map getEnvironment() {
117 return environment;
118 }
119
120 public void setEnvironment(Map environment) {
121 this.environment = environment;
122 }
123
124
125
126 protected TransactionalCache registerCache(Map caches, Cache backingCache, String name) {
127 TransactionalCache answer = createTransactionalCache(backingCache, name);
128 answer.setName(name);
129 answer.setTransactionRegistration(getTransactionRegistration());
130 caches.put(name, answer);
131 return answer;
132 }
133
134 protected TransactionalCache createTransactionalCache(Cache backingCache, String name) {
135 return new TransactionalCache(backingCache);
136 }
137
138 protected Collection getTransactionalCaches() {
139 return caches.values();
140 }
141
142 protected Cache getBackingCache(String name) {
143 return super.getCache(name);
144 }
145
146 protected synchronized Cache createBackingCache(String name) throws CacheException {
147 Cache cache = getCacheFactory().createCache(environment);
148 super.registerCache(name, cache);
149 return cache;
150 }
151
152 protected void resetLocalChanges(Collection caches) {
153 for (Iterator iter = caches.iterator(); iter.hasNext();) {
154 TransactionalCache cache = (TransactionalCache) iter.next();
155 if (cache.isModifiedInTransaction()) {
156 cache.resetLocalChanges();
157 }
158 }
159 }
160
161 protected void handleCommitException(Collection caches) {
162 for (Iterator iter = caches.iterator(); iter.hasNext();) {
163 TransactionalCache cache = (TransactionalCache) iter.next();
164 if (cache.isModifiedInTransaction()) {
165 cache.resetLocalChanges();
166 }
167 }
168
169 for (Iterator iter = caches.iterator(); iter.hasNext();) {
170 TransactionalCache cache = (TransactionalCache) iter.next();
171 ThreadCache threadCache = cache.getThreadCache();
172 threadCache.handleCommitException();
173 }
174 }
175
176 protected CompositeCacheCommand createCommitCommand(Collection caches) {
177 CompositeCacheCommand command = new CompositeCacheCommand();
178 for (Iterator iter = caches.iterator(); iter.hasNext();) {
179 TransactionalCache cache = (TransactionalCache) iter.next();
180 if (cache.isModifiedInTransaction()) {
181 command.addCommand(cache.createTransactionCommand());
182 }
183 }
184 return command;
185 }
186 }