]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WOServerSessionStore.m
renamed packages as discussed in the developer list
[sope] / sope-appserver / NGObjWeb / WOServerSessionStore.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include <NGObjWeb/WOSessionStore.h>
24
25 /*
26   The default session store. It stores all the sessions in memory
27   (it's basically a simple hashmap of the session-id to the session object).
28
29   If the application goes down, all sessions will go down - this store
30   doesn't provide "session-failover".
31 */
32
33 @interface WOServerSessionStore : WOSessionStore
34 {
35   NSMapTable *idToSession;
36   NSMapTable *activeSessions;
37 }
38 @end
39
40 #include <NGObjWeb/WOContext.h>
41 #include <NGObjWeb/WOApplication.h>
42 #include <NGObjWeb/WOSession.h>
43 #include "common.h"
44
45 /* hh: moved in here from application, check whether it's required ... */
46 @interface WOSessionInfo : NSObject
47 {
48 @private
49   NSString *sessionID;
50   NSDate   *timeoutDate;
51 }
52
53 + (WOSessionInfo *)infoForSession:(WOSession *)_session;
54
55 - (NSString *)sessionID;
56 - (NSDate *)timeoutDate;
57
58 @end
59
60 @implementation WOServerSessionStore
61
62 static BOOL logExpiredSessions = NO;
63
64 + (int)version {
65   return [super version] + 0;
66 }
67 + (void)initialize {
68   NSAssert2([super version] == 2,
69             @"invalid superclass (%@) version %i !",
70             NSStringFromClass([self superclass]), [super version]);
71 }
72
73 - (id)init {
74   if ((self = [super init])) {
75     self->idToSession = NSCreateMapTable(NSObjectMapKeyCallBacks,
76                                          NSObjectMapValueCallBacks,
77                                          128);
78     self->activeSessions = NSCreateMapTable(NSObjectMapKeyCallBacks,
79                                             NSObjectMapValueCallBacks,
80                                             128);
81     self->checkedOutSessions = [[NSMutableSet allocWithZone:[self zone]]
82                                               initWithCapacity:64];
83     
84     if ([[[NSUserDefaults standardUserDefaults]
85                           objectForKey:@"WORunMultithreaded"]
86                           boolValue]) {
87       self->lock         = [[NSRecursiveLock allocWithZone:[self zone]] init];
88       self->checkoutLock = [[NSConditionLock allocWithZone:[self zone]]
89                                              initWithCondition:0];
90     }
91   }
92   return self;
93 }
94
95 - (void)dealloc {
96   if (self->activeSessions) {
97     NSFreeMapTable(self->activeSessions);
98     self->activeSessions = NULL;
99   }
100   if (self->idToSession) {
101     NSFreeMapTable(self->idToSession);
102     self->idToSession = NULL;
103   }
104   [self->checkedOutSessions release];
105   [self->checkoutLock       release];
106   [self->lock               release];
107   [super dealloc];
108 }
109
110 /* accessors */
111
112 - (int)activeSessionsCount {
113   int count;
114   
115   [self->lock lock];
116   count = NSCountMapTable(self->idToSession);
117   [self->lock unlock];
118
119   return count;
120 }
121
122 /* store */
123
124 - (void)saveSessionForContext:(WOContext *)_context {
125   if (![_context hasSession])
126     return;
127   
128   [self->lock lock];
129   {
130     WOSession *sn = [_context session];
131       
132     if ([sn isTerminating]) {
133       sn = [sn retain];
134         
135       NSMapRemove(self->idToSession,    [sn sessionID]);
136       NSMapRemove(self->activeSessions, [sn sessionID]);
137         
138       NSLog(@"session %@ terminated at %@ ..",
139             [sn sessionID], [NSCalendarDate calendarDate]);
140         
141       [sn release]; sn = nil;
142     }
143     else {
144       WOSessionInfo *info;
145         
146       NSMapInsert(self->idToSession, [sn sessionID], sn);
147         
148       info = [WOSessionInfo infoForSession:sn];
149       NSMapInsert(self->activeSessions, [sn sessionID], info);
150     }
151   }
152   [self->lock unlock];
153 }
154
155 - (WOSession *)restoreSessionWithID:(NSString *)_sid
156   request:(WORequest *)_request
157 {
158   WOSession *session = nil;
159
160   if ([_sid length] == 0)
161     return nil;
162   
163   if (![_sid isKindOfClass:[NSString class]]) {
164     [self logWithFormat:
165             @"WARNING(%s): got invalid session id (expected string !): %@",
166             __PRETTY_FUNCTION__, _sid];
167     return nil;
168   }
169   
170   if ([_sid isEqualToString:@"expired"])
171     return nil;
172
173   [self->lock lock];
174   session = NSMapGet(self->idToSession, _sid);
175   [self->lock unlock];
176
177   if (logExpiredSessions) {
178     if (session == nil)
179       [self logWithFormat:@"session with id %@ expired.", _sid];
180   }
181
182   return session;
183 }
184
185 /* termination */
186
187 - (void)sessionExpired:(NSString *)_sessionID {
188   [self->lock lock];
189   NSMapRemove(self->idToSession, _sessionID);
190   [self->lock unlock];
191 }
192
193 - (void)sessionTerminated:(WOSession *)_session {
194   _session = [_session retain];
195   [self->lock lock];
196   NSMapRemove(self->idToSession, [_session sessionID]);
197   [self->lock unlock];
198   [_session release];
199   
200   [[WOApplication application]
201                   logWithFormat:
202                     @"WOServerSessionStore: session %@ terminated.",
203                     [_session sessionID]];
204 }
205
206 /* expiration check */
207
208 - (void)performExpirationCheck:(NSTimer *)_timer {
209   NSNotificationCenter *nc;
210   NSMutableArray  *timedOut = nil;
211   NSMapEnumerator e;
212   NSString        *sid  = nil;
213   WOSessionInfo   *info = nil;
214   NSDate          *now;
215   unsigned cnt, count;
216     
217   //NSLog(@"%s: perform expiration check ...", __PRETTY_FUNCTION__);
218   
219   if (self->activeSessions == NULL)
220     count = 0;
221   else
222     count = NSCountMapTable(self->activeSessions);
223   
224   if (!(count > 0 && (self->activeSessions != NULL)))
225     return;
226   
227   e   = NSEnumerateMapTable(self->activeSessions);
228   now = [NSDate date];
229       
230   /* search for expired sessions */
231   while (NSNextMapEnumeratorPair(&e, (void **)&sid, (void **)&info)) {
232     NSDate *timeOutDate = [info timeoutDate];
233     
234     if (timeOutDate == nil) continue;
235
236     if ([now compare:timeOutDate] != NSOrderedAscending) {
237         [self logWithFormat:@"session %@ expired at %@.", sid, now];
238           
239         if (timedOut == nil)
240           timedOut = [NSMutableArray arrayWithCapacity:32];
241         [timedOut addObject:info];
242     }
243   }
244       
245   /* Expire sessions */
246   if (!timedOut)
247     return;
248
249   nc = [NSNotificationCenter defaultCenter];
250         
251   for (cnt = 0, count = [timedOut count]; cnt < count; cnt++) {
252     NSString *sid;
253           
254         info = [timedOut objectAtIndex:cnt];
255         sid  = [[info sessionID] copy];
256           
257         NSMapRemove(self->activeSessions, sid);
258         NSMapRemove(self->idToSession,    sid);
259           
260         [nc postNotificationName:WOSessionDidTimeOutNotification
261             object:sid];
262
263         [sid release];
264   }
265 }
266
267 /* description */
268
269 - (NSString *)description {
270   return [NSString stringWithFormat:@"<%@[0x%08X]: active=%i>",
271                      NSStringFromClass([self class]), self,
272                      [self activeSessionsCount]
273                    ];
274 }
275
276 @end /* WOServerSessionStore */
277
278 @implementation WOSessionInfo
279
280 - (id)initWithSession:(WOSession *)_session {
281   self->sessionID = RETAIN([_session sessionID]);
282
283   if ([_session respondsToSelector:@selector(timeoutDate)]) {
284     self->timeoutDate = [(id)_session timeoutDate];
285   }
286   else {
287     NSTimeInterval timeOut = [_session timeOut];
288     
289     self->timeoutDate = (timeOut > 0.0)
290       ? [NSDate dateWithTimeIntervalSinceNow:(timeOut + 1.0)]
291       : [NSDate distantFuture];
292   }
293   self->timeoutDate = RETAIN(self->timeoutDate);
294   
295   return self;
296 }
297
298 + (WOSessionInfo *)infoForSession:(WOSession *)_session {
299   return AUTORELEASE([[self alloc] initWithSession:_session]);
300 }
301
302 - (void)dealloc {
303   [self->sessionID   release];
304   [self->timeoutDate release];
305   [super dealloc];
306 }
307
308 - (NSString *)sessionID {
309   return self->sessionID;
310 }
311 - (NSDate *)timeoutDate {
312   return self->timeoutDate;
313 }
314
315 @end /* WOSessionInfo */