2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE 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
11 SOPE 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.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include <NGObjWeb/WOSessionStore.h>
25 The default session store. It stores all the sessions in memory
26 (it's basically a simple hashmap of the session-id to the session object).
28 If the application goes down, all sessions will go down - this store
29 doesn't provide "session-failover".
32 @interface WOServerSessionStore : WOSessionStore
34 NSMapTable *idToSession;
35 NSMapTable *activeSessions;
39 #include <NGObjWeb/WOContext.h>
40 #include <NGObjWeb/WOApplication.h>
41 #include <NGObjWeb/WOSession.h>
44 /* hh: moved in here from application, check whether it's required ... */
45 @interface WOSessionInfo : NSObject
52 + (WOSessionInfo *)infoForSession:(WOSession *)_session;
54 - (NSString *)sessionID;
55 - (NSDate *)timeoutDate;
59 @implementation WOServerSessionStore
61 static BOOL logExpiredSessions = NO;
64 return [super version] + 0;
67 NSAssert2([super version] == 2,
68 @"invalid superclass (%@) version %i !",
69 NSStringFromClass([self superclass]), [super version]);
73 if ((self = [super init])) {
74 self->idToSession = NSCreateMapTable(NSObjectMapKeyCallBacks,
75 NSObjectMapValueCallBacks,
77 self->activeSessions = NSCreateMapTable(NSObjectMapKeyCallBacks,
78 NSObjectMapValueCallBacks,
80 self->checkedOutSessions = [[NSMutableSet allocWithZone:[self zone]]
83 if ([[[NSUserDefaults standardUserDefaults]
84 objectForKey:@"WORunMultithreaded"]
86 self->lock = [[NSRecursiveLock allocWithZone:[self zone]] init];
87 self->checkoutLock = [[NSConditionLock allocWithZone:[self zone]]
95 if (self->activeSessions) {
96 NSFreeMapTable(self->activeSessions);
97 self->activeSessions = NULL;
99 if (self->idToSession) {
100 NSFreeMapTable(self->idToSession);
101 self->idToSession = NULL;
103 [self->checkedOutSessions release];
104 [self->checkoutLock release];
105 [self->lock release];
111 - (int)activeSessionsCount {
115 count = NSCountMapTable(self->idToSession);
123 - (void)saveSessionForContext:(WOContext *)_context {
124 if (![_context hasSession])
129 WOSession *sn = [_context session];
131 if ([sn isTerminating]) {
134 NSMapRemove(self->idToSession, [sn sessionID]);
135 NSMapRemove(self->activeSessions, [sn sessionID]);
137 NSLog(@"session %@ terminated at %@ ..",
138 [sn sessionID], [NSCalendarDate calendarDate]);
140 [sn release]; sn = nil;
145 NSMapInsert(self->idToSession, [sn sessionID], sn);
147 info = [WOSessionInfo infoForSession:sn];
148 NSMapInsert(self->activeSessions, [sn sessionID], info);
154 - (WOSession *)restoreSessionWithID:(NSString *)_sid
155 request:(WORequest *)_request
157 WOSession *session = nil;
159 if ([_sid length] == 0)
162 if (![_sid isKindOfClass:[NSString class]]) {
163 [self warnWithFormat:@"%s: got invalid session id (expected string !): %@",
164 __PRETTY_FUNCTION__, _sid];
168 if ([_sid isEqualToString:@"expired"])
172 session = NSMapGet(self->idToSession, _sid);
175 if (logExpiredSessions) {
177 [self logWithFormat:@"session with id %@ expired.", _sid];
185 - (void)sessionExpired:(NSString *)_sessionID {
187 NSMapRemove(self->idToSession, _sessionID);
191 - (void)sessionTerminated:(WOSession *)_session {
192 _session = [_session retain];
194 NSMapRemove(self->idToSession, [_session sessionID]);
198 [[WOApplication application]
200 @"WOServerSessionStore: session %@ terminated.",
201 [_session sessionID]];
204 /* expiration check */
206 - (void)performExpirationCheck:(NSTimer *)_timer {
207 NSNotificationCenter *nc;
208 NSMutableArray *timedOut = nil;
211 WOSessionInfo *info = nil;
215 //NSLog(@"%s: perform expiration check ...", __PRETTY_FUNCTION__);
217 if (self->activeSessions == NULL)
220 count = NSCountMapTable(self->activeSessions);
222 if (!(count > 0 && (self->activeSessions != NULL)))
225 e = NSEnumerateMapTable(self->activeSessions);
228 /* search for expired sessions */
229 while (NSNextMapEnumeratorPair(&e, (void **)&sid, (void **)&info)) {
230 NSDate *timeOutDate = [info timeoutDate];
232 if (timeOutDate == nil) continue;
234 if ([now compare:timeOutDate] != NSOrderedAscending) {
235 [self logWithFormat:@"session %@ expired at %@.", sid, now];
238 timedOut = [NSMutableArray arrayWithCapacity:32];
239 [timedOut addObject:info];
243 /* Expire sessions */
247 nc = [NSNotificationCenter defaultCenter];
249 for (cnt = 0, count = [timedOut count]; cnt < count; cnt++) {
252 info = [timedOut objectAtIndex:cnt];
253 sid = [[info sessionID] copy];
255 NSMapRemove(self->activeSessions, sid);
256 NSMapRemove(self->idToSession, sid);
258 [nc postNotificationName:WOSessionDidTimeOutNotification
267 - (NSString *)description {
268 return [NSString stringWithFormat:@"<%@[0x%08X]: active=%i>",
269 NSStringFromClass([self class]), self,
270 [self activeSessionsCount]
274 @end /* WOServerSessionStore */
276 @implementation WOSessionInfo
278 - (id)initWithSession:(WOSession *)_session {
279 self->sessionID = RETAIN([_session sessionID]);
281 if ([_session respondsToSelector:@selector(timeoutDate)]) {
282 self->timeoutDate = [(id)_session timeoutDate];
285 NSTimeInterval timeOut = [_session timeOut];
287 self->timeoutDate = (timeOut > 0.0)
288 ? [NSDate dateWithTimeIntervalSinceNow:(timeOut + 1.0)]
289 : [NSDate distantFuture];
291 self->timeoutDate = RETAIN(self->timeoutDate);
296 + (WOSessionInfo *)infoForSession:(WOSession *)_session {
297 return AUTORELEASE([[self alloc] initWithSession:_session]);
301 [self->sessionID release];
302 [self->timeoutDate release];
306 - (NSString *)sessionID {
307 return self->sessionID;
309 - (NSDate *)timeoutDate {
310 return self->timeoutDate;
313 @end /* WOSessionInfo */