KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > web > tomcat > tc6 > session > CacheListener


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.web.tomcat.tc6.session;
23
24 import java.util.Map JavaDoc;
25
26 import org.jboss.cache.CacheSPI;
27 import org.jboss.cache.Fqn;
28 import org.jboss.cache.TreeCache;
29 import org.jboss.cache.AbstractCacheListener;
30 import org.jboss.cache.buddyreplication.BuddyManager;
31 import org.jboss.logging.Logger;
32 import org.jgroups.View;
33
34
35 public class CacheListener extends AbstractCacheListener
36 {
37    // Element within an FQN that is JSESSION
38
private static final int JSESSION_FQN_INDEX = 0;
39    // Element within an FQN that is the hostname
40
private static final int HOSTNAME_FQN_INDEX = 1;
41    // ELEMENT within an FQN this is the webapp name
42
private static final int WEBAPP_FQN_INDEX = 2;
43    // Element within an FQN that is the session id
44
private static final int SESSION_ID_FQN_INDEX = 3;
45    // Size of an Fqn that points to the root of a session
46
private static final int SESSION_FQN_SIZE = SESSION_ID_FQN_INDEX + 1;
47    // Element within an FQN that is the root of a Pojo attribute map
48
private static final int POJO_ATTRIBUTE_FQN_INDEX = SESSION_ID_FQN_INDEX + 1;
49    // Element within an FQN that is the root of an individual Pojo attribute
50
private static final int POJO_KEY_FQN_INDEX = POJO_ATTRIBUTE_FQN_INDEX + 1;
51    // Size of an Fqn that points to the root of a session
52
private static final int POJO_KEY_FQN_SIZE = POJO_KEY_FQN_INDEX + 1;
53    // The index of the root of a buddy backup subtree
54
private static final int BUDDY_BACKUP_ROOT_OWNER_INDEX = BuddyManager.BUDDY_BACKUP_SUBTREE_FQN.size();
55    // The size of the root of a buddy backup subtree (including owner)
56
private static final int BUDDY_BACKUP_ROOT_OWNER_SIZE = BUDDY_BACKUP_ROOT_OWNER_INDEX + 1;
57    
58    private static Logger log_ = Logger.getLogger(CacheListener.class);
59    private JBossCacheWrapper cacheWrapper_;
60    private JBossCacheManager manager_;
61    private String JavaDoc webapp_;
62    private String JavaDoc hostname_;
63    private boolean fieldBased_;
64    // When trying to ignore unwanted notifications, do we check for local activity first?
65
private boolean disdainLocalActivity_;
66
67    CacheListener(JBossCacheWrapper wrapper, JBossCacheManager manager, String JavaDoc hostname, String JavaDoc webapp)
68    {
69       cacheWrapper_ = wrapper;
70       manager_ = manager;
71       hostname_ = hostname;
72       webapp_ = webapp;
73       ReplicationGranularity granularity = manager_.getReplicationGranularity();
74       fieldBased_ = (granularity == ReplicationGranularity.FIELD);
75       // TODO decide if disdaining local activity is always good for REPL_ASYNC
76
disdainLocalActivity_ = (granularity == ReplicationGranularity.SESSION);; // for now
77
}
78
79    // --------------- TreeCacheListener methods ------------------------------------
80

81    @Override JavaDoc
82    public void nodeRemoved(Fqn fqn, boolean pre, boolean isLocal, Map JavaDoc data)
83    {
84       if (pre || isLocal)
85          return;
86       
87       boolean isBuddy = isBuddyFqn(fqn);
88       
89       // Potential removal of a Pojo where we need to unregister as an Observer.
90
if (fieldBased_
91             && isFqnPojoKeySized(fqn, isBuddy)
92             && isFqnForOurWebapp(fqn, isBuddy))
93       {
94          String JavaDoc sessId = getIdFromFqn(fqn, isBuddy);
95          String JavaDoc attrKey = getPojoKeyFromFqn(fqn, isBuddy);
96          manager_.processRemoteAttributeRemoval(sessId, attrKey);
97       }
98       else if(isFqnSessionRootSized(fqn, isBuddy)
99                   && isFqnForOurWebapp(fqn, isBuddy))
100       {
101          // A session has been invalidated from another node;
102
// need to inform manager
103
String JavaDoc sessId = getIdFromFqn(fqn, isBuddy);
104          manager_.processRemoteInvalidation(sessId);
105       }
106    }
107    
108    @Override JavaDoc
109    public void nodeModified(Fqn fqn, boolean pre, boolean isLocal, Map JavaDoc data)
110    {
111       if (pre || isLocal)
112          return;
113       
114 // // If checking for local activity has a higher likelihood of
115
// // catching unwanted notifications than checking fqn size,
116
// // do it first
117
// if (disdainLocalActivity_)
118
// {
119
// if (SessionReplicationContext.isLocallyActive())
120
// return;
121
// }
122

123       boolean isBuddy = isBuddyFqn(fqn);
124       // We only care if there is a chance this is for a session root
125
if (!isFqnSessionRootSized(fqn, isBuddy))
126          return;
127       
128 // if (!disdainLocalActivity_)
129
// {
130
// if (SessionReplicationContext.isLocallyActive())
131
// return;
132
// }
133

134       // We only care if this is for our webapp
135
if (!isFqnForOurWebapp(fqn, isBuddy))
136          return;
137
138       // Query if we have version value in the distributed cache.
139
// If we have a version value, compare the version and invalidate if necessary.
140
// TODO get the key from the passed in data map!!
141
Integer JavaDoc version = (Integer JavaDoc)cacheWrapper_.get(fqn, JBossCacheService.VERSION_KEY);
142       if(version != null)
143       {
144          String JavaDoc realId = getIdFromFqn(fqn, isBuddy);
145          
146          ClusteredSession session = manager_.findLocalSession(realId);
147          if (session == null)
148          {
149             String JavaDoc owner = isBuddy ? getBuddyOwner(fqn) : null;
150             // Notify the manager that an unloaded session has been updated
151
manager_.unloadedSessionChanged(realId, owner);
152          }
153          else if (session.isNewData(version.intValue()))
154          {
155             // Need to invalidate the loaded session
156
session.setOutdatedVersion(version.intValue());
157             if(log_.isTraceEnabled())
158             {
159                log_.trace("nodeDirty(): session in-memory data is " +
160                           "invalidated with id: " + realId + " and version: " +
161                           version.intValue());
162             }
163          }
164          else if (!isBuddy)
165          {
166             log_.warn("Possible concurrency problem: Replicated version id " +
167                       version + " matches in-memory version for session " + realId);
168          }
169          /*else
170          {
171             We have a local session but got a modification for the buddy tree.
172             This means another node is in the process of taking over the session;
173             we don't worry about it
174          }
175           */

176       }
177       else
178       {
179          log_.warn("No VERSION_KEY attribute found in " + fqn);
180       }
181    }
182
183    @Override JavaDoc
184    public void cacheStarted(CacheSPI cache)
185    {
186       // TODO will need to synchronize this with local sessions
187
}
188
189    @Override JavaDoc
190    public void cacheStopped(CacheSPI cache)
191    {
192       // TODO will need to synchronize this with local sessions
193
}
194
195    @Override JavaDoc
196    public void viewChange(View new_view)
197    {
198       // We don't care for this event.
199
}
200    
201    @Override JavaDoc
202    public void nodeActivated(Fqn fqn, boolean pre)
203    {
204       // we don't need to handle node activation notification since the
205
// session manager will notify any servlet API listeners upon
206
// loading the session from the distrubted store.
207
}
208    
209    // FIXME why would there be a notification of passivation on another node?
210
@Override JavaDoc
211    public void nodePassivated(Fqn fqn, boolean pre)
212    {
213       if (!pre || SessionReplicationContext.isLocallyActive())
214          return;
215       
216       boolean isBuddy = isBuddyFqn(fqn);
217       
218       // We only deal with events for the root node of a session,
219
// so skip all others
220
if(isFqnSessionRootSized(fqn, isBuddy)
221             && isFqnForOurWebapp(fqn, isBuddy))
222       {
223          // A session has been passivated on another node;
224
// need to inform the manager
225
String JavaDoc realId = getIdFromFqn(fqn, isBuddy);
226          String JavaDoc owner = isBuddy ? getBuddyOwner(fqn) : null;
227          manager_.processSessionPassivation(realId, owner);
228       }
229            
230    }
231    
232    private boolean isFqnForOurWebapp(Fqn fqn, boolean isBuddy)
233    {
234       try
235       {
236          if (webapp_.equals(fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + WEBAPP_FQN_INDEX : WEBAPP_FQN_INDEX))
237                && hostname_.equals(fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + HOSTNAME_FQN_INDEX : HOSTNAME_FQN_INDEX))
238                && JBossCacheService.SESSION.equals(fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + JSESSION_FQN_INDEX : JSESSION_FQN_INDEX)))
239             return true;
240       }
241       catch (IndexOutOfBoundsException JavaDoc e)
242       {
243          // can't be ours; too small; just fall through
244
}
245
246       return false;
247    }
248    
249    private static boolean isFqnSessionRootSized(Fqn fqn, boolean isBuddy)
250    {
251       return fqn.size() == (isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + SESSION_FQN_SIZE : SESSION_FQN_SIZE);
252    }
253    
254    private static boolean isFqnPojoKeySized(Fqn fqn, boolean isBuddy)
255    {
256       return fqn.size() == (isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + POJO_KEY_FQN_SIZE : POJO_KEY_FQN_SIZE);
257    }
258    
259    private static String JavaDoc getIdFromFqn(Fqn fqn, boolean isBuddy)
260    {
261       return (String JavaDoc)fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + SESSION_ID_FQN_INDEX : SESSION_ID_FQN_INDEX);
262    }
263    
264    private static String JavaDoc getPojoKeyFromFqn(Fqn fqn, boolean isBuddy)
265    {
266       return (String JavaDoc) fqn.get(isBuddy ? BUDDY_BACKUP_ROOT_OWNER_SIZE + POJO_KEY_FQN_INDEX: POJO_KEY_FQN_INDEX);
267    }
268    
269    private static boolean isBuddyFqn(Fqn fqn)
270    {
271       try
272       {
273          return BuddyManager.BUDDY_BACKUP_SUBTREE.equals(fqn.get(0));
274       }
275       catch (IndexOutOfBoundsException JavaDoc e)
276       {
277          // Can only happen if fqn is ROOT, and we shouldn't get
278
// notifications for ROOT.
279
// If it does, just means it's not a buddy
280
return false;
281       }
282    }
283    
284    /**
285     * Extracts the owner portion of an buddy subtree Fqn.
286     *
287     * @param fqn An Fqn that is a child of the buddy backup root node.
288     */

289    private static String JavaDoc getBuddyOwner(Fqn fqn)
290    {
291       return (String JavaDoc) fqn.get(BUDDY_BACKUP_ROOT_OWNER_INDEX);
292    }
293 }
294
Popular Tags