KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sync4j > transport > http > server > RemoteHolderCache


1 /**
2  * Copyright (C) 2003-2005 Funambol
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18 package sync4j.transport.http.server;
19
20 import java.util.*;
21 import java.util.logging.*;
22
23 import javax.servlet.*;
24
25 import org.apache.commons.lang.*;
26 import org.jgroups.*;
27 import org.jgroups.blocks.*;
28 import org.jgroups.log.*;
29
30 import sync4j.framework.transport.http.*;
31
32 /**
33  * This class implements the remote reference cache.
34  * It holds the DistributedHashtable in its instance parameter cache.
35  * <p>
36  * Another optimization performed in this object is avoiding memory eating
37  * due to missing SyncHolders removing. This problem is solved with the
38  * following actions:
39  * <ul>
40  * <li> each SyncHolder stores a creation timestamp that is set in the
41  * constructor to the current system time (ms);
42  * <li> HolderCache stores in the lastCleaningTimestamp static field the last
43  * time the cache was cleared;
44  * <li> If the difference between the current time (ms) and the
45  * lastCleaningTimestamp is greater then the configured sessionTimeToLive,
46  * the cleaner process is executed;
47  * <li> the cleaner process iterates the sync holders in the cache and closes and removes the expired ones;
48  * </ul>
49  * <p>
50  * NOTES:
51  * <p>
52  * 1. The cleaning process could be moved to a separate thread and executed
53  * asynchronously respect to the execution of servlet execution.
54  *
55  * @author Stefano Fornari
56  * @version $Id: RemoteHolderCache.java,v 1.7 2005/03/02 20:57:40 harrie Exp $
57  */

58 public class RemoteHolderCache
59 implements Constants {
60
61     // --------------------------------------------------------------- Constants
62

63     public static final long CLEANING_PERIOD = 300000; // 5 mins
64

65     private static final Logger log = Logger.getLogger(LOG_NAME);
66
67     // ------------------------------------------------------------ Private data
68

69     private long holderTimeToLive = DEFAULT_TTL;
70
71     private long lastCleaningTimestamp = 0;
72
73     private String JavaDoc channelProps;
74
75     private DistributedHashtable cache;
76
77     // ------------------------------------------------------------ Constructors
78

79     public RemoteHolderCache(ServletConfig config) {
80         try {
81             String JavaDoc group = config.getInitParameter(PARAM_GROUP);
82             String JavaDoc props = config.getInitParameter(PARAM_CHANNEL_PROPERTIES);
83
84             if (StringUtils.isEmpty(group)) {
85                 group = DEFAULT_GROUP;
86             }
87
88             //
89
// Consitionally enable tracing (if the logging level includes
90
// Level.FINE, enable it, otherwise not)
91
//
92
if (log.isLoggable(Level.FINE)) {
93                 Trace.init();
94             }
95
96             if (log.isLoggable(Level.FINE)) {
97                 log.fine("Multicast group: " + group);
98                 log.fine("Multicast properties: " + props);
99             }
100
101             JChannelFactory cf = new JChannelFactory();
102             cache = new DistributedHashtable(group, cf, props, DEFAULT_TIMEOUT);
103
104         } catch (Exception JavaDoc e) {
105             log.severe(e.getMessage());
106             log.throwing(getClass().getName(), "configure", e);
107         }
108
109         lastCleaningTimestamp = System.currentTimeMillis();
110
111         holderTimeToLive =
112             Long.parseLong(config.getInitParameter(PARAM_SESSION_TTL));
113
114     }
115
116     // ------------------------------------------- Implementation of HolderCache
117

118     public void put(SyncHolder holder) {
119         clean();
120         if (log.isLoggable(Level.FINE)) {
121             log.fine("Caching " + holder.getSessionId() + '(' + holder + ')');
122         }
123         synchronized (cache) {
124             cache.put(holder.getSessionId(), holder);
125         }
126     }
127
128     public SyncHolder get(String JavaDoc sessionId) {
129         return (SyncHolder)cache.get(sessionId);
130     }
131
132     public void remove(String JavaDoc sessionId) {
133         if (log.isLoggable(Level.FINE)) {
134             log.fine("Removing holder for " + sessionId);
135         }
136         synchronized (cache) {
137             cache.remove(sessionId);
138         }
139     }
140
141     // ---------------------------------------------------- Other public methods
142

143     public String JavaDoc toString() {
144         String JavaDoc s = null;
145         synchronized (cache) {
146             s = String.valueOf(cache);
147         }
148         return s;
149     }
150
151     // --------------------------------------------------------- Private methods
152

153     /**
154      * If System.currentTimeMillis() - lastCleaningTimestamp is greater than
155      * holderTimeToLive, purge old holders.
156      *
157      * @returns true if cleaning was performed, false otherwise
158      */

159     private boolean clean() {
160         long now = System.currentTimeMillis();
161
162         if (log.isLoggable(Level.FINE)) {
163             log.fine("Cleaning procedure..." );
164             log.fine("now: " + now );
165             log.fine("CLEANING_PERIOD: " + CLEANING_PERIOD );
166             log.fine("lastCleaningTimestamp: " + lastCleaningTimestamp);
167             log.fine("holderTimeToLive: " + holderTimeToLive );
168         }
169
170         ArrayList toBeRemoved = null;
171
172         RemoteEJBSyncHolder h;
173         Object JavaDoc key, value;
174         Iterator i = null;
175
176         synchronized (cache) {
177
178             if ((now - lastCleaningTimestamp) <= CLEANING_PERIOD) {
179                 if (log.isLoggable(Level.FINEST)) {
180                     log.finest("No purging required");
181                 }
182                 return false;
183             }
184
185             if (log.isLoggable(Level.FINEST)) {
186                 log.finest("Performing purging...");
187             }
188
189             toBeRemoved = new ArrayList();
190
191             i = cache.keySet().iterator();
192             while (i.hasNext()) {
193                 key = i.next();
194                 value = cache.get(key);
195
196                 if (!(value instanceof RemoteEJBSyncHolder)) {
197                     // You shouldn't be here matey!!!
198
if (log.isLoggable(Level.FINEST)) {
199                         log.finest("Found unexpected object:" + key + " will be removed!");
200                     }
201                     toBeRemoved.add(key);
202                     continue;
203                 }
204                 h = (RemoteEJBSyncHolder)value;
205                 if ((now - h.getCreationTimestamp()) > holderTimeToLive) {
206                     if (log.isLoggable(Level.FINEST)) {
207                         log.finest("Purging holder for session " + key);
208                     }
209                     try {
210                         h.close();
211                     } catch (Exception JavaDoc e) {
212                         log.severe(e.getMessage());
213                         log.throwing(getClass().getName(), "clean", e);
214                     }
215                     toBeRemoved.add(key);
216                 }
217             }
218
219             //
220
// Now remove the purged objects
221
//
222
i = toBeRemoved.iterator();
223             while(i.hasNext()) {
224                 cache.remove(i.next());
225             }
226         }
227
228         lastCleaningTimestamp = System.currentTimeMillis();
229
230         return true;
231     }
232 }
233
Popular Tags