]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WOServerSessionStore.m
removed bogus line
[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: WOServerSessionStore.m 1 2004-08-20 10:08:27Z znek $
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 warnWithFormat:@"%s: got invalid session id (expected string !): %@",
165             __PRETTY_FUNCTION__, _sid];
166     return nil;
167   }
168   
169   if ([_sid isEqualToString:@"expired"])
170     return nil;
171
172   [self->lock lock];
173   session = NSMapGet(self->idToSession, _sid);
174   [self->lock unlock];
175
176   if (logExpiredSessions) {
177     if (session == nil)
178       [self logWithFormat:@"session with id %@ expired.", _sid];
179   }
180
181   return session;
182 }
183
184 /* termination */
185
186 - (void)sessionExpired:(NSString *)_sessionID {
187   [self->lock lock];
188   NSMapRemove(self->idToSession, _sessionID);
189   [self->lock unlock];
190 }
191
192 - (void)sessionTerminated:(WOSession *)_session {
193   _session = [_session retain];
194   [self->lock lock];
195   NSMapRemove(self->idToSession, [_session sessionID]);
196   [self->lock unlock];
197   [_session release];
198   
199   [[WOApplication application]
200                   logWithFormat:
201                     @"WOServerSessionStore: session %@ terminated.",
202                     [_session sessionID]];
203 }
204
205 /* expiration check */
206
207 - (void)performExpirationCheck:(NSTimer *)_timer {
208   NSNotificationCenter *nc;
209   NSMutableArray  *timedOut = nil;
210   NSMapEnumerator e;
211   NSString        *sid  = nil;
212   WOSessionInfo   *info = nil;
213   NSDate          *now;
214   unsigned cnt, count;
215     
216   //NSLog(@"%s: perform expiration check ...", __PRETTY_FUNCTION__);
217   
218   if (self->activeSessions == NULL)
219     count = 0;
220   else
221     count = NSCountMapTable(self->activeSessions);
222   
223   if (!(count > 0 && (self->activeSessions != NULL)))
224     return;
225   
226   e   = NSEnumerateMapTable(self->activeSessions);
227   now = [NSDate date];
228       
229   /* search for expired sessions */
230   while (NSNextMapEnumeratorPair(&e, (void **)&sid, (void **)&info)) {
231     NSDate *timeOutDate = [info timeoutDate];
232     
233     if (timeOutDate == nil) continue;
234
235     if ([now compare:timeOutDate] != NSOrderedAscending) {
236         [self logWithFormat:@"session %@ expired at %@.", sid, now];
237           
238         if (timedOut == nil)
239           timedOut = [NSMutableArray arrayWithCapacity:32];
240         [timedOut addObject:info];
241     }
242   }
243       
244   /* Expire sessions */
245   if (!timedOut)
246     return;
247
248   nc = [NSNotificationCenter defaultCenter];
249         
250   for (cnt = 0, count = [timedOut count]; cnt < count; cnt++) {
251     NSString *sid;
252           
253         info = [timedOut objectAtIndex:cnt];
254         sid  = [[info sessionID] copy];
255           
256         NSMapRemove(self->activeSessions, sid);
257         NSMapRemove(self->idToSession,    sid);
258           
259         [nc postNotificationName:WOSessionDidTimeOutNotification
260             object:sid];
261
262         [sid release];
263   }
264 }
265
266 /* description */
267
268 - (NSString *)description {
269   return [NSString stringWithFormat:@"<%@[0x%08X]: active=%i>",
270                      NSStringFromClass([self class]), self,
271                      [self activeSessionsCount]
272                    ];
273 }
274
275 @end /* WOServerSessionStore */
276
277 @implementation WOSessionInfo
278
279 - (id)initWithSession:(WOSession *)_session {
280   self->sessionID = RETAIN([_session sessionID]);
281
282   if ([_session respondsToSelector:@selector(timeoutDate)]) {
283     self->timeoutDate = [(id)_session timeoutDate];
284   }
285   else {
286     NSTimeInterval timeOut = [_session timeOut];
287     
288     self->timeoutDate = (timeOut > 0.0)
289       ? [NSDate dateWithTimeIntervalSinceNow:(timeOut + 1.0)]
290       : [NSDate distantFuture];
291   }
292   self->timeoutDate = RETAIN(self->timeoutDate);
293   
294   return self;
295 }
296
297 + (WOSessionInfo *)infoForSession:(WOSession *)_session {
298   return AUTORELEASE([[self alloc] initWithSession:_session]);
299 }
300
301 - (void)dealloc {
302   [self->sessionID   release];
303   [self->timeoutDate release];
304   [super dealloc];
305 }
306
307 - (NSString *)sessionID {
308   return self->sessionID;
309 }
310 - (NSDate *)timeoutDate {
311   return self->timeoutDate;
312 }
313
314 @end /* WOSessionInfo */