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

akonadi

  • akonadi
job.cpp
1 /*
2  Copyright (c) 2006 Tobias Koenig <tokoe@kde.org>
3  2006 Marc Mutz <mutz@kde.org>
4  2006 - 2007 Volker Krause <vkrause@kde.org>
5 
6  This library is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Library General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or (at your
9  option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14  License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301, USA.
20 */
21 
22 #include "job.h"
23 #include "job_p.h"
24 #include "dbusconnectionpool.h"
25 #include <QTime>
26 #include "imapparser_p.h"
27 #include "session.h"
28 #include "session_p.h"
29 
30 #include <kdebug.h>
31 #include <klocalizedstring.h>
32 
33 #include <QtCore/QEventLoop>
34 #include <QtCore/QTimer>
35 #include <QtCore/QTextStream>
36 #include <QtDBus/QDBusInterface>
37 #include <QtDBus/QDBusConnectionInterface>
38 
39 using namespace Akonadi;
40 
41 static QDBusAbstractInterface *s_jobtracker = 0;
42 
43 //@cond PRIVATE
44 void JobPrivate::handleResponse( const QByteArray & tag, const QByteArray & data )
45 {
46  Q_Q( Job );
47 
48  if ( mCurrentSubJob ) {
49  mCurrentSubJob->d_ptr->handleResponse( tag, data );
50  return;
51  }
52 
53  if ( tag == mTag ) {
54  if ( data.startsWith( "NO " ) || data.startsWith( "BAD " ) ) { //krazy:exclude=strings
55  QString msg = QString::fromUtf8( data );
56 
57  msg.remove( 0, msg.startsWith( QLatin1String( "NO " ) ) ? 3 : 4 );
58 
59  if ( msg.endsWith( QLatin1String( "\r\n" ) ) )
60  msg.chop( 2 );
61 
62  q->setError( Job::Unknown );
63  q->setErrorText( msg );
64  q->emitResult();
65  return;
66  } else if ( data.startsWith( "OK" ) ) { //krazy:exclude=strings
67 
68  // We can't use emitResult() here: The slot connected to the result signal might exec()
69  // another job, and therefore this method would never return. That causes the session
70  // to deadlock, since it calls this method and does not continue starting new jobs until
71  // this method finishes. Which would also mean the exec()'d job is never started,, and there-
72  // fore everything deadlocks.
73  QTimer::singleShot( 0, q, SLOT(delayedEmitResult()) );
74  return;
75  }
76  }
77 
78  q->doHandleResponse( tag, data );
79 }
80 
81 void JobPrivate::init( QObject *parent )
82 {
83  Q_Q( Job );
84 
85  mParentJob = dynamic_cast<Job*>( parent );
86  mSession = dynamic_cast<Session*>( parent );
87 
88  if ( !mSession ) {
89  if ( !mParentJob )
90  mSession = Session::defaultSession();
91  else
92  mSession = mParentJob->d_ptr->mSession;
93  }
94 
95  if ( !mParentJob )
96  mSession->d->addJob( q );
97  else
98  mParentJob->addSubjob( q );
99 
100  // if there's a job tracker running, tell it about the new job
101  if ( !s_jobtracker ) {
102  // Let's only check for the debugging console every 3 seconds, otherwise every single job
103  // makes a dbus call to the dbus daemon, doesn't help performance.
104  static QTime s_lastTime;
105  if ( s_lastTime.isNull() || s_lastTime.elapsed() > 3000 ) {
106  if ( s_lastTime.isNull() )
107  s_lastTime.start();
108  if ( DBusConnectionPool::threadConnection().interface()->isServiceRegistered(QLatin1String( "org.kde.akonadiconsole" ) ) ) {
109  s_jobtracker = new QDBusInterface( QLatin1String( "org.kde.akonadiconsole" ),
110  QLatin1String( "/jobtracker" ),
111  QLatin1String( "org.freedesktop.Akonadi.JobTracker" ),
112  DBusConnectionPool::threadConnection(), 0 );
113  } else {
114  s_lastTime.restart();
115  }
116  }
117  // Note: we never reset s_jobtracker to 0 when a call fails; but if we did
118  // then we should restart s_lastTime.
119  }
120  QMetaObject::invokeMethod( q, "signalCreationToJobTracker", Qt::QueuedConnection );
121 }
122 
123 void JobPrivate::signalCreationToJobTracker()
124 {
125  Q_Q( Job );
126  if ( s_jobtracker ) {
127  // We do these dbus calls manually, so as to avoid having to install (or copy) the console's
128  // xml interface document. Since this is purely a debugging aid, that seems preferable to
129  // publishing something not intended for public consumption.
130  // WARNING: for any signature change here, apply it to resourcescheduler.cpp too
131  QList<QVariant> argumentList;
132  argumentList << QLatin1String( mSession->sessionId() )
133  << QString::number(reinterpret_cast<quintptr>( q ), 16)
134  << ( mParentJob ? QString::number( reinterpret_cast<quintptr>( mParentJob ), 16) : QString() )
135  << QString::fromLatin1( q->metaObject()->className() )
136  << jobDebuggingString();
137  s_jobtracker->callWithArgumentList(QDBus::NoBlock, QLatin1String( "jobCreated" ), argumentList);
138  }
139 }
140 
141 void JobPrivate::signalStartedToJobTracker()
142 {
143  Q_Q( Job );
144  if ( s_jobtracker ) {
145  // if there's a job tracker running, tell it a job started
146  QList<QVariant> argumentList;
147  argumentList << QString::number(reinterpret_cast<quintptr>( q ), 16);
148  s_jobtracker->callWithArgumentList(QDBus::NoBlock, QLatin1String( "jobStarted" ), argumentList);
149  }
150 }
151 
152 void JobPrivate::aboutToFinish()
153 {
154  // Dummy
155 }
156 
157 void JobPrivate::delayedEmitResult()
158 {
159  Q_Q( Job );
160  aboutToFinish();
161  q->emitResult();
162 }
163 
164 void JobPrivate::startQueued()
165 {
166  Q_Q( Job );
167  mStarted = true;
168 
169  emit q->aboutToStart( q );
170  q->doStart();
171  QTimer::singleShot( 0, q, SLOT(startNext()) );
172  QMetaObject::invokeMethod( q, "signalStartedToJobTracker", Qt::QueuedConnection );
173 }
174 
175 void JobPrivate::lostConnection()
176 {
177  Q_Q( Job );
178 
179  if ( mCurrentSubJob ) {
180  mCurrentSubJob->d_ptr->lostConnection();
181  } else {
182  q->setError( Job::ConnectionFailed );
183  q->emitResult();
184  }
185 }
186 
187 void JobPrivate::slotSubJobAboutToStart( Job * job )
188 {
189  Q_ASSERT( mCurrentSubJob == 0 );
190  mCurrentSubJob = job;
191 }
192 
193 void JobPrivate::startNext()
194 {
195  Q_Q( Job );
196 
197  if ( mStarted && !mCurrentSubJob && q->hasSubjobs() ) {
198  Job *job = dynamic_cast<Akonadi::Job*>( q->subjobs().first() );
199  Q_ASSERT( job );
200  job->d_ptr->startQueued();
201  }
202 }
203 
204 QByteArray JobPrivate::newTag( )
205 {
206  if ( mParentJob )
207  mTag = mParentJob->d_ptr->newTag();
208  else
209  mTag = QByteArray::number( mSession->d->nextTag() );
210  return mTag;
211 }
212 
213 QByteArray JobPrivate::tag() const
214 {
215  return mTag;
216 }
217 
218 void JobPrivate::writeData( const QByteArray & data )
219 {
220  Q_ASSERT_X( !mWriteFinished, "Job::writeData()", "Calling writeData() after emitting writeFinished()" );
221  mSession->d->writeData( data );
222 }
223 
224 void JobPrivate::itemRevisionChanged( Akonadi::Item::Id itemId, int oldRevision, int newRevision )
225 {
226  mSession->d->itemRevisionChanged( itemId, oldRevision, newRevision );
227 }
228 
229 void JobPrivate::updateItemRevision( Akonadi::Item::Id itemId, int oldRevision, int newRevision )
230 {
231  Q_Q( Job );
232  foreach ( KJob *j, q->subjobs() ) {
233  Akonadi::Job *job = qobject_cast<Akonadi::Job*>( j );
234  if ( job )
235  job->d_ptr->updateItemRevision( itemId, oldRevision, newRevision );
236  }
237  doUpdateItemRevision( itemId, oldRevision, newRevision );
238 }
239 
240 void JobPrivate::doUpdateItemRevision( Akonadi::Item::Id itemId, int oldRevision, int newRevision )
241 {
242  Q_UNUSED( itemId );
243  Q_UNUSED( oldRevision );
244  Q_UNUSED( newRevision );
245 }
246 
247 int JobPrivate::protocolVersion() const
248 {
249  return mSession->d->protocolVersion;
250 }
251 //@endcond
252 
253 Job::Job( QObject *parent )
254  : KCompositeJob( parent ),
255  d_ptr( new JobPrivate( this ) )
256 {
257  d_ptr->init( parent );
258 }
259 
260 Job::Job( JobPrivate *dd, QObject *parent )
261  : KCompositeJob( parent ),
262  d_ptr( dd )
263 {
264  d_ptr->init( parent );
265 }
266 
267 Job::~Job()
268 {
269  delete d_ptr;
270 
271  // if there is a job tracer listening, tell it the job is done now
272  if ( s_jobtracker ) {
273  QList<QVariant> argumentList;
274  argumentList << QString::number(reinterpret_cast<quintptr>( this ), 16)
275  << errorString();
276  s_jobtracker->callWithArgumentList(QDBus::NoBlock, QLatin1String( "jobEnded" ), argumentList);
277  }
278 }
279 
280 void Job::start()
281 {
282 }
283 
284 bool Job::doKill()
285 {
286  Q_D( Job );
287  if ( d->mStarted ) {
288  // the only way to cancel an already started job is reconnecting to the server
289  d->mSession->d->forceReconnect();
290  }
291  d->mStarted = false;
292  return true;
293 }
294 
295 QString Job::errorString() const
296 {
297  QString str;
298  switch ( error() ) {
299  case NoError:
300  break;
301  case ConnectionFailed:
302  str = i18n( "Cannot connect to the Akonadi service." );
303  break;
304  case ProtocolVersionMismatch:
305  str = i18n( "The protocol version of the Akonadi server is incompatible. Make sure you have a compatible version installed." );
306  break;
307  case UserCanceled:
308  str = i18n( "User canceled operation." );
309  break;
310  case Unknown:
311  return errorText();
312  default:
313  str = i18n( "Unknown error." );
314  break;
315  }
316  if ( !errorText().isEmpty() ) {
317  str += QString::fromLatin1( " (%1)" ).arg( errorText() );
318  }
319  return str;
320 }
321 
322 bool Job::addSubjob( KJob * job )
323 {
324  bool rv = KCompositeJob::addSubjob( job );
325  if ( rv ) {
326  connect( job, SIGNAL(aboutToStart(Akonadi::Job*)), SLOT(slotSubJobAboutToStart(Akonadi::Job*)) );
327  QTimer::singleShot( 0, this, SLOT(startNext()) );
328  }
329  return rv;
330 }
331 
332 bool Job::removeSubjob(KJob * job)
333 {
334  bool rv = KCompositeJob::removeSubjob( job );
335  if ( job == d_ptr->mCurrentSubJob ) {
336  d_ptr->mCurrentSubJob = 0;
337  QTimer::singleShot( 0, this, SLOT(startNext()) );
338  }
339  return rv;
340 }
341 
342 void Job::doHandleResponse(const QByteArray & tag, const QByteArray & data)
343 {
344  kDebug() << "Unhandled response: " << tag << data;
345 }
346 
347 void Job::slotResult(KJob * job)
348 {
349  if ( d_ptr->mCurrentSubJob == job ) {
350  // current job finished, start the next one
351  d_ptr->mCurrentSubJob = 0;
352  KCompositeJob::slotResult( job );
353  if ( !job->error() )
354  QTimer::singleShot( 0, this, SLOT(startNext()) );
355  } else {
356  // job that was still waiting for execution finished, probably canceled,
357  // so just remove it from the queue and move on without caring about
358  // its error code
359  KCompositeJob::removeSubjob( job );
360  }
361 }
362 
363 void Job::emitWriteFinished()
364 {
365  d_ptr->mWriteFinished = true;
366  emit writeFinished( this );
367 }
368 
369 #include "moc_job.cpp"
Akonadi::JobPrivate::doUpdateItemRevision
virtual void doUpdateItemRevision(Akonadi::Item::Id, int oldRevision, int newRevision)
Overwrite this if your job does operations with conflict detection and update the item revisions if y...
Akonadi::Job::ProtocolVersionMismatch
The server protocol version is too old or too new.
Definition: job.h:107
Akonadi::Job::Unknown
Unknown error.
Definition: job.h:109
Akonadi::Job
Base class for all actions in the Akonadi storage.
Definition: job.h:86
Akonadi::JobPrivate::updateItemRevision
void updateItemRevision(Akonadi::Item::Id itemId, int oldRevision, int newRevision)
Propagate item revision changes to this job and its sub-jobs.
Akonadi::JobPrivate::itemRevisionChanged
void itemRevisionChanged(Akonadi::Item::Id itemId, int oldRevision, int newRevision)
Notify following jobs about item revision changes.
Akonadi::Job::ConnectionFailed
The connection to the Akonadi server failed.
Definition: job.h:106
Akonadi::Session::defaultSession
static Session * defaultSession()
Returns the default session for this thread.
Definition: session.cpp:479
Akonadi::Job::start
void start()
Jobs are started automatically once entering the event loop again, no need to explicitly call this...
Definition: job.cpp:280
Akonadi::Job::writeFinished
void writeFinished(Akonadi::Job *job)
This signal is emitted if the job has finished all write operations, ie.
Akonadi::Session::sessionId
QByteArray sessionId() const
Returns the session identifier.
Definition: session.cpp:457
Akonadi::JobPrivate::aboutToFinish
virtual void aboutToFinish()
This method is called right before result() and finished() signals are emitted.
Akonadi::JobPrivate::tag
QByteArray tag() const
Return the tag used for the request.
Akonadi::Job::addSubjob
virtual bool addSubjob(KJob *job)
Adds the given job as a subjob to this job.
Definition: job.cpp:322
Akonadi::Job::doKill
virtual bool doKill()
Kills the execution of the job.
Definition: job.cpp:284
Akonadi::Job::emitWriteFinished
void emitWriteFinished()
Call this method to indicate that this job will not call writeData() again.
Definition: job.cpp:363
Akonadi::Session
A communication session with the Akonadi storage.
Definition: session.h:59
Akonadi::JobPrivate::newTag
QByteArray newTag()
Returns a new unique command tag for communication with the backend.
Akonadi::Job::doHandleResponse
virtual void doHandleResponse(const QByteArray &tag, const QByteArray &data)
This method should be reimplemented in the concrete jobs in case you want to handle incoming data...
Definition: job.cpp:342
Akonadi::Job::~Job
virtual ~Job()
Destroys the job.
Definition: job.cpp:267
Akonadi::JobPrivate::writeData
void writeData(const QByteArray &data)
Sends raw data to the backend.
Akonadi::JobPrivate
Definition: job_p.h:31
Akonadi::Job::removeSubjob
virtual bool removeSubjob(KJob *job)
Removes the given subjob of this job.
Definition: job.cpp:332
Akonadi::Job::aboutToStart
void aboutToStart(Akonadi::Job *job)
This signal is emitted directly before the job will be started.
Akonadi::Job::UserCanceled
The user canceld this job.
Definition: job.h:108
Akonadi::Job::errorString
virtual QString errorString() const
Returns the error string, if there has been an error, an empty string otherwise.
Definition: job.cpp:295
Akonadi::Job::Job
Job(QObject *parent=0)
Creates a new job.
Definition: job.cpp:253
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Mon Jul 21 2014 08:03:54 by doxygen 1.8.6 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.13.3 API Reference

Skip menu "kdepimlibs-4.13.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • 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