KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > rift > coad > lib > deployment > rmi > TransactionRMICache


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  * TransactionRMICache.java
20  */

21
22 // package path
23
package com.rift.coad.lib.deployment.rmi;
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.concurrent.ConcurrentHashMap JavaDoc;
33 import javax.rmi.PortableRemoteObject JavaDoc;
34 import javax.transaction.xa.XAException JavaDoc;
35 import javax.transaction.xa.XAResource JavaDoc;
36 import javax.transaction.xa.Xid JavaDoc;
37
38 // logging import
39
import org.apache.log4j.Logger;
40
41 // coad imports
42
import com.rift.coad.lib.cache.Cache;
43 import com.rift.coad.lib.cache.CacheEntry;
44 import com.rift.coad.lib.common.RandomGuid;
45 import com.rift.coad.lib.configuration.ConfigurationFactory;
46 import com.rift.coad.lib.configuration.Configuration;
47 import com.rift.coad.lib.thread.ThreadStateMonitor;
48 import com.rift.coad.util.lock.LockRef;
49 import com.rift.coad.util.lock.ObjectLockFactory;
50 import com.rift.coad.util.transaction.TransactionManager;
51
52 /**
53  * This object is responsible for controlling the rmi cache entries bound to
54  * various transactions.
55  *
56  * @author Brett Chaldecott
57  */

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

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

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

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

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

102         public List JavaDoc getEntries() {
103             return newEntries;
104         }
105     }
106     
107     
108     // class constants
109
private final static String JavaDoc CACHE_EXPIRY_TIME = "rmi_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(TransactionRMICache.class.getName());
115     
116     // private member variables
117
private ThreadLocal JavaDoc currentTransaction = new ThreadLocal JavaDoc();
118     private Map JavaDoc cacheEntries = new ConcurrentHashMap JavaDoc();
119     private Map JavaDoc transactionChanges = new ConcurrentHashMap JavaDoc();
120     private long defaultCacheExpiryTime = 0;
121     private ThreadStateMonitor status = new ThreadStateMonitor();
122     
123     
124     /**
125      * Creates a new instance of TransactionRMICache
126      */

127     public TransactionRMICache() {
128     }
129     
130     
131     /**
132      * This method is called to perform garbage collection on the cache entries.
133      */

134     public void garbageCollect() {
135         Map JavaDoc currentEntryList = new HashMap JavaDoc();
136         synchronized (cacheEntries) {
137             currentEntryList.putAll(cacheEntries);
138         }
139         Date JavaDoc expiryDate = new Date JavaDoc();
140         for (Iterator JavaDoc iter = currentEntryList.keySet().iterator(); iter.hasNext();) {
141             Object JavaDoc key = iter.next();
142             RMICacheEntry cacheEntry = (RMICacheEntry)currentEntryList.get(key);
143             if (cacheEntry.isExpired(expiryDate)) {
144                 try {
145                     PortableRemoteObject.unexportObject(
146                             cacheEntry.getRemoteInterface());
147                     synchronized(cacheEntries) {
148                         cacheEntries.remove(key);
149                     }
150                     cacheEntry.cacheRelease();
151                 } catch (java.rmi.NoSuchObjectException JavaDoc ex) {
152                     log.warn("The object was never exported : " +
153                             ex.getMessage(),ex);
154                     // remove from cache
155
synchronized(cacheEntries) {
156                         cacheEntries.remove(key);
157                     }
158                     cacheEntry.cacheRelease();
159                 } catch (Exception JavaDoc ex) {
160                     log.error("Failed to remove a cache entry because : " +
161                             ex.getMessage(),ex);
162                 }
163             }
164         }
165     }
166     
167     
168     /**
169      * This method is called to forcibly remove everything from the cache.
170      */

171     public void clear() {
172         LockRef lockRef = null;
173         try {
174             lockRef = ObjectLockFactory.getInstance().acquireReadLock(this);
175             status.terminate(false);
176             Map JavaDoc currentEntryList = new HashMap JavaDoc();
177             synchronized (cacheEntries) {
178                 currentEntryList.putAll(cacheEntries);
179                 cacheEntries.clear();
180             }
181             for (Iterator JavaDoc iter = currentEntryList.keySet().iterator();
182             iter.hasNext();) {
183                 Object JavaDoc key = iter.next();
184                 RMICacheEntry cacheEntry =
185                         (RMICacheEntry)currentEntryList.get(key);
186                 try {
187                     PortableRemoteObject.unexportObject(
188                             cacheEntry.getRemoteInterface());
189                 } catch (java.rmi.NoSuchObjectException JavaDoc ex) {
190                     log.warn("The object was never exported : " +
191                             ex.getMessage(),ex);
192                 } catch (Exception JavaDoc ex) {
193                     log.error("Failed to remove a cache entry because : " +
194                             ex.getMessage(),ex);
195                 }
196                 try {
197                     cacheEntry.cacheRelease();
198                 } catch (Exception JavaDoc ex) {
199                     log.error("Failed to release cache info : " +
200                             ex.getMessage(),ex);
201                 }
202             }
203         } catch (Exception JavaDoc ex) {
204             log.error("Failed clear the cache : " + ex.getMessage(),ex);
205         } finally {
206             try {
207                 if (lockRef != null) {
208                     lockRef.release();
209                 }
210             } catch (Exception JavaDoc ex) {
211                 log.error("Failed to release the lock : " +
212                         ex.getMessage(),ex);
213             }
214         }
215     }
216     
217     
218     /**
219      * This method is responsible for adding an entry to the cache.
220      *
221      * @param entry The entry to add to the cache.
222      */

223     public void addCacheEntry(long timeout, CacheEntry entry) throws
224             RMIException {
225         try {
226             checkStatus();
227             TransactionManager.getInstance().bindResource(this,false);
228             long cacheTimeout = timeout;
229             if (timeout == -1) {
230                 cacheTimeout = defaultCacheExpiryTime;
231             }
232             RMICacheEntry newEntry = new RMICacheEntry(cacheTimeout,entry);
233             ChangeEntry changeEntry = (ChangeEntry)transactionChanges.get(
234                     currentTransaction.get());
235             changeEntry.addEntry(newEntry);
236         } catch (Exception JavaDoc ex) {
237             log.error("Failed to add the cache entry : " +
238                     ex.getMessage(),ex);
239             throw new RMIException("Failed to add the cache entry : " +
240                     ex.getMessage(),ex);
241         }
242     }
243     
244     
245     /**
246      * This method will check to see if the cache has been terminated or not.
247      *
248      * @exception BeanException
249      */

250     private void checkStatus() throws RMIException {
251         if (status.isTerminated()) {
252             throw new RMIException("The RMI cache has been shut down.");
253         }
254     }
255     
256     
257     /**
258      * This mehtod returns true if the cache contains the checked entry.
259      *
260      * @return TRUE if the cache contains the checked entry.
261      * @param cacheEntry The entry to perform the check for.
262      */

263     public boolean contains(Object JavaDoc cacheEntry) {
264         if (!status.isTerminated()) {
265             return cacheEntries.containsKey(cacheEntry);
266         }
267         return false;
268     }
269     
270     
271     /**
272      * This method returns the bean cache entry.
273      *
274      * @return The reference to the bean cache object.
275      * @param key The key to retrieve.
276      * @exception BeanException
277      */

278     public void commit(Xid JavaDoc xid, boolean b) throws XAException JavaDoc {
279         try {
280             ChangeEntry changeEntry = (ChangeEntry)transactionChanges.get(xid);
281             List JavaDoc entries = changeEntry.getEntries();
282             for (Iterator JavaDoc iter = entries.iterator(); iter.hasNext();) {
283                 RMICacheEntry rmiCacheEntry = (RMICacheEntry)iter.next();
284                 cacheEntries.put(rmiCacheEntry.getCacheEntry(),rmiCacheEntry);
285             }
286         } catch (Exception JavaDoc ex) {
287             log.error("Failed to commit the changes : " + ex.getMessage(),ex);
288             throw new XAException JavaDoc("Failed to commit the changes : " +
289                     ex.getMessage());
290         }
291     }
292     
293     
294     /**
295      * The resource manager has dissociated this object from the transaction.
296      *
297      * @param xid The id of the transaction that is getting ended.
298      * @param flags The flags associated with this operation.
299      * @exception XAException
300      */

301     public void end(Xid JavaDoc xid, int i) throws XAException JavaDoc {
302     }
303     
304     
305     /**
306      * The transaction has been completed and must be forgotten.
307      *
308      * @param xid The id of the transaction to forget.
309      * @exception XAException
310      */

311     public void forget(Xid JavaDoc xid) throws XAException JavaDoc {
312         try {
313             transactionChanges.remove(xid);
314         } catch (Exception JavaDoc ex) {
315             log.error("Failed to forget the changes : " + ex.getMessage(),ex);
316             throw new XAException JavaDoc("Failed to forget the changes : " +
317                     ex.getMessage());
318         }
319     }
320     
321     
322     /**
323      * This method returns the transaction timeout for this object.
324      *
325      * @return The int containing the transaction timeout.
326      * @exception XAException
327      */

328     public int getTransactionTimeout() throws XAException JavaDoc {
329         return -1;
330     }
331     
332     
333     /**
334      * This method returns true if this object is the resource manager getting
335      * queried.
336      *
337      * @return TRUE if this is the resource manager, FALSE if not.
338      * @param xaResource The resource to perform the check against.
339      * @exception XAException
340      */

341     public boolean isSameRM(XAResource JavaDoc xAResource) throws XAException JavaDoc {
342         return this == xAResource;
343     }
344     
345     
346     /**
347      * This is called before a transaction is committed.
348      *
349      * @return The results of the transaction.
350      * @param xid The id of the transaction to check against.
351      * @exception XAException
352      */

353     public int prepare(Xid JavaDoc xid) throws XAException JavaDoc {
354         return XAResource.XA_OK;
355     }
356     
357     
358     /**
359      * This method returns the list of transaction branches for this resource
360      * manager.
361      *
362      * @return The list of resource branches.
363      * @param flags The flags
364      * @exception XAException
365      */

366     public Xid JavaDoc[] recover(int i) throws XAException JavaDoc {
367         return null;
368     }
369     
370     
371     /**
372      * This method is called to roll back the specified transaction.
373      *
374      * @param xid The id of the transaction to roll back.
375      * @exception XAException
376      */

377     public void rollback(Xid JavaDoc xid) throws XAException JavaDoc {
378         try {
379             ChangeEntry changeEntry = (ChangeEntry)transactionChanges.get(xid);
380             List JavaDoc entries = changeEntry.getEntries();
381             for (Iterator JavaDoc iter = entries.iterator(); iter.hasNext();) {
382                 RMICacheEntry rmiCacheEntry = (RMICacheEntry)iter.next();
383                 try {
384                     PortableRemoteObject.unexportObject(
385                             rmiCacheEntry.getRemoteInterface());
386                 } catch (java.rmi.NoSuchObjectException JavaDoc ex) {
387                     log.warn("The object was never exported : " +
388                             ex.getMessage(),ex);
389                 } catch (Exception JavaDoc ex) {
390                     log.error("Failed to rollback a cache entry because : " +
391                             ex.getMessage(),ex);
392                 }
393                 try {
394                     rmiCacheEntry.cacheRelease();
395                 } catch (Exception JavaDoc ex) {
396                     log.error("Failed to release the entry");
397                 }
398             }
399             transactionChanges.remove(xid);
400         } catch (Exception JavaDoc ex) {
401             log.error("Failed to rollback the changes : " + ex.getMessage(),ex);
402             throw new XAException JavaDoc("Failed to rollback the changes : " +
403                     ex.getMessage());
404         }
405     }
406     
407     
408     /**
409      * This method sets the transaction timeout for this resource manager.
410      *
411      * @return TRUE if the transaction timeout can be set successfully.
412      * @param transactionTimeout The new transaction timeout value.
413      * @exception XAException
414      */

415     public boolean setTransactionTimeout(int i) throws XAException JavaDoc {
416         return true;
417     }
418     
419     
420     /**
421      * This method is called to start a transaction on a resource manager.
422      *
423      * @param xid The id of the new transaction.
424      * @param flags The flags associated with the transaction.
425      * @exception XAException
426      */

427     public void start(Xid JavaDoc xid, int i) throws XAException JavaDoc {
428         if (!transactionChanges.containsKey(xid)) {
429             transactionChanges.put(xid,new ChangeEntry(xid));
430         }
431         currentTransaction.set(xid);
432     }
433     
434 }
435
Popular Tags