20 #ifndef AKONADI_ENTITYCACHE_P_H
21 #define AKONADI_ENTITYCACHE_P_H
23 #include <akonadi/item.h>
24 #include <akonadi/itemfetchjob.h>
25 #include <akonadi/itemfetchscope.h>
26 #include <akonadi/collection.h>
27 #include <akonadi/collectionfetchjob.h>
28 #include <akonadi/collectionfetchscope.h>
29 #include <akonadi/session.h>
31 #include "akonadiprivate_export.h"
36 #include <QtCore/QQueue>
52 void setSession(
Session *session);
61 virtual void processResult( KJob* job ) = 0;
65 struct EntityCacheNode
67 EntityCacheNode() : pending( false ), invalid( false ) {}
68 EntityCacheNode(
typename T::Id
id ) : entity( T( id ) ), pending( true ), invalid( false ) {}
78 template<
typename T,
typename FetchJob,
typename FetchScope_>
82 typedef FetchScope_ FetchScope;
85 mCapacity( maxCapacity )
96 EntityCacheNode<T>* node = cacheNodeForId(
id );
97 return node && !node->pending;
103 return cacheNodeForId(
id );
109 EntityCacheNode<T>* node = cacheNodeForId(
id );
110 if ( node && !node->pending && !node->invalid )
118 EntityCacheNode<T>* node = cacheNodeForId(
id );
120 node->invalid =
true;
124 void update(
typename T::Id
id,
const FetchScope &scope )
126 EntityCacheNode<T>* node = cacheNodeForId(
id );
128 mCache.removeAll( node );
136 virtual bool ensureCached(
typename T::Id
id,
const FetchScope &scope )
138 EntityCacheNode<T>* node = cacheNodeForId(
id );
143 return !node->pending;
151 virtual void request(
typename T::Id
id,
const FetchScope &scope )
155 EntityCacheNode<T> *node =
new EntityCacheNode<T>( id );
156 FetchJob* job = createFetchJob(
id );
157 job->setFetchScope( scope );
158 job->setProperty(
"EntityCacheNode", QVariant::fromValue<typename T::Id>(
id ) );
159 connect( job, SIGNAL( result( KJob* )), SLOT(processResult( KJob* ) ) );
160 mCache.enqueue( node );
164 EntityCacheNode<T>* cacheNodeForId(
typename T::Id
id )
const
166 for (
typename QQueue<EntityCacheNode<T>*>::const_iterator it = mCache.constBegin(), endIt = mCache.constEnd();
169 if ( (*it)->entity.id() == id )
175 void processResult( KJob* job )
178 typename T::Id
id = job->property(
"EntityCacheNode" ).template value<typename T::Id>();
179 EntityCacheNode<T> *node = cacheNodeForId(
id );
183 node->pending =
false;
184 extractResult( node, job );
187 if ( node->entity.id() != id ) {
189 node->entity.setId(
id );
190 node->invalid =
true;
192 emit dataAvailable();
195 void extractResult( EntityCacheNode<T>* node, KJob* job )
const;
197 inline FetchJob* createFetchJob(
typename T::Id
id )
199 return new FetchJob( T(
id ), session );
205 while ( mCache.size() >= mCapacity && !mCache.first()->pending )
206 delete mCache.dequeue();
210 QQueue<EntityCacheNode<T>*> mCache;
214 template<>
inline void EntityCache<Collection, CollectionFetchJob, CollectionFetchScope>::extractResult( EntityCacheNode<Collection>* node, KJob *job )
const
216 CollectionFetchJob* fetch = qobject_cast<CollectionFetchJob*>( job );
218 if ( fetch->collections().isEmpty() )
219 node->entity = Collection();
221 node->entity = fetch->collections().first();
224 template<>
inline void EntityCache<Item, ItemFetchJob, ItemFetchScope>::extractResult( EntityCacheNode<Item>* node, KJob *job )
const
226 ItemFetchJob* fetch = qobject_cast<ItemFetchJob*>( job );
228 if ( fetch->items().isEmpty() )
229 node->entity = Item();
231 node->entity = fetch->items().first();
234 template<>
inline CollectionFetchJob* EntityCache<Collection, CollectionFetchJob, CollectionFetchScope>::createFetchJob(
Collection::Id id )
239 typedef EntityCache<Collection, CollectionFetchJob, CollectionFetchScope> CollectionCache;
240 typedef EntityCache<Item, ItemFetchJob, ItemFetchScope> ItemCache;
247 static bool compare(
const typename T::List &lhs_,
const QList<typename T::Id> &rhs_ )
249 if (lhs_.size() != rhs_.size())
252 typename T::List lhs = lhs_;
253 QList<typename T::Id> rhs = rhs_;
260 static bool compare(
const QList<typename T::Id> &l1,
const typename T::List &l2)
262 return compare(l2, l1);
265 static bool compare(
const typename T::List &l1,
const typename T::List &l2)
267 typename T::List l1_ = l1;
268 typename T::List l2_ = l2;
276 template <
typename T>
277 struct EntityListCacheNode
279 EntityListCacheNode(
const typename T::List &list ) : entityList( list ), pending( false ), invalid( false ) {}
280 EntityListCacheNode(
const QList<typename T::Id> &list ) : pending( false ), invalid( false ) {
281 foreach(
typename T::Id
id, list)
282 entityList.append(T(
id));
284 typename T::List entityList;
289 template<
typename T,
typename FetchJob,
typename FetchScope_>
290 class EntityListCache :
public EntityCacheBase
293 typedef FetchScope_ FetchScope;
295 explicit EntityListCache(
int maxCapacity, Session *session = 0, QObject *parent = 0 ) :
296 EntityCacheBase( session, parent ),
297 mCapacity( maxCapacity )
302 qDeleteAll( mCache );
306 template<
typename TArg>
307 typename T::List retrieve(
const QList<TArg> &
id )
const
309 EntityListCacheNode<T>* node = cacheNodeForId(
id );
310 if ( node && !node->pending && !node->invalid )
311 return node->entityList;
312 return typename T::List();
316 template<
typename TArg>
317 bool ensureCached(
const QList<TArg> &
id,
const FetchScope &scope )
319 EntityListCacheNode<T>* node = cacheNodeForId(
id );
321 request(
id, scope );
324 return !node->pending;
328 template<
typename TArg>
329 void invalidate(
const QList<TArg> &
id )
331 EntityListCacheNode<T>* node = cacheNodeForId(
id );
333 node->invalid =
true;
337 template<
typename TArg>
338 void update(
const QList<TArg> &
id,
const FetchScope &scope )
340 EntityListCacheNode<T>* node = cacheNodeForId(
id );
342 mCache.removeAll( node );
344 request(
id, scope );
351 template<
typename TArg>
352 bool isCached(
const QList<TArg> &
id )
const
354 EntityListCacheNode<T>* node = cacheNodeForId(
id );
355 return node && !node->pending;
360 typename T::List getTList(
const QList<typename T::Id> &
id )
362 typename T::List ids;
363 foreach(
typename T::Id id_,
id)
368 typename T::List getTList(
const typename T::List &
id )
378 template<
typename TArg>
379 void request(
const QList<TArg> &
id,
const FetchScope &scope )
381 Q_ASSERT( !isRequested(
id ) );
383 EntityListCacheNode<T> *node =
new EntityListCacheNode<T>( id );
384 FetchJob* job = createFetchJob(
id );
385 job->setFetchScope( scope );
386 job->setProperty(
"EntityListCacheNode", QVariant::fromValue<typename T::List>( getTList(
id ) ) );
387 connect( job, SIGNAL(result(KJob*)), SLOT(processResult(KJob*)) );
388 mCache.enqueue( node );
394 while ( mCache.size() >= mCapacity && !mCache.first()->pending )
395 delete mCache.dequeue();
399 template<
typename TArg>
400 bool isRequested(
const QList<TArg> &
id )
const
402 return cacheNodeForId(
id );
405 template<
typename TArg>
406 EntityListCacheNode<T>* cacheNodeForId(
const QList<TArg> &
id )
const
408 for (
typename QQueue<EntityListCacheNode<T>*>::const_iterator it = mCache.constBegin(), endIt = mCache.constEnd();
411 if ( Comparator<T>::compare( ( *it )->entityList,
id ) )
417 template<
typename TArg>
418 inline FetchJob* createFetchJob(
const QList<TArg> &
id )
420 return new FetchJob(
id, session );
423 void processResult( KJob* job )
425 typename T::List ids = job->property(
"EntityListCacheNode" ).template value<typename T::List>();
427 EntityListCacheNode<T> *node = cacheNodeForId( ids );
431 node->pending =
false;
432 extractResult( node, job );
435 if ( node->entityList != ids ) {
436 node->entityList = ids;
437 node->invalid =
true;
439 emit dataAvailable();
442 void extractResult( EntityListCacheNode<T>* node, KJob* job )
const;
446 QQueue<EntityListCacheNode<T>*> mCache;
450 template<>
inline void EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope>::extractResult( EntityListCacheNode<Collection>* node, KJob *job )
const
452 CollectionFetchJob* fetch = qobject_cast<CollectionFetchJob*>( job );
454 node->entityList = fetch->collections();
457 template<>
inline void EntityListCache<Item, ItemFetchJob, ItemFetchScope>::extractResult( EntityListCacheNode<Item>* node, KJob *job )
const
459 ItemFetchJob* fetch = qobject_cast<ItemFetchJob*>( job );
461 node->entityList = fetch->items();
465 template<
typename TArg>
466 inline CollectionFetchJob* EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope>::createFetchJob(
const QList<TArg> &
id )
471 typedef EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope> CollectionListCache;
472 typedef EntityListCache<Item, ItemFetchJob, ItemFetchScope> ItemListCache;