]> err.no Git - sope/blob - sope-core/NGExtensions/EOExt.subproj/EOCacheDataSource.m
7c20334073e256885ede79907e95f4dc60ac1215
[sope] / sope-core / NGExtensions / EOExt.subproj / EOCacheDataSource.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 //#define PROFILE 1
24
25 #include "EOCacheDataSource.h"
26 #import <EOControl/EOControl.h>
27 #import "EODataSource+NGExtensions.h"
28 #import "common.h"
29 #include <sys/time.h>
30
31 @interface EOCacheDataSource(Private)
32 - (void)_registerForSource:(id)_source;
33 - (void)_removeObserverForSource:(id)_source;
34 - (void)_clearCache;
35 @end
36
37 @implementation EOCacheDataSource
38
39 - (id)initWithDataSource:(EODataSource *)_ds {
40   if ((self = [super init])) {
41     self->source  = [_ds retain];
42     self->timeout = 0;
43     self->timer   = nil;
44     self->time    = 0;
45     [self _registerForSource:self->source];
46   }
47   return self;
48 }
49
50 - (void)dealloc {
51   [self _removeObserverForSource:self->source];
52   [self->timer invalidate];
53   [self->timer  release];
54   [self->source release];
55   [self->cache  release];
56   [super dealloc];
57 }
58
59 /* accessors */
60
61 - (void)setSource:(EODataSource *)_source {
62   [self _removeObserverForSource:self->source];
63   ASSIGN(self->source, _source);
64   [self _registerForSource:self->source];
65   [self _clearCache];
66 }
67
68 - (EODataSource *)source {
69   return self->source;
70 }
71
72 - (void)setTimeout:(NSTimeInterval)_timeout {
73   self->timeout = _timeout;
74 }
75 - (NSTimeInterval)timeout {
76   return self->timeout;
77 }
78
79 /* operations */
80
81 - (NSArray *)fetchObjects {
82   BEGIN_PROFILE;
83
84   self->_isFetching = YES;
85   
86   if (self->time > 0) {
87     if (self->time < [[NSDate date] timeIntervalSinceReferenceDate]) {
88       [self->cache release]; self->cache = nil;
89     }
90   }
91   if (self->cache == nil) {
92     self->time = 0;
93     if (self->timer != nil) {
94       [self->timer invalidate];
95       [self->timer release]; self->timer = nil;
96     }
97     
98     self->cache = [[self->source fetchObjects] retain];
99     
100     if (self->timeout > 0) {
101       self->time =
102         [[NSDate date] timeIntervalSinceReferenceDate] + self->timeout;
103       
104       self->timer = [NSTimer scheduledTimerWithTimeInterval:self->timeout
105                              target:self
106                              selector:@selector(clear)
107                              userInfo:nil repeats:NO];
108       self->timer = [self->timer retain];
109     }
110     PROFILE_CHECKPOINT("cache miss");
111   }
112   else {
113     PROFILE_CHECKPOINT("cache hit");
114   }
115   
116   self->_isFetching = NO;
117   END_PROFILE;
118   return self->cache;
119 }
120
121 - (EOFetchSpecification *)fetchSpecification {
122   return [self->source fetchSpecification];
123 }
124
125 - (void)setFetchSpecification:(EOFetchSpecification *)_fetchSpec {
126   [self->source setFetchSpecification:_fetchSpec];
127 }
128
129 - (void)insertObject:(id)_obj {
130   [self _clearCache];
131   [self->source insertObject:_obj];
132 }
133
134 - (void)deleteObject:(id)_obj {
135   [self _clearCache];
136   [self->source deleteObject:_obj];
137 }
138
139 - (id)createObject {
140   return [self->source createObject];
141 }
142
143 - (void)updateObject:(id)_obj {
144   [self->source updateObject:_obj];
145   [self _clearCache];  
146 }
147
148 - (EOClassDescription *)classDescriptionForObjects {
149   return [[self source] classDescriptionForObjects];
150 }
151
152 - (void)clear {
153   [self _clearCache];
154 }
155
156 /* description */
157
158 - (NSString *)description {
159   NSString *fmt;
160
161   fmt = [NSString stringWithFormat:@"<%@[0x%08X]: source=%@>",
162                     NSStringFromClass([self class]), self,
163                     self->source];
164   return fmt;
165 }
166
167 @end /* EOCacheDataSource */
168
169 @implementation EOCacheDataSource(Private)
170
171 - (void)_registerForSource:(id)_source {
172   static NSNotificationCenter *nc = nil;
173
174   if (_source != nil) {
175     if (nc == nil)
176       nc = [[NSNotificationCenter defaultCenter] retain];
177     
178     [nc addObserver:self selector:@selector(_clearCache)
179         name:EODataSourceDidChangeNotification object:_source];
180   }
181 }
182
183 - (void)_removeObserverForSource:(id)_source {
184   static NSNotificationCenter *nc = nil;
185
186   if (_source != nil) {
187     if (nc == nil)
188       nc = [NSNotificationCenter defaultCenter];
189     [nc removeObserver:self name:EODataSourceDidChangeNotification
190         object:_source];
191   }
192 }
193
194  
195 - (void)_clearCache {
196 #if DEBUG && 0
197   NSLog(@"clearing cache (%s)...", self->_isFetching?"fetching":"");
198   if (fgetc(stdin) == 'a')
199     abort();
200 #endif
201   
202   self->time = 0;
203   
204   if (self->timer) {
205     [self->timer invalidate];
206     [self->timer release]; self->timer = nil;
207   }
208   
209   if (self->cache) {
210     [self->cache release]; self->cache = nil;
211     [self postDataSourceChangedNotification];
212   }
213 }
214
215 @end /* EOCacheDataSource(Private) */