2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
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
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.
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
21 // $Id: WOServerSessionStore.m 1 2004-08-20 10:08:27Z znek $
23 #include <NGObjWeb/WOSessionStore.h>
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).
29 If the application goes down, all sessions will go down - this store
30 doesn't provide "session-failover".
33 @interface WOServerSessionStore : WOSessionStore
35 NSMapTable *idToSession;
36 NSMapTable *activeSessions;
40 #include <NGObjWeb/WOContext.h>
41 #include <NGObjWeb/WOApplication.h>
42 #include <NGObjWeb/WOSession.h>
45 /* hh: moved in here from application, check whether it's required ... */
46 @interface WOSessionInfo : NSObject
53 + (WOSessionInfo *)infoForSession:(WOSession *)_session;
55 - (NSString *)sessionID;
56 - (NSDate *)timeoutDate;
60 @implementation WOServerSessionStore
62 static BOOL logExpiredSessions = NO;
65 return [super version] + 0;
68 NSAssert2([super version] == 2,
69 @"invalid superclass (%@) version %i !",
70 NSStringFromClass([self superclass]), [super version]);
74 if ((self = [super init])) {
75 self->idToSession = NSCreateMapTable(NSObjectMapKeyCallBacks,
76 NSObjectMapValueCallBacks,
78 self->activeSessions = NSCreateMapTable(NSObjectMapKeyCallBacks,
79 NSObjectMapValueCallBacks,
81 self->checkedOutSessions = [[NSMutableSet allocWithZone:[self zone]]
84 if ([[[NSUserDefaults standardUserDefaults]
85 objectForKey:@"WORunMultithreaded"]
87 self->lock = [[NSRecursiveLock allocWithZone:[self zone]] init];
88 self->checkoutLock = [[NSConditionLock allocWithZone:[self zone]]
96 if (self->activeSessions) {
97 NSFreeMapTable(self->activeSessions);
98 self->activeSessions = NULL;
100 if (self->idToSession) {
101 NSFreeMapTable(self->idToSession);
102 self->idToSession = NULL;
104 [self->checkedOutSessions release];
105 [self->checkoutLock release];
106 [self->lock release];
112 - (int)activeSessionsCount {
116 count = NSCountMapTable(self->idToSession);
124 - (void)saveSessionForContext:(WOContext *)_context {
125 if (![_context hasSession])
130 WOSession *sn = [_context session];
132 if ([sn isTerminating]) {
135 NSMapRemove(self->idToSession, [sn sessionID]);
136 NSMapRemove(self->activeSessions, [sn sessionID]);
138 NSLog(@"session %@ terminated at %@ ..",
139 [sn sessionID], [NSCalendarDate calendarDate]);
141 [sn release]; sn = nil;
146 NSMapInsert(self->idToSession, [sn sessionID], sn);
148 info = [WOSessionInfo infoForSession:sn];
149 NSMapInsert(self->activeSessions, [sn sessionID], info);
155 - (WOSession *)restoreSessionWithID:(NSString *)_sid
156 request:(WORequest *)_request
158 WOSession *session = nil;
160 if ([_sid length] == 0)
163 if (![_sid isKindOfClass:[NSString class]]) {
164 [self warnWithFormat:@"%s: got invalid session id (expected string !): %@",
165 __PRETTY_FUNCTION__, _sid];
169 if ([_sid isEqualToString:@"expired"])
173 session = NSMapGet(self->idToSession, _sid);
176 if (logExpiredSessions) {
178 [self logWithFormat:@"session with id %@ expired.", _sid];
186 - (void)sessionExpired:(NSString *)_sessionID {
188 NSMapRemove(self->idToSession, _sessionID);
192 - (void)sessionTerminated:(WOSession *)_session {
193 _session = [_session retain];
195 NSMapRemove(self->idToSession, [_session sessionID]);
199 [[WOApplication application]
201 @"WOServerSessionStore: session %@ terminated.",
202 [_session sessionID]];
205 /* expiration check */
207 - (void)performExpirationCheck:(NSTimer *)_timer {
208 NSNotificationCenter *nc;
209 NSMutableArray *timedOut = nil;
212 WOSessionInfo *info = nil;
216 //NSLog(@"%s: perform expiration check ...", __PRETTY_FUNCTION__);
218 if (self->activeSessions == NULL)
221 count = NSCountMapTable(self->activeSessions);
223 if (!(count > 0 && (self->activeSessions != NULL)))
226 e = NSEnumerateMapTable(self->activeSessions);
229 /* search for expired sessions */
230 while (NSNextMapEnumeratorPair(&e, (void **)&sid, (void **)&info)) {
231 NSDate *timeOutDate = [info timeoutDate];
233 if (timeOutDate == nil) continue;
235 if ([now compare:timeOutDate] != NSOrderedAscending) {
236 [self logWithFormat:@"session %@ expired at %@.", sid, now];
239 timedOut = [NSMutableArray arrayWithCapacity:32];
240 [timedOut addObject:info];
244 /* Expire sessions */
248 nc = [NSNotificationCenter defaultCenter];
250 for (cnt = 0, count = [timedOut count]; cnt < count; cnt++) {
253 info = [timedOut objectAtIndex:cnt];
254 sid = [[info sessionID] copy];
256 NSMapRemove(self->activeSessions, sid);
257 NSMapRemove(self->idToSession, sid);
259 [nc postNotificationName:WOSessionDidTimeOutNotification
268 - (NSString *)description {
269 return [NSString stringWithFormat:@"<%@[0x%08X]: active=%i>",
270 NSStringFromClass([self class]), self,
271 [self activeSessionsCount]
275 @end /* WOServerSessionStore */
277 @implementation WOSessionInfo
279 - (id)initWithSession:(WOSession *)_session {
280 self->sessionID = RETAIN([_session sessionID]);
282 if ([_session respondsToSelector:@selector(timeoutDate)]) {
283 self->timeoutDate = [(id)_session timeoutDate];
286 NSTimeInterval timeOut = [_session timeOut];
288 self->timeoutDate = (timeOut > 0.0)
289 ? [NSDate dateWithTimeIntervalSinceNow:(timeOut + 1.0)]
290 : [NSDate distantFuture];
292 self->timeoutDate = RETAIN(self->timeoutDate);
297 + (WOSessionInfo *)infoForSession:(WOSession *)_session {
298 return AUTORELEASE([[self alloc] initWithSession:_session]);
302 [self->sessionID release];
303 [self->timeoutDate release];
307 - (NSString *)sessionID {
308 return self->sessionID;
310 - (NSDate *)timeoutDate {
311 return self->timeoutDate;
314 @end /* WOSessionInfo */