KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > cache > interceptors > CreateIfNotExistsInterceptor


1 package org.jboss.cache.interceptors;
2
3 import org.jboss.cache.CacheException;
4 import org.jboss.cache.CacheImpl;
5 import org.jboss.cache.CacheSPI;
6 import org.jboss.cache.Fqn;
7 import org.jboss.cache.GlobalTransaction;
8 import org.jboss.cache.NodeSPI;
9 import org.jboss.cache.marshall.MethodCall;
10 import org.jboss.cache.marshall.MethodCallFactory;
11 import org.jboss.cache.marshall.MethodDeclarations;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.concurrent.locks.ReentrantLock JavaDoc;
16
17 /**
18  * Handles putXXX() methods: if the given node doesn't exist, it will be created
19  * (depending on the create_if_not_exists argument)
20  *
21  * @author Bela Ban
22  * @version $Id: CreateIfNotExistsInterceptor.java,v 1.24 2007/01/04 05:35:37 msurtani Exp $
23  * @deprecated This code is not used anymore and will be removed in a future unlock
24  */

25 public class CreateIfNotExistsInterceptor extends Interceptor
26 {
27
28    private final ReentrantLock JavaDoc put_lock = new ReentrantLock JavaDoc();
29
30    private final ReentrantLock JavaDoc remove_lock = new ReentrantLock JavaDoc();
31
32    private final ArrayList JavaDoc put_list = new ArrayList JavaDoc();
33
34    private final ArrayList JavaDoc remove_list = new ArrayList JavaDoc();
35
36
37    public void setCache(CacheSPI cache)
38    {
39       super.setCache(cache);
40    }
41
42    /* public Object invoke(MethodCall m) throws Throwable {
43
44       // we need to sync here - might have concurrent put() and remove() calls
45       synchronized(this) { // only 1 thread can be here at any time - missing node needs to be created only once
46          if(putMethods.contains(m.getMethod())) {
47             Object[] args=m.getArgs();
48             Fqn fqn=(Fqn)(args != null? args[1] : null);
49             if(fqn == null)
50                throw new CacheException("failed extracting FQN from method " + m);
51             if(!cache.exists(fqn)) {
52                GlobalTransaction gtx=cache.getCurrentTransaction();
53                createNode(fqn, gtx);
54                lock(fqn, DataNode.LOCK_TYPE_WRITE, false);
55                // return super.invoke(m); // we need to execute the locking and put() in the same sync block !
56             }
57          }
58       }
59       return super.invoke(m);
60    }*/

61
62    // /**
63
// * Synchronize between put(), remove() and evict() methods. This is coarse-grained, and should be replaced
64
// * with FQN-based synchronization, e.g. put("/1/2/3" should <em>not</em> synchronize with remove("/a/b/c").
65
// * @param m
66
// * @return
67
// * @throws Throwable
68
// */
69
// public Object invoke(MethodCall m) throws Throwable {
70
// Method meth=m.getMethod();
71
//
72
// boolean isPut=putMethods.contains(meth),
73
// isRemove=CacheImpl.removeNodeMethodLocal.equals(meth),
74
// isEvict=CacheImpl.evictNodeMethodLocal.equals(meth);
75
//
76
// if(isPut || isRemove || isEvict) { // we need to sync put(), remove() and evict() calls
77
// try {
78
// Object[] args=m.getArgs();
79
// Fqn fqn=(Fqn)(args != null? (isEvict? args[0] : args[1]) : null);
80
// if(fqn == null)
81
// throw new CacheException("failed extracting FQN from method " + m);
82
//
83
// lock.lockInterruptibly();
84
// if(isPut) { // lock needs to be held across puts()
85
// if(!cache.exists(fqn)) {
86
// GlobalTransaction gtx=cache.getCurrentTransaction();
87
// if(log.isTraceEnabled())
88
// log.trace("creating node " + fqn);
89
// createNode(fqn, gtx);
90
// // lock(fqn, DataNode.LOCK_TYPE_WRITE, false);
91
// }
92
// else
93
// lock.unlock();
94
// }
95
// return super.invoke(m);
96
// }
97
// finally {
98
// if(lock.holds() > 0)
99
// lock.unlock(); // unlock lock for put()
100
// }
101
// }
102
// return super.invoke(m); // no locks held for non put()/remove()/evict() methods (e.g. for get() methods)
103
// }
104

105
106    /**
107     * Synchronize between put(), remove() and evict() methods. This is coarse-grained, and should be replaced
108     * with FQN-based synchronization, e.g. put("/1/2/3" should <em>not</em> synchronize with remove("/a/b/c").
109     *
110     * @return
111     * @throws Throwable
112     */

113    public Object JavaDoc invoke(MethodCall m) throws Throwable JavaDoc
114    {
115       Fqn fqn;
116       boolean isPut = MethodDeclarations.isPutMethod(m.getMethodId()),
117               isRemove = m.getMethodId() == MethodDeclarations.removeNodeMethodLocal_id,
118               isEvict = m.getMethodId() == MethodDeclarations.evictNodeMethodLocal_id;
119
120       if (isPut || isRemove || isEvict)
121       {// we need to sync put(), remove() and evict() calls
122
Object JavaDoc[] args = m.getArgs();
123          fqn = (Fqn) (args != null ? (isEvict ? args[0] : args[1]) : null);
124          if (fqn == null)
125          {
126             throw new CacheException("failed extracting FQN from method " + m);
127          }
128
129          if (isPut)
130          {// lock needs to be held across puts()
131
try
132             {
133                addFqnToPutList(fqn, put_lock);
134                findAndBlockOnRemove(fqn, remove_lock);
135                if (!cache.getRoot().hasChild(fqn))
136                {
137                   GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
138                   if (log.isTraceEnabled())
139                   {
140                      log.trace("creating node " + fqn);
141                   }
142                   createNode(fqn, gtx);
143                }
144
145                return super.invoke(m);
146             }
147             finally
148             {
149                removeFqnFromPutList(fqn, put_lock);
150             }
151          }
152          else
153          {// remove() or evict(): wait until all puts() that work on the same subtree have completed
154
try
155             {
156                findAndBlockOnPut(fqn, put_lock);// does NOT unlock put_lock !
157
addFqnToRemoveList(fqn, remove_lock);
158                put_lock.unlock();
159                // we only unlock now because waiting on the put-list and adding to remove-list need to be atomic !
160
return super.invoke(m);
161             }
162             finally
163             {
164                if (put_lock.isHeldByCurrentThread())
165                {
166                   put_lock.unlock();
167                }
168                removeFqnFromRemoveList(fqn, remove_lock);
169             }
170          }
171       }
172       return super.invoke(m);
173    }
174
175
176    /**
177     * Finds all FQNs in the put_list form which <code>fqn</code> is a parent (or equals), and waits on them.
178     * Loops until no more matching FQNs are found or the list is empty.<p/>
179     * <em>Don't</em> unlock the lock, the caller will unlock it !
180     *
181     * @param fqn
182     * @param lock
183     * @throws InterruptedException
184     */

185    private void findAndBlockOnPut(Fqn fqn, ReentrantLock JavaDoc lock) throws InterruptedException JavaDoc
186    {
187       Fqn tmp;
188       while (true)
189       {
190          //try {
191
lock.lockInterruptibly();
192          tmp = findFqnInPutList(fqn);
193          if (tmp == null)// put_list is empty, or fqn has not been found
194
{
195             return;
196          }
197          if (log.isTraceEnabled())
198          {
199             log.trace("found " + tmp + " in put-list, waiting");
200          }
201          synchronized (tmp)
202          {
203             lock.unlock();
204             tmp.wait();
205          }
206          if (log.isTraceEnabled())
207          {
208             log.trace("wait() for put-list on " + tmp + " got notified");
209          }
210          //}
211
//finally {
212
// if(lock.holds() > 0)
213
// lock.unlock();
214
//}
215
}
216    }
217
218    /**
219     * Finds all FQNs in the remove_list for which <code>fqn</code> is a child (or equals), and waits for them.
220     * Loops until no more matching FQNs are found or the list is empty.
221     *
222     * @param fqn
223     * @param lock
224     * @throws InterruptedException
225     */

226    private void findAndBlockOnRemove(Fqn fqn, ReentrantLock JavaDoc lock) throws InterruptedException JavaDoc
227    {
228       Fqn tmp;
229       while (true)
230       {
231          lock.lockInterruptibly();
232          try
233          {
234             tmp = findFqnInRemoveList(fqn);
235             if (tmp == null)// remove_list is empty, or fqn has not been found
236
{
237                return;
238             }
239             if (log.isTraceEnabled())
240             {
241                log.trace("found " + tmp + " in remove-list, waiting");
242             }
243             synchronized (tmp)
244             {
245                lock.unlock();
246                tmp.wait();
247             }
248             if (log.isTraceEnabled())
249             {
250                log.trace("wait() for remove-list on " + tmp + " got notified");
251             }
252          }
253          finally
254          {
255             lock.unlock();
256          }
257       }
258    }
259
260
261    private Fqn findFqnInPutList(Fqn fqn)
262    {
263       Fqn tmp;
264       for (Iterator JavaDoc it = put_list.iterator(); it.hasNext();)
265       {
266          tmp = (Fqn) it.next();
267          if (tmp.isChildOf(fqn) || tmp.equals(fqn))// child or same, e.g. put(/a/b/c) and rem(/a/b) or rem(/a/b/c)
268
{
269             return tmp;
270          }
271       }
272       return null;
273    }
274
275    private Fqn findFqnInRemoveList(Fqn fqn)
276    {
277       Fqn tmp;
278       for (Iterator JavaDoc it = remove_list.iterator(); it.hasNext();)
279       {
280          tmp = (Fqn) it.next();
281          if (fqn.isChildOf(tmp) || fqn.equals(tmp))// child or same, e.g. put(/a/b/c) and rem(/a/b) or rem(/a/b/c)
282
{
283             return tmp;
284          }
285       }
286       return null;
287    }
288
289    private void addFqnToPutList(Fqn fqn, ReentrantLock JavaDoc lock)
290            throws InterruptedException JavaDoc
291    {
292       lock.lockInterruptibly();
293       try
294       {
295          if (!put_list.contains(fqn))
296          {
297             put_list.add(fqn);
298             if (log.isTraceEnabled())
299             {
300                log.trace("adding " + fqn + " to put-list (size=" + put_list.size() + ")");
301             }
302          }
303       }
304       finally
305       {
306          lock.unlock();
307       }
308    }
309
310    private void addFqnToRemoveList(Fqn fqn, ReentrantLock JavaDoc lock)
311            throws InterruptedException JavaDoc
312    {
313       lock.lockInterruptibly();
314       try
315       {
316          if (!remove_list.contains(fqn))
317          {
318             remove_list.add(fqn);
319             if (log.isTraceEnabled())
320             {
321                log.trace("adding " + fqn + " to remove-list (size=" + remove_list.size() + ")");
322             }
323          }
324       }
325       finally
326       {
327          lock.unlock();
328       }
329    }
330
331
332    private void removeFqnFromPutList(Fqn fqn, ReentrantLock JavaDoc lock)
333            throws InterruptedException JavaDoc
334    {
335       lock.lockInterruptibly();
336       try
337       {
338          if (log.isTraceEnabled())
339          {
340             log.trace("removing " + fqn + " from put-list (size=" + put_list.size() + ")");
341          }
342          put_list.remove(fqn);
343          lock.unlock();
344          synchronized (fqn)
345          {
346             fqn.notifyAll();
347          }
348       }
349       finally
350       {
351          lock.unlock();
352       }
353    }
354
355    private void removeFqnFromRemoveList(Fqn fqn, ReentrantLock JavaDoc lock)
356            throws InterruptedException JavaDoc
357    {
358       lock.lockInterruptibly();
359       try
360       {
361          if (log.isTraceEnabled())
362          {
363             log.trace("removing " + fqn + " from remove-list (size=" + remove_list.size() + ")");
364          }
365          remove_list.remove(fqn);
366          lock.unlock();
367          synchronized (fqn)
368          {
369             fqn.notifyAll();
370          }
371       }
372       finally
373       {
374          lock.unlock();
375       }
376    }
377
378    private void createNode(Fqn fqn, GlobalTransaction tx)
379    {
380       NodeSPI n, child_node;
381       Object JavaDoc child_name;
382       Fqn tmp_fqn = Fqn.ROOT;
383
384       if (fqn == null) return;
385       synchronized (this)
386       {
387          int treeNodeSize = fqn.size();
388          n = cache.getRoot();
389          for (int i = 0; i < treeNodeSize; i++)
390          {
391             child_name = fqn.get(i);
392             tmp_fqn = new Fqn(tmp_fqn, child_name);
393             child_node = n.getChildDirect(child_name);
394             if (child_node == null)
395             {
396                //child_node=n.createChild(child_name, tmp_fqn, n);
397
child_node = n.addChildDirect(new Fqn(child_name));
398                if (tx != null)
399                {
400                   MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal,
401                           tx, tmp_fqn, false);
402                   ((CacheImpl) cache).addUndoOperation(tx, undo_op);
403
404                   // add the node name to the list maintained for the current tx
405
// (needed for abort/rollback of transaction)
406
// cache.addNode(tx, (Fqn)tmp_fqn.clone());
407
}
408                cache.getNotifier().notifyNodeCreated(tmp_fqn, true, true);
409                cache.getNotifier().notifyNodeCreated(tmp_fqn, false, true);
410             }
411             n = child_node;
412          }
413       }
414    }
415
416 }
417
Popular Tags