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_ )
251 if (lhs_.size() != rhs_.size())
254 typename T::List lhs = lhs_;
255 QList<typename T::Id> rhs = rhs_;
262 static bool compare(
const QList<typename T::Id> &l1,
const typename T::List &l2)
264 return compare(l2, l1);
267 static bool compare(
const typename T::List &l1,
const typename T::List &l2)
269 typename T::List l1_ = l1;
270 typename T::List l2_ = l2;
278 template <
typename T>
279 struct EntityListCacheNode
281 EntityListCacheNode(
const typename T::List &list ) : entityList( list ), pending( false ), invalid( false ) {}
282 EntityListCacheNode(
const QList<typename T::Id> &list ) : pending( false ), invalid( false ) {
283 foreach(
typename T::Id
id, list)
284 entityList.append(T(
id));
286 typename T::List entityList;
291 template<
typename T,
typename FetchJob,
typename FetchScope_>
292 class EntityListCache :
public EntityCacheBase
295 typedef FetchScope_ FetchScope;
297 explicit EntityListCache(
int maxCapacity, Session *session = 0, QObject *parent = 0 ) :
298 EntityCacheBase( session, parent ),
299 mCapacity( maxCapacity )
304 qDeleteAll( mCache );
308 template<
typename TArg>
309 typename T::List retrieve(
const QList<TArg> &
id )
const
311 EntityListCacheNode<T>* node = cacheNodeForId(
id );
312 if ( node && !node->pending && !node->invalid )
313 return node->entityList;
314 return typename T::List();
318 template<
typename TArg>
319 bool ensureCached(
const QList<TArg> &
id,
const FetchScope &scope )
321 EntityListCacheNode<T>* node = cacheNodeForId(
id );
323 request(
id, scope );
326 return !node->pending;
330 template<
typename TArg>
331 void invalidate(
const QList<TArg> &
id )
333 EntityListCacheNode<T>* node = cacheNodeForId(
id );
335 node->invalid =
true;
339 template<
typename TArg>
340 void update(
const QList<TArg> &
id,
const FetchScope &scope )
342 EntityListCacheNode<T>* node = cacheNodeForId(
id );
344 mCache.removeAll( node );
346 request(
id, scope );
353 template<
typename TArg>
354 bool isCached(
const QList<TArg> &
id )
const
356 EntityListCacheNode<T>* node = cacheNodeForId(
id );
357 return node && !node->pending;
362 typename T::List getTList(
const QList<typename T::Id> &
id )
364 typename T::List ids;
365 foreach(
typename T::Id id_,
id)
370 typename T::List getTList(
const typename T::List &
id )
380 template<
typename TArg>
381 void request(
const QList<TArg> &
id,
const FetchScope &scope )
383 Q_ASSERT( !isRequested(
id ) );
385 EntityListCacheNode<T> *node =
new EntityListCacheNode<T>( id );
386 FetchJob* job = createFetchJob(
id );
387 job->setFetchScope( scope );
388 job->setProperty(
"EntityListCacheNode", QVariant::fromValue<typename T::List>( getTList(
id ) ) );
389 connect( job, SIGNAL(result(KJob*)), SLOT(processResult(KJob*)) );
390 mCache.enqueue( node );
396 while ( mCache.size() >= mCapacity && !mCache.first()->pending )
397 delete mCache.dequeue();
401 template<
typename TArg>
402 bool isRequested(
const QList<TArg> &
id )
const
404 return cacheNodeForId(
id );
407 template<
typename TArg>
408 EntityListCacheNode<T>* cacheNodeForId(
const QList<TArg> &
id )
const
410 for (
typename QQueue<EntityListCacheNode<T>*>::const_iterator it = mCache.constBegin(), endIt = mCache.constEnd();
413 if ( Comparator<T>::compare( ( *it )->entityList,
id ) )
419 template<
typename TArg>
420 inline FetchJob* createFetchJob(
const QList<TArg> &
id )
422 return new FetchJob(
id, session );
425 void processResult( KJob* job )
427 typename T::List ids = job->property(
"EntityListCacheNode" ).template value<typename T::List>();
429 EntityListCacheNode<T> *node = cacheNodeForId( ids );
433 node->pending =
false;
434 extractResult( node, job );
437 if ( node->entityList != ids ) {
438 node->entityList = ids;
439 node->invalid =
true;
441 emit dataAvailable();
444 void extractResult( EntityListCacheNode<T>* node, KJob* job )
const;
448 QQueue<EntityListCacheNode<T>*> mCache;
452 template<>
inline void EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope>::extractResult( EntityListCacheNode<Collection>* node, KJob *job )
const
454 CollectionFetchJob* fetch = qobject_cast<CollectionFetchJob*>( job );
456 node->entityList = fetch->collections();
459 template<>
inline void EntityListCache<Item, ItemFetchJob, ItemFetchScope>::extractResult( EntityListCacheNode<Item>* node, KJob *job )
const
461 ItemFetchJob* fetch = qobject_cast<ItemFetchJob*>( job );
463 node->entityList = fetch->items();
467 template<
typename TArg>
468 inline CollectionFetchJob* EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope>::createFetchJob(
const QList<TArg> &
id )
473 typedef EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope> CollectionListCache;
474 typedef EntityListCache<Item, ItemFetchJob, ItemFetchScope> ItemListCache;