KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > cache > aop > MarshalledTreeCache


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.cache.aop;
8
9 import org.jboss.cache.TreeCache;
10 import org.jboss.cache.Fqn;
11 import org.jboss.cache.CacheException;
12 import org.jboss.cache.TreeCacheListener;
13 import org.jboss.cache.lock.IsolationLevel;
14 import org.jboss.invocation.MarshalledValue;
15 import org.jgroups.JChannel;
16 import org.jgroups.View;
17 import org.jgroups.stack.IpAddress;
18
19 import java.util.HashMap JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.io.IOException JavaDoc;
22
23 /**
24  * <p>Version of TreeCache that added call to handle marshalling values. You will need marshalling when your application
25  * is running under different class loader scope, for example, under JBoss AS where your application has a scoped
26  * class loader.</p>
27  * <p>Note that: Currently, we also have a in-memory cache copy to minimize the call to unmarshalling. And we also
28  * have an invalidation mechanism in place to synchronize the external updates.</p>
29  * <p>In the future, it'd be best if JBossCache can provides 1) notification excluding myself, 2) notification granulairty
30  * with specific modified key, 3) we will also move this to different package.</p>
31  * <p>Finally, since the use of in-memory copy, the memory usage is almost doubled since we have one in-memory copy and
32  * the marshalled value in the cache store.</p>
33  * @author Ben Wang
34  */

35 public class MarshalledTreeCache extends TreeCache implements TreeCacheListener {
36    // Store the in-memory copy of the treecache (key, value) pair.
37
// This is used for performance reason so there is no need to un-marshall every single operation.
38
// In addition, it will support an invalidation mechanism.
39
protected TreeCache localCopy_;
40    protected String JavaDoc nodeId_;
41    // Key to denotes the caller's ID. We will use this to check whether this is from myself or not.
42
// TODO Will need to document this.
43
protected static final String JavaDoc NODEID_KEY = "__NODEID_KEY__";
44    // Context class loader. If it is not null, marshalling/unmarshalling will use this.
45
protected ClassLoader JavaDoc tcl_ = null;
46    // If it is on, will use an internal copy to keep the unmarshalling value.
47
protected boolean useLocalOptimization_ = true;
48    // Indicate whether we want marshalling or not. If it is false, useLocalOptimization will be false as wel.
49
protected boolean marshalling_ = true;
50
51    public MarshalledTreeCache(String JavaDoc cluster_name,
52                        String JavaDoc props,
53                        long state_fetch_timeout)
54          throws Exception JavaDoc
55    {
56       super(cluster_name, props, state_fetch_timeout);
57       this._init();
58    }
59
60    public MarshalledTreeCache() throws Exception JavaDoc
61    {
62       this._init();
63    }
64
65    public MarshalledTreeCache(JChannel channel) throws Exception JavaDoc
66    {
67       super(channel);
68       this._init();
69    }
70
71    private void _init() throws Exception JavaDoc {
72       localCopy_ = new TreeCache();
73       localCopy_.setCacheMode(TreeCache.LOCAL);
74       localCopy_.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
75       marshalling_ = true;
76       useLocalOptimization_ = true;
77       tcl_ = null;
78    }
79
80    public void startService() throws Exception JavaDoc
81    {
82       super.addTreeCacheListener(this);
83       super.startService();
84       if(localCopy_ == null)
85          throw new RuntimeException JavaDoc("startService(): null localCopy_");
86       localCopy_.startService();
87       obtainNodeId();
88    }
89
90    public void stopService()
91    {
92       nodeId_ = null;
93       localCopy_.stopService();
94       super.stopService();
95    }
96
97    /**
98     * Get a node id based on jgroups properties.
99     */

100    protected void obtainNodeId()
101    {
102       IpAddress address = (IpAddress)getLocalAddress();
103       if(address == null)
104       {
105          log.info("obtainNodeId(): has null IpAddress. Assume it is running in local mode.");
106          nodeId_ = "local";
107          return;
108       }
109
110       if (address.getAdditionalData() == null)
111       {
112          nodeId_ = address.getIpAddress().getHostAddress() + ":" + address.getPort();
113       }
114       else
115       {
116          nodeId_ = new String JavaDoc(address.getAdditionalData());
117       }
118    }
119
120    /**
121     * Node id is a communication id that denotes the cluster node.
122     */

123    public String JavaDoc getNodeId() {
124       return nodeId_;
125    }
126
127
128    /**
129     * Turn marshalling layer on or off. If off, no marshalling. Default is on.
130     *
131     */

132    public void setMarshalling(boolean marshalling)
133    {
134       marshalling_ = marshalling;
135    }
136
137    /**
138     * Indicate whether to have a in-memory copy of the unmarshalling object such that
139     * there is no need to unmarshal. If it is on, invlidation will be handled where another active
140     * node has update this fqn.
141     */

142    public void setLocalOptimization(boolean optimization)
143    {
144       useLocalOptimization_ = optimization;
145       throw new RuntimeException JavaDoc("MarshalledTreeCache.setLocalOptimization(): operation not supported yet.");
146    }
147
148    /**
149     * The context class loader to perform marshalling/unmarshalling
150     */

151    public void setClassLoader(ClassLoader JavaDoc tcl)
152    {
153       tcl_ = tcl;
154    }
155
156    public void marshalledPut(String JavaDoc fqn, Object JavaDoc key, Object JavaDoc value) throws CacheException {
157       marshalledPut(Fqn.fromString(fqn), key, value);
158    }
159
160    /**
161     * Marshalled put. That is, the value that is put into cache is marshalled first. Note that
162     * we still require that key to be primitive type.
163     */

164    public void marshalledPut(Fqn fqn, Object JavaDoc key, Object JavaDoc value) throws CacheException
165    {
166       if(marshalling_)
167       {
168          marshalledPut_(fqn, key, value);
169       } else {
170          put(fqn, key, value);
171       }
172    }
173
174    public void marshalledPut_(Fqn fqn, Object JavaDoc key, Object JavaDoc value) throws CacheException
175    {
176       MarshalledValue mv = null;
177       try {
178          mv = new MarshalledValue(value);
179       } catch (IOException JavaDoc e) {
180          e.printStackTrace();
181          throw new CacheException("marshalledPut() exception: " +e);
182       }
183
184       // Put into local copy first.
185
localCopy_.put(fqn, key, value);
186       // Put into cache
187
Map JavaDoc map = new HashMap JavaDoc();
188       map.put(key, mv);
189       map.put(NODEID_KEY, nodeId_);
190       this.put(fqn, map);
191    }
192
193    public Object JavaDoc marshalledGet(String JavaDoc fqn, Object JavaDoc key) throws CacheException {
194       return marshalledGet(Fqn.fromString(fqn), key);
195    }
196
197    /**
198     * Obtain the value from the marshalled cache. Note that the return value is un-marshalled
199     * either from the local copy or from the distributed store.
200     */

201    public Object JavaDoc marshalledGet(Fqn fqn, Object JavaDoc key) throws CacheException {
202       if(marshalling_)
203       {
204          ClassLoader JavaDoc prevTCL = null;
205          if(tcl_ != null)
206          {
207             prevTCL = Thread.currentThread().getContextClassLoader();
208             Thread.currentThread().setContextClassLoader(tcl_);
209          }
210          try {
211             return marshalledGet_(fqn, key);
212          } finally
213          {
214             if(tcl_ != null && prevTCL != null)
215             {
216                Thread.currentThread().setContextClassLoader(prevTCL);
217             }
218          }
219       } else
220       {
221          return get(fqn, key);
222       }
223    }
224
225    public Object JavaDoc marshalledGet_(Fqn fqn, Object JavaDoc key) throws CacheException {
226       // Check if it is in local copy first.
227
Object JavaDoc value;
228       try {
229          if( (value = localCopy_.get(fqn, key)) != null)
230             return value;
231          else
232          { // get it from cache store
233
value = get(fqn, key);
234             if(value == null) return null;
235             checkValue(value);
236             MarshalledValue mv = (MarshalledValue)value;
237             value = mv.get();
238             // populate the local copy
239
localCopy_.put(fqn, key, value);
240             return value;
241          }
242       } catch (IOException JavaDoc e) {
243          e.printStackTrace();
244          throw new CacheException("marshalledGet(): exception encountered: ", e);
245       } catch (ClassNotFoundException JavaDoc e) {
246          e.printStackTrace();
247          throw new CacheException("marshalledGet(): exception encountered: ", e);
248       }
249    }
250
251    public Object JavaDoc marshalledRemove(String JavaDoc fqn, Object JavaDoc key) throws CacheException
252    {
253       return marshalledRemove(Fqn.fromString(fqn), key);
254    }
255
256    /**
257     * Remove a marshalled node. This is required if you have performed a marshalledPut since
258     * we will need to do clean up.
259     */

260    public Object JavaDoc marshalledRemove(Fqn fqn, Object JavaDoc key) throws CacheException
261    {
262       if(marshalling_)
263       {
264          return marshalledRemove_(fqn, key);
265       } else
266       {
267          return remove(fqn, key);
268       }
269    }
270
271    public Object JavaDoc marshalledRemove_(Fqn fqn, Object JavaDoc key) throws CacheException
272       {
273       if( !exists(fqn, key) )
274          log.warn("marshalledRemove(): fqn: " +fqn + " key: " +key + " not found.");
275
276       Object JavaDoc value = localCopy_.get(fqn, key);
277       localCopy_.remove(fqn);
278       remove(fqn, NODEID_KEY);
279       Object JavaDoc obj = remove(fqn, key);
280       if(value != null) return value;
281       checkValue(obj);
282       try {
283          return ((MarshalledValue)obj).get();
284       } catch (IOException JavaDoc e) {
285          e.printStackTrace();
286          throw new CacheException("marshalledRemove(): exception encountered: ", e);
287       } catch (ClassNotFoundException JavaDoc e) {
288          e.printStackTrace();
289          throw new CacheException("marshalledRemove(): exception encountered: ", e);
290       }
291    }
292
293    public void nodeCreated(Fqn fqn)
294    {
295       // no-op
296
}
297
298    public void nodeRemoved(Fqn fqn)
299    {
300       invalidate(fqn);
301    }
302
303    public void nodeLoaded(Fqn fqn)
304    {
305       // no-op
306
}
307
308    public void nodeEvicted(Fqn fqn)
309    {
310       invalidate(fqn);
311    }
312
313    public void nodeModified(Fqn fqn)
314    {
315       invalidate(fqn);
316    }
317
318    public void nodeVisited(Fqn fqn)
319    {
320       // no-op
321
}
322
323    public void cacheStarted(TreeCache cache)
324    {
325       // no-op
326
}
327
328    public void cacheStopped(TreeCache cache)
329    {
330       // no-op
331
}
332
333    public void viewChange(View new_view)
334    {
335       // no-op
336
}
337
338    protected void checkValue(Object JavaDoc value)
339    {
340       if( value != null && !(value instanceof MarshalledValue))
341          throw new RuntimeException JavaDoc("checkValue: return object is not instance of MarshalledValue. object: "+value);
342    }
343
344    /**
345     * Invalidate the local copy cache. Assumption is invlidation should not happen that often anyway.
346     * In addition, we will invalidate the whole thing under the fqn.
347     * @param fqn
348     */

349    protected void invalidate(Fqn fqn)
350    {
351       if(!marshalling_) return; // No need if there is no marshalling!
352
if(fqn.toString().equals("/")) return; // No need to handle root.
353
if( !localCopy_.exists(fqn)) return; // probably not a mv node anyway.
354

355       try {
356          String JavaDoc eventId = (String JavaDoc)get(fqn, NODEID_KEY);
357          if(eventId == null)
358             throw new RuntimeException JavaDoc("invlidate(): fqn to invlidate has null node id. fqn: " +fqn);
359
360          if( nodeId_.equals(eventId) ) return; // skip since this event is initiated by myself.
361
localCopy_.remove(fqn);
362       } catch (CacheException e) {
363          e.printStackTrace();
364       }
365    }
366 }
367
Popular Tags