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 ) {
119 EntityCacheNode<T>* node = cacheNodeForId(
id );
121 node->invalid =
true;
126 void update(
typename T::Id
id,
const FetchScope &scope )
128 EntityCacheNode<T>* node = cacheNodeForId(
id );
130 mCache.removeAll( node );
131 if ( node->pending ) {
139 virtual bool ensureCached(
typename T::Id
id,
const FetchScope &scope )
141 EntityCacheNode<T>* node = cacheNodeForId(
id );
146 return !node->pending;
154 virtual void request(
typename T::Id
id,
const FetchScope &scope )
158 EntityCacheNode<T> *node =
new EntityCacheNode<T>( id );
159 FetchJob* job = createFetchJob(
id );
160 job->setFetchScope( scope );
161 job->setProperty(
"EntityCacheNode", QVariant::fromValue<typename T::Id>(
id ) );
162 connect( job, SIGNAL( result( KJob* )), SLOT(processResult( KJob* ) ) );
163 mCache.enqueue( node );
167 EntityCacheNode<T>* cacheNodeForId(
typename T::Id
id )
const
169 for (
typename QQueue<EntityCacheNode<T>*>::const_iterator it = mCache.constBegin(), endIt = mCache.constEnd();
170 it != endIt; ++it ) {
171 if ( ( *it )->entity.id() == id ) {
178 void processResult( KJob* job )
181 typename T::Id
id = job->property(
"EntityCacheNode" ).template value<typename T::Id>();
182 EntityCacheNode<T> *node = cacheNodeForId(
id );
187 node->pending =
false;
188 extractResult( node, job );
191 if ( node->entity.id() != id ) {
193 node->entity.setId(
id );
194 node->invalid =
true;
196 emit dataAvailable();
199 void extractResult( EntityCacheNode<T>* node, KJob* job )
const;
201 inline FetchJob* createFetchJob(
typename T::Id
id )
203 return new FetchJob( T(
id ), session );
209 while ( mCache.size() >= mCapacity && !mCache.first()->pending ) {
210 delete mCache.dequeue();
215 QQueue<EntityCacheNode<T>*> mCache;
219 template<>
inline void EntityCache<Collection, CollectionFetchJob, CollectionFetchScope>::extractResult( EntityCacheNode<Collection>* node, KJob *job )
const
221 CollectionFetchJob* fetch = qobject_cast<CollectionFetchJob*>( job );
223 if ( fetch->collections().isEmpty() ) {
224 node->entity = Collection();
226 node->entity = fetch->collections().first();
230 template<>
inline void EntityCache<Item, ItemFetchJob, ItemFetchScope>::extractResult( EntityCacheNode<Item>* node, KJob *job )
const
232 ItemFetchJob* fetch = qobject_cast<ItemFetchJob*>( job );
234 if ( fetch->items().isEmpty() ) {
235 node->entity = Item();
237 node->entity = fetch->items().first();
241 template<>
inline CollectionFetchJob* EntityCache<Collection, CollectionFetchJob, CollectionFetchScope>::createFetchJob(
Collection::Id id )
246 typedef EntityCache<Collection, CollectionFetchJob, CollectionFetchScope> CollectionCache;
247 typedef EntityCache<Item, ItemFetchJob, ItemFetchScope> ItemCache;
254 static bool compare(
const typename T::List &lhs_,
const QList<typename T::Id> &rhs_ )
256 if ( lhs_.size() != rhs_.size() ) {
260 typename T::List lhs = lhs_;
261 QList<typename T::Id> rhs = rhs_;
268 static bool compare(
const QList<typename T::Id> &l1,
const typename T::List &l2)
270 return compare( l2, l1 );
273 static bool compare(
const typename T::List &l1,
const typename T::List &l2)
275 typename T::List l1_ = l1;
276 typename T::List l2_ = l2;
284 template <
typename T>
285 struct EntityListCacheNode
287 EntityListCacheNode(
const typename T::List &list ) : entityList( list ), pending( false ), invalid( false ) {}
288 EntityListCacheNode(
const QList<typename T::Id> &list ) : pending( false ), invalid( false ) {
289 foreach (
typename T::Id
id, list ) {
290 entityList.append( T(
id ) );
293 typename T::List entityList;
298 template<
typename T,
typename FetchJob,
typename FetchScope_>
299 class EntityListCache :
public EntityCacheBase
302 typedef FetchScope_ FetchScope;
304 explicit EntityListCache(
int maxCapacity, Session *session = 0, QObject *parent = 0 ) :
305 EntityCacheBase( session, parent ),
306 mCapacity( maxCapacity )
311 qDeleteAll( mCache );
315 template<
typename TArg>
316 typename T::List retrieve(
const QList<TArg> &
id )
const
318 EntityListCacheNode<T>* node = cacheNodeForId(
id );
319 if ( node && !node->pending && !node->invalid ) {
320 return node->entityList;
322 return typename T::List();
326 template<
typename TArg>
327 bool ensureCached(
const QList<TArg> &
id,
const FetchScope &scope )
329 EntityListCacheNode<T>* node = cacheNodeForId(
id );
331 request(
id, scope );
334 return !node->pending;
338 template<
typename TArg>
339 void invalidate(
const QList<TArg> &
id )
341 EntityListCacheNode<T>* node = cacheNodeForId(
id );
343 node->invalid =
true;
348 template<
typename TArg>
349 void update(
const QList<TArg> &
id,
const FetchScope &scope )
351 EntityListCacheNode<T>* node = cacheNodeForId(
id );
353 mCache.removeAll( node );
354 if ( node->pending ) {
355 request(
id, scope );
363 template<
typename TArg>
364 bool isCached(
const QList<TArg> &
id )
const
366 EntityListCacheNode<T>* node = cacheNodeForId(
id );
367 return node && !node->pending;
372 typename T::List getTList(
const QList<typename T::Id> &
id )
374 typename T::List ids;
375 foreach (
typename T::Id id_,
id ) {
376 ids.append( T( id_ ) );
381 typename T::List getTList(
const typename T::List &
id )
391 template<
typename TArg>
392 void request(
const QList<TArg> &
id,
const FetchScope &scope )
394 Q_ASSERT( !isRequested(
id ) );
396 EntityListCacheNode<T> *node =
new EntityListCacheNode<T>( id );
397 FetchJob* job = createFetchJob(
id );
398 job->setFetchScope( scope );
399 job->setProperty(
"EntityListCacheNode", QVariant::fromValue<typename T::List>( getTList(
id ) ) );
400 connect( job, SIGNAL(result(KJob*)), SLOT(processResult(KJob*)) );
401 mCache.enqueue( node );
407 while ( mCache.size() >= mCapacity && !mCache.first()->pending ) {
408 delete mCache.dequeue();
413 template<
typename TArg>
414 bool isRequested(
const QList<TArg> &
id )
const
416 return cacheNodeForId(
id );
419 template<
typename TArg>
420 EntityListCacheNode<T>* cacheNodeForId(
const QList<TArg> &
id )
const
422 for (
typename QQueue<EntityListCacheNode<T>*>::const_iterator it = mCache.constBegin(), endIt = mCache.constEnd();
423 it != endIt; ++it ) {
424 if ( Comparator<T>::compare( ( *it )->entityList,
id ) ) {
431 template<
typename TArg>
432 inline FetchJob* createFetchJob(
const QList<TArg> &
id )
434 return new FetchJob(
id, session );
437 void processResult( KJob* job )
439 typename T::List ids = job->property(
"EntityListCacheNode" ).template value<typename T::List>();
441 EntityListCacheNode<T> *node = cacheNodeForId( ids );
446 node->pending =
false;
447 extractResult( node, job );
450 if ( node->entityList != ids ) {
451 node->entityList = ids;
452 node->invalid =
true;
454 emit dataAvailable();
457 void extractResult( EntityListCacheNode<T>* node, KJob* job )
const;
461 QQueue<EntityListCacheNode<T>*> mCache;
465 template<>
inline void EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope>::extractResult( EntityListCacheNode<Collection>* node, KJob *job )
const
467 CollectionFetchJob* fetch = qobject_cast<CollectionFetchJob*>( job );
469 node->entityList = fetch->collections();
472 template<>
inline void EntityListCache<Item, ItemFetchJob, ItemFetchScope>::extractResult( EntityListCacheNode<Item>* node, KJob *job )
const
474 ItemFetchJob* fetch = qobject_cast<ItemFetchJob*>( job );
476 node->entityList = fetch->items();
480 template<
typename TArg>
481 inline CollectionFetchJob* EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope>::createFetchJob(
const QList<TArg> &
id )
486 typedef EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope> CollectionListCache;
487 typedef EntityListCache<Item, ItemFetchJob, ItemFetchScope> ItemListCache;