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 - (id)restoreSessionWithID:(NSString *)_sid request:(WORequest *)_request {
155 WOSession *session = nil;
157 if ([_sid length] == 0)
160 if (![_sid isKindOfClass:[NSString class]]) {
161 [self warnWithFormat:@"%s: got invalid session id (expected string !): %@",
162 __PRETTY_FUNCTION__, _sid];
166 if ([_sid isEqualToString:@"expired"])
170 session = NSMapGet(self->idToSession, _sid);
173 if (logExpiredSessions) {
175 [self logWithFormat:@"session with id %@ expired.", _sid];
183 - (void)sessionExpired:(NSString *)_sessionID {
185 NSMapRemove(self->idToSession, _sessionID);
189 - (void)sessionTerminated:(WOSession *)_session {
190 _session = [_session retain];
192 NSMapRemove(self->idToSession, [_session sessionID]);
196 [[WOApplication application]
198 @"WOServerSessionStore: session %@ terminated.",
199 [_session sessionID]];
202 /* expiration check */
204 - (void)performExpirationCheck:(NSTimer *)_timer {
205 NSNotificationCenter *nc;
206 NSMutableArray *timedOut = nil;
209 WOSessionInfo *info = nil;
213 //NSLog(@"%s: perform expiration check ...", __PRETTY_FUNCTION__);
215 if (self->activeSessions == NULL)
218 count = NSCountMapTable(self->activeSessions);
220 if (!(count > 0 && (self->activeSessions != NULL)))
223 e = NSEnumerateMapTable(self->activeSessions);
226 /* search for expired sessions */
227 while (NSNextMapEnumeratorPair(&e, (void **)&sid, (void **)&info)) {
228 NSDate *timeOutDate = [info timeoutDate];
230 if (timeOutDate == nil) continue;
232 if ([now compare:timeOutDate] != NSOrderedAscending) {
233 [self logWithFormat:@"session %@ expired at %@.", sid, now];
236 timedOut = [NSMutableArray arrayWithCapacity:32];
237 [timedOut addObject:info];
241 /* Expire sessions */
245 nc = [NSNotificationCenter defaultCenter];
247 for (cnt = 0, count = [timedOut count]; cnt < count; cnt++) {
250 info = [timedOut objectAtIndex:cnt];
251 sid = [[info sessionID] copy];
253 NSMapRemove(self->activeSessions, sid);
254 NSMapRemove(self->idToSession, sid);
256 [nc postNotificationName:WOSessionDidTimeOutNotification
265 - (NSString *)description {
266 return [NSString stringWithFormat:@"<%@[0x%p]: active=%i>",
267 NSStringFromClass([self class]), self,
268 [self activeSessionsCount]
272 @end /* WOServerSessionStore */
274 @implementation WOSessionInfo
276 - (id)initWithSession:(WOSession *)_session {
277 self->sessionID = RETAIN([_session sessionID]);
279 if ([_session respondsToSelector:@selector(timeoutDate)]) {
280 self->timeoutDate = [(id)_session timeoutDate];
283 NSTimeInterval timeOut = [_session timeOut];
285 self->timeoutDate = (timeOut > 0.0)
286 ? [NSDate dateWithTimeIntervalSinceNow:(timeOut + 1.0)]
287 : [NSDate distantFuture];
289 self->timeoutDate = RETAIN(self->timeoutDate);
294 + (WOSessionInfo *)infoForSession:(WOSession *)_session {
295 return AUTORELEASE([[self alloc] initWithSession:_session]);
299 [self->sessionID release];
300 [self->timeoutDate release];
304 - (NSString *)sessionID {
305 return self->sessionID;
307 - (NSDate *)timeoutDate {
308 return self->timeoutDate;
311 @end /* WOSessionInfo */