• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.5 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
entitycache_p.h
1 /*
2  Copyright (c) 2009 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #ifndef AKONADI_ENTITYCACHE_P_H
21 #define AKONADI_ENTITYCACHE_P_H
22 
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>
30 
31 #include "akonadiprivate_export.h"
32 
33 #include <qobject.h>
34 #include <QQueue>
35 #include <QVariant>
36 #include <QtCore/QQueue>
37 
38 class KJob;
39 
40 namespace Akonadi {
41 
46 class AKONADI_TESTS_EXPORT EntityCacheBase : public QObject
47 {
48  Q_OBJECT
49  public:
50  explicit EntityCacheBase ( Session *session, QObject * parent = 0 );
51 
52  void setSession(Session *session);
53 
54  protected:
55  Session *session;
56 
57  signals:
58  void dataAvailable();
59 
60  private slots:
61  virtual void processResult( KJob* job ) = 0;
62 };
63 
64 template <typename T>
65 struct EntityCacheNode
66 {
67  EntityCacheNode() : pending( false ), invalid( false ) {}
68  EntityCacheNode( typename T::Id id ) : entity( T( id ) ), pending( true ), invalid( false ) {}
69  T entity;
70  bool pending;
71  bool invalid;
72 };
73 
78 template<typename T, typename FetchJob, typename FetchScope_>
79 class EntityCache : public EntityCacheBase
80 {
81  public:
82  typedef FetchScope_ FetchScope;
83  explicit EntityCache( int maxCapacity, Session *session = 0, QObject *parent = 0 ) :
84  EntityCacheBase( session, parent ),
85  mCapacity( maxCapacity )
86  {}
87 
88  ~EntityCache()
89  {
90  qDeleteAll( mCache );
91  }
92 
94  bool isCached( typename T::Id id ) const
95  {
96  EntityCacheNode<T>* node = cacheNodeForId( id );
97  return node && !node->pending;
98  }
99 
101  bool isRequested( typename T::Id id ) const
102  {
103  return cacheNodeForId( id );
104  }
105 
107  virtual T retrieve( typename T::Id id ) const
108  {
109  EntityCacheNode<T>* node = cacheNodeForId( id );
110  if ( node && !node->pending && !node->invalid )
111  return node->entity;
112  return T();
113  }
114 
116  void invalidate( typename T::Id id )
117  {
118  EntityCacheNode<T>* node = cacheNodeForId( id );
119  if ( node )
120  node->invalid = true;
121  }
122 
124  void update( typename T::Id id, const FetchScope &scope )
125  {
126  EntityCacheNode<T>* node = cacheNodeForId( id );
127  if ( node ) {
128  mCache.removeAll( node );
129  if ( node->pending )
130  request( id, scope );
131  delete node;
132  }
133  }
134 
136  virtual bool ensureCached( typename T::Id id, const FetchScope &scope )
137  {
138  EntityCacheNode<T>* node = cacheNodeForId( id );
139  if ( !node ) {
140  request( id, scope );
141  return false;
142  }
143  return !node->pending;
144  }
145 
151  virtual void request( typename T::Id id, const FetchScope &scope )
152  {
153  Q_ASSERT( !isRequested( id ) );
154  shrinkCache();
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 );
161  }
162 
163  private:
164  EntityCacheNode<T>* cacheNodeForId( typename T::Id id ) const
165  {
166  for ( typename QQueue<EntityCacheNode<T>*>::const_iterator it = mCache.constBegin(), endIt = mCache.constEnd();
167  it != endIt; ++it )
168  {
169  if ( (*it)->entity.id() == id )
170  return *it;
171  }
172  return 0;
173  }
174 
175  void processResult( KJob* job )
176  {
177  // Error handling?
178  typename T::Id id = job->property( "EntityCacheNode" ).template value<typename T::Id>();
179  EntityCacheNode<T> *node = cacheNodeForId( id );
180  if ( !node )
181  return; // got replaced in the meantime
182 
183  node->pending = false;
184  extractResult( node, job );
185  // make sure we find this node again if something went wrong here,
186  // most likely the object got deleted from the server in the meantime
187  if ( node->entity.id() != id ) {
188  // TODO: Recursion guard? If this is called with non-existing ids, the if will never be true!
189  node->entity.setId( id );
190  node->invalid = true;
191  }
192  emit dataAvailable();
193  }
194 
195  void extractResult( EntityCacheNode<T>* node, KJob* job ) const;
196 
197  inline FetchJob* createFetchJob( typename T::Id id )
198  {
199  return new FetchJob( T( id ), session );
200  }
201 
203  void shrinkCache()
204  {
205  while ( mCache.size() >= mCapacity && !mCache.first()->pending )
206  delete mCache.dequeue();
207  }
208 
209  private:
210  QQueue<EntityCacheNode<T>*> mCache;
211  int mCapacity;
212 };
213 
214 template<> inline void EntityCache<Collection, CollectionFetchJob, CollectionFetchScope>::extractResult( EntityCacheNode<Collection>* node, KJob *job ) const
215 {
216  CollectionFetchJob* fetch = qobject_cast<CollectionFetchJob*>( job );
217  Q_ASSERT( fetch );
218  if ( fetch->collections().isEmpty() )
219  node->entity = Collection();
220  else
221  node->entity = fetch->collections().first();
222 }
223 
224 template<> inline void EntityCache<Item, ItemFetchJob, ItemFetchScope>::extractResult( EntityCacheNode<Item>* node, KJob *job ) const
225 {
226  ItemFetchJob* fetch = qobject_cast<ItemFetchJob*>( job );
227  Q_ASSERT( fetch );
228  if ( fetch->items().isEmpty() )
229  node->entity = Item();
230  else
231  node->entity = fetch->items().first();
232 }
233 
234 template<> inline CollectionFetchJob* EntityCache<Collection, CollectionFetchJob, CollectionFetchScope>::createFetchJob( Collection::Id id )
235 {
236  return new CollectionFetchJob( Collection( id ), CollectionFetchJob::Base, session );
237 }
238 
239 typedef EntityCache<Collection, CollectionFetchJob, CollectionFetchScope> CollectionCache;
240 typedef EntityCache<Item, ItemFetchJob, ItemFetchScope> ItemCache;
241 
242 
243 template<typename T>
244 class Comparator
245 {
246 public:
247  static bool compare(const typename T::List &lhs_, const QList<typename T::Id> &rhs_ )
248  {
249  if (lhs_.size() != rhs_.size())
250  return false;
251 
252  typename T::List lhs = lhs_;
253  QList<typename T::Id> rhs = rhs_;
254 
255  qSort(lhs);
256  qSort(rhs);
257  return lhs == rhs;
258  }
259 
260  static bool compare(const QList<typename T::Id> &l1, const typename T::List &l2)
261  {
262  return compare(l2, l1);
263  }
264 
265  static bool compare(const typename T::List &l1, const typename T::List &l2)
266  {
267  typename T::List l1_ = l1;
268  typename T::List l2_ = l2;
269  qSort(l1_);
270  qSort(l2_);
271  return l1_ == l2_;
272  }
273 };
274 
275 
276 template <typename T>
277 struct EntityListCacheNode
278 {
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));
283  }
284  typename T::List entityList;
285  bool pending;
286  bool invalid;
287 };
288 
289 template<typename T, typename FetchJob, typename FetchScope_>
290 class EntityListCache : public EntityCacheBase
291 {
292 public:
293  typedef FetchScope_ FetchScope;
294 
295  explicit EntityListCache( int maxCapacity, Session *session = 0, QObject *parent = 0 ) :
296  EntityCacheBase( session, parent ),
297  mCapacity( maxCapacity )
298  {}
299 
300  ~EntityListCache()
301  {
302  qDeleteAll( mCache );
303  }
304 
306  template<typename TArg>
307  typename T::List retrieve( const QList<TArg> &id ) const
308  {
309  EntityListCacheNode<T>* node = cacheNodeForId( id );
310  if ( node && !node->pending && !node->invalid )
311  return node->entityList;
312  return typename T::List();
313  }
314 
316  template<typename TArg>
317  bool ensureCached( const QList<TArg> &id, const FetchScope &scope )
318  {
319  EntityListCacheNode<T>* node = cacheNodeForId( id );
320  if ( !node ) {
321  request( id, scope );
322  return false;
323  }
324  return !node->pending;
325  }
326 
328  template<typename TArg>
329  void invalidate( const QList<TArg> &id )
330  {
331  EntityListCacheNode<T>* node = cacheNodeForId( id );
332  if ( node )
333  node->invalid = true;
334  }
335 
337  template<typename TArg>
338  void update( const QList<TArg> &id, const FetchScope &scope )
339  {
340  EntityListCacheNode<T>* node = cacheNodeForId( id );
341  if ( node ) {
342  mCache.removeAll( node );
343  if ( node->pending )
344  request( id, scope );
345  delete node;
346  }
347  }
348 
349 
351  template<typename TArg>
352  bool isCached( const QList<TArg> &id ) const
353  {
354  EntityListCacheNode<T>* node = cacheNodeForId( id );
355  return node && !node->pending;
356  }
357 
358 private:
359 
360  typename T::List getTList( const QList<typename T::Id> &id )
361  {
362  typename T::List ids;
363  foreach(typename T::Id id_, id)
364  ids.append(T(id_));
365  return ids;
366  }
367 
368  typename T::List getTList( const typename T::List &id )
369  {
370  return id;
371  }
372 
378  template<typename TArg>
379  void request( const QList<TArg> &id, const FetchScope &scope )
380  {
381  Q_ASSERT( !isRequested( id ) );
382  shrinkCache();
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 );
389  }
390 
392  void shrinkCache()
393  {
394  while ( mCache.size() >= mCapacity && !mCache.first()->pending )
395  delete mCache.dequeue();
396  }
397 
399  template<typename TArg>
400  bool isRequested( const QList<TArg> &id ) const
401  {
402  return cacheNodeForId( id );
403  }
404 
405  template<typename TArg>
406  EntityListCacheNode<T>* cacheNodeForId( const QList<TArg> &id ) const
407  {
408  for ( typename QQueue<EntityListCacheNode<T>*>::const_iterator it = mCache.constBegin(), endIt = mCache.constEnd();
409  it != endIt; ++it )
410  {
411  if ( Comparator<T>::compare( ( *it )->entityList, id ) )
412  return *it;
413  }
414  return 0;
415  }
416 
417  template<typename TArg>
418  inline FetchJob* createFetchJob( const QList<TArg> &id )
419  {
420  return new FetchJob( id, session );
421  }
422 
423  void processResult( KJob* job )
424  {
425  typename T::List ids = job->property( "EntityListCacheNode" ).template value<typename T::List>();
426 
427  EntityListCacheNode<T> *node = cacheNodeForId( ids );
428  if ( !node )
429  return; // got replaced in the meantime
430 
431  node->pending = false;
432  extractResult( node, job );
433  // make sure we find this node again if something went wrong here,
434  // most likely the object got deleted from the server in the meantime
435  if ( node->entityList != ids ) {
436  node->entityList = ids;
437  node->invalid = true;
438  }
439  emit dataAvailable();
440  }
441 
442  void extractResult( EntityListCacheNode<T>* node, KJob* job ) const;
443 
444 
445 private:
446  QQueue<EntityListCacheNode<T>*> mCache;
447  int mCapacity;
448 };
449 
450 template<> inline void EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope>::extractResult( EntityListCacheNode<Collection>* node, KJob *job ) const
451 {
452  CollectionFetchJob* fetch = qobject_cast<CollectionFetchJob*>( job );
453  Q_ASSERT( fetch );
454  node->entityList = fetch->collections();
455 }
456 
457 template<> inline void EntityListCache<Item, ItemFetchJob, ItemFetchScope>::extractResult( EntityListCacheNode<Item>* node, KJob *job ) const
458 {
459  ItemFetchJob* fetch = qobject_cast<ItemFetchJob*>( job );
460  Q_ASSERT( fetch );
461  node->entityList = fetch->items();
462 }
463 
464 template<>
465 template<typename TArg>
466 inline CollectionFetchJob* EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope>::createFetchJob( const QList<TArg> &id )
467 {
468  return new CollectionFetchJob( id, CollectionFetchJob::Base, session );
469 }
470 
471 typedef EntityListCache<Collection, CollectionFetchJob, CollectionFetchScope> CollectionListCache;
472 typedef EntityListCache<Item, ItemFetchJob, ItemFetchScope> ItemListCache;
473 
474 }
475 
476 #endif
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jan 5 2013 19:46:03 by doxygen 1.8.1.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.9.5 API Reference

Skip menu "kdepimlibs-4.9.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal