KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > rift > coad > lib > bean > TransactionProxyCache


1 /*
2  * CoadunationLib: The coaduntion implementation library.
3  * Copyright (C) 2006 Rift IT Contracting
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * TransactionProxyCache.java
20  */

21
22 // package path
23
package com.rift.coad.lib.bean;
24
25 // java imports
26
import java.util.ArrayList JavaDoc;
27 import java.util.Date JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Vector JavaDoc;
33 import java.util.concurrent.ConcurrentHashMap JavaDoc;
34 import javax.rmi.PortableRemoteObject JavaDoc;
35 import javax.transaction.xa.XAException JavaDoc;
36 import javax.transaction.xa.XAResource JavaDoc;
37 import javax.transaction.xa.Xid JavaDoc;
38
39 // logging import
40
import org.apache.log4j.Logger;
41
42 // coadunation imports
43
import com.rift.coad.lib.cache.Cache;
44 import com.rift.coad.lib.cache.CacheEntry;
45 import com.rift.coad.lib.common.RandomGuid;
46 import com.rift.coad.lib.configuration.ConfigurationFactory;
47 import com.rift.coad.lib.configuration.Configuration;
48 import com.rift.coad.lib.thread.ThreadStateMonitor;
49 import com.rift.coad.util.lock.LockRef;
50 import com.rift.coad.util.lock.ObjectLockFactory;
51 import com.rift.coad.util.transaction.TransactionManager;
52
53
54 /**
55  * This object acts as the transaction proxy cache for the container.
56  *
57  * @author Brett Chaldecott
58  */

59 public class TransactionProxyCache implements Cache,XAResource JavaDoc {
60     
61     /**
62      * This object tracks the changes for a transaction
63      */

64     public class ChangeEntry {
65         // private member variables
66
private Xid JavaDoc transactionId = null;
67         private List JavaDoc newEntries = new ArrayList JavaDoc();
68         
69         
70         /**
71          * The constructor of the change entry
72          *
73          * @param transactionId The id of the transaction.
74          */

75         public ChangeEntry(Xid JavaDoc transactionId) {
76             this.transactionId = transactionId;
77         }
78         
79         
80         /**
81          * This method returns the transaction id.
82          *
83          * @return The object containing the transaction id.
84          */

85         public Xid JavaDoc getTransactionId() {
86             return transactionId;
87         }
88         
89         
90         /**
91          * This method addes the cache entry.
92          *
93          * @param entry The proxy cache entry to add.
94          */

95         public void addEntry(ProxyCacheEntry entry) {
96             newEntries.add(entry);
97         }
98         
99         
100         /**
101          * This method returns the list of added entries.
102          */

103         public List JavaDoc getEntries() {
104             return newEntries;
105         }
106     }
107     
108     // class constants
109
private final static String JavaDoc CACHE_EXPIRY_TIME = "proxy_cache_expiry";
110     private final static long CACHE_EXPIRY_TIME_DEFAULT = 60 * 1000;
111     
112     // private member variables
113
protected static Logger log =
114             Logger.getLogger(ProxyCache.class.getName());
115     
116     // private member variables
117
private ThreadLocal JavaDoc currentTransaction = new ThreadLocal JavaDoc();
118     private ThreadStateMonitor status = new ThreadStateMonitor();
119     private Map JavaDoc cacheEntries = new ConcurrentHashMap JavaDoc();
120     private long defaultCacheExpiryTime = 0;
121     private Map JavaDoc transactionChanges = new ConcurrentHashMap JavaDoc();
122     
123     
124     /**
125      * Creates a new instance of TransactionProxyCache
126      */

127     public TransactionProxyCache() throws BeanException {
128         try {
129             Configuration config = ConfigurationFactory.getInstance().
130                     getConfig(ProxyCache.class);
131             defaultCacheExpiryTime = config.getLong(CACHE_EXPIRY_TIME,
132                     CACHE_EXPIRY_TIME_DEFAULT);
133         } catch (Exception JavaDoc ex) {
134             log.error("Failed to start the TransactionProxyCache object " +
135                     "because : " + ex.getMessage(),ex);
136             throw new BeanException(
137                     "Failed to start the TransactionProxyCache object " +
138                     "because : " + ex.getMessage(),ex);
139         }
140     }
141     
142     
143     /**
144      * This method is called to perform garbage collection on the cache entries.
145      */

146     public void garbageCollect() {
147         Map JavaDoc cacheEntries = new HashMap JavaDoc();
148         cacheEntries.putAll(this.cacheEntries);
149         
150         // the start time
151
Date JavaDoc currentTime = new Date JavaDoc();
152         for (Iterator JavaDoc iter = cacheEntries.keySet().iterator();
153                 iter.hasNext();) {
154             Object JavaDoc key = iter.next();
155             ProxyCacheEntry cacheEntry =
156                     (ProxyCacheEntry)cacheEntries.get(key);
157             if (cacheEntry.isExpired(currentTime)) {
158                 synchronized(this.cacheEntries) {
159                     this.cacheEntries.remove(key);
160                 }
161                 cacheEntry.cacheRelease();
162             }
163         }
164     }
165     
166     
167     /**
168      * This method is called to forcibly remove everything from the cache.
169      */

170     public void clear() {
171         LockRef lockRef = null;
172         try {
173             lockRef = ObjectLockFactory.getInstance().acquireReadLock(this);
174             Map JavaDoc cacheEntries = new HashMap JavaDoc();
175             status.terminate(false);
176             cacheEntries.putAll(this.cacheEntries);
177             this.cacheEntries.clear();
178
179             for (Iterator JavaDoc iter = cacheEntries.keySet().iterator();
180                     iter.hasNext();) {
181                 ProxyCacheEntry cacheEntry =
182                         (ProxyCacheEntry)cacheEntries.get(iter.next());
183                 try {
184                     cacheEntry.cacheRelease();
185                 } catch (Exception JavaDoc ex) {
186                     log.error("Failed to release the cache entry : " +
187                             ex.getMessage(),ex);
188                 }
189             }
190         } catch (Exception JavaDoc ex) {
191             log.error("Failed clear the cache : " + ex.getMessage(),ex);
192         } finally {
193             try {
194                 if (lockRef != null) {
195                     lockRef.release();
196                 }
197             } catch (Exception JavaDoc ex) {
198                 log.error("Failed to release the lock : " +
199                         ex.getMessage(),ex);
200             }
201         }
202     }
203     
204     
205     /**
206      * This method adds a new entry to the proxy cache.
207      *
208      * @param timeout The timeout for this object.
209      * @param proxy The proxy to add to the cache.
210      * @param handler The handler to perform the check for.
211      */

212     public void addCacheEntry(long timeout, Object JavaDoc proxy, CacheEntry handler)
213             throws BeanException {
214         try {
215             checkStatus();
216             TransactionManager.getInstance().bindResource(this,false);
217             long cacheTimeout = timeout;
218             if (timeout == -1) {
219                 cacheTimeout = defaultCacheExpiryTime;
220             }
221             ProxyCacheEntry newEntry = new ProxyCacheEntry(timeout,
222                     proxy, handler);
223             ChangeEntry changeEntry = (ChangeEntry)transactionChanges.get(
224                     currentTransaction.get());
225             changeEntry.addEntry(newEntry);
226         } catch (Exception JavaDoc ex) {
227             log.error("Failed to add the cache entry : " +
228                     ex.getMessage(),ex);
229             throw new BeanException("Failed to add the cache entry : " +
230                     ex.getMessage(),ex);
231         }
232     }
233     
234     
235     /**
236      * This mehtod returns true if the cache contains the checked entry.
237      *
238      * @return TRUE if the cache contains the checked entry.
239      * @param cacheEntry The entry to perform the check for.
240      */

241     public boolean contains(Object JavaDoc cacheEntry) {
242         if (!status.isTerminated()) {
243             return cacheEntries.containsKey(cacheEntry);
244         }
245         return false;
246     }
247     
248     
249     /**
250      * This method returns the bean cache entry.
251      *
252      * @return The reference to the bean cache object.
253      * @param key The key to retrieve.
254      * @exception BeanException
255      */

256     public void commit(Xid JavaDoc xid, boolean b) throws XAException JavaDoc {
257         try {
258             ChangeEntry changeEntry = (ChangeEntry)transactionChanges.get(xid);
259             List JavaDoc entries = changeEntry.getEntries();
260             for (Iterator JavaDoc iter = entries.iterator(); iter.hasNext();) {
261                 ProxyCacheEntry proxyCacheEntry = (ProxyCacheEntry)iter.next();
262                 cacheEntries.put(proxyCacheEntry.getCacheEntry(),
263                         proxyCacheEntry);
264             }
265         } catch (Exception JavaDoc ex) {
266             log.error("Failed to commit the changes : " + ex.getMessage(),ex);
267             throw new XAException JavaDoc("Failed to commit the changes : " +
268                     ex.getMessage());
269         }
270     }
271     
272     
273     /**
274      * The resource manager has dissociated this object from the transaction.
275      *
276      * @param xid The id of the transaction that is getting ended.
277      * @param flags The flags associated with this operation.
278      * @exception XAException
279      */

280     public void end(Xid JavaDoc xid, int i) throws XAException JavaDoc {
281     }
282     
283     
284     /**
285      * The transaction has been completed and must be forgotten.
286      *
287      * @param xid The id of the transaction to forget.
288      * @exception XAException
289      */

290     public void forget(Xid JavaDoc xid) throws XAException JavaDoc {
291         try {
292             transactionChanges.remove(xid);
293         } catch (Exception JavaDoc ex) {
294             log.error("Failed to forget the changes : " + ex.getMessage(),ex);
295             throw new XAException JavaDoc("Failed to forget the changes : " +
296                     ex.getMessage());
297         }
298     }
299     
300     
301     /**
302      * This method returns the transaction timeout for this object.
303      *
304      * @return The int containing the transaction timeout.
305      * @exception XAException
306      */

307     public int getTransactionTimeout() throws XAException JavaDoc {
308         return -1;
309     }
310     
311     
312     /**
313      * This method returns true if this object is the resource manager getting
314      * queried.
315      *
316      * @return TRUE if this is the resource manager, FALSE if not.
317      * @param xaResource The resource to perform the check against.
318      * @exception XAException
319      */

320     public boolean isSameRM(XAResource JavaDoc xAResource) throws XAException JavaDoc {
321         return this == xAResource;
322     }
323     
324     
325     /**
326      * This is called before a transaction is committed.
327      *
328      * @return The results of the transaction.
329      * @param xid The id of the transaction to check against.
330      * @exception XAException
331      */

332     public int prepare(Xid JavaDoc xid) throws XAException JavaDoc {
333         return XAResource.XA_OK;
334     }
335     
336     
337     /**
338      * This method returns the list of transaction branches for this resource
339      * manager.
340      *
341      * @return The list of resource branches.
342      * @param flags The flags
343      * @exception XAException
344      */

345     public Xid JavaDoc[] recover(int i) throws XAException JavaDoc {
346         return null;
347     }
348     
349     
350     /**
351      * This method is called to roll back the specified transaction.
352      *
353      * @param xid The id of the transaction to roll back.
354      * @exception XAException
355      */

356     public void rollback(Xid JavaDoc xid) throws XAException JavaDoc {
357         try {
358             ChangeEntry changeEntry = (ChangeEntry)transactionChanges.get(xid);
359             List JavaDoc entries = changeEntry.getEntries();
360             for (Iterator JavaDoc iter = entries.iterator(); iter.hasNext();) {
361                 ProxyCacheEntry proxyCacheEntry = (ProxyCacheEntry)iter.next();
362                 try {
363                     proxyCacheEntry.cacheRelease();
364                 } catch (Exception JavaDoc ex) {
365                     log.error("Failed to release the entry");
366                 }
367             }
368             transactionChanges.remove(xid);
369         } catch (Exception JavaDoc ex) {
370             log.error("Failed to rollback the changes : " + ex.getMessage(),ex);
371             throw new XAException JavaDoc("Failed to rollback the changes : " +
372                     ex.getMessage());
373         }
374     }
375     
376     /**
377      * This method sets the transaction timeout for this resource manager.
378      *
379      * @return TRUE if the transaction timeout can be set successfully.
380      * @param transactionTimeout The new transaction timeout value.
381      * @exception XAException
382      */

383     public boolean setTransactionTimeout(int i) throws XAException JavaDoc {
384         return true;
385     }
386     
387     
388     /**
389      * This method is called to start a transaction on a resource manager.
390      *
391      * @param xid The id of the new transaction.
392      * @param flags The flags associated with the transaction.
393      * @exception XAException
394      */

395     public void start(Xid JavaDoc xid, int i) throws XAException JavaDoc {
396         if (!transactionChanges.containsKey(xid)) {
397             transactionChanges.put(xid,new ChangeEntry(xid));
398         }
399         currentTransaction.set(xid);
400     }
401     
402     /**
403      * This method will check to see if the cache has been terminated or not.
404      *
405      * @exception BeanException
406      */

407     private void checkStatus() throws BeanException {
408         if (status.isTerminated()) {
409             throw new BeanException("The proxy cache has been shut down.");
410         }
411     }
412 }
413
Popular Tags