Merge remote-tracking branch 'origin/api_changes'
[profile/ivi/qtbase.git] / src / dbus / qdbuspendingcall.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdbuspendingcall.h"
43 #include "qdbuspendingcall_p.h"
44
45 #include "qdbusconnection_p.h"
46 #include "qdbusmetatype_p.h"
47 #include "qcoreapplication.h"
48 #include "qcoreevent.h"
49 #include <private/qobject_p.h>
50
51 #ifndef QT_NO_DBUS
52
53 QT_BEGIN_NAMESPACE
54
55 /*!
56     \class QDBusPendingCall
57     \inmodule QtDBus
58     \since 4.5
59
60     \brief The QDBusPendingCall class refers to one pending asynchronous call
61
62     A QDBusPendingCall object is a reference to a method call that was
63     sent over D-Bus without waiting for a reply. QDBusPendingCall is an
64     opaque type, meant to be used as a handle for a pending reply.
65
66     In most programs, the QDBusPendingCall class will not be used
67     directly. It can be safely replaced with the template-based
68     QDBusPendingReply, in order to access the contents of the reply or
69     wait for it to be complete.
70
71     The QDBusPendingCallWatcher class allows one to connect to a signal
72     that will indicate when the reply has arrived or if the call has
73     timed out. It also provides the
74     QDBusPendingCallWatcher::waitForFinished() method which will suspend
75     the execution of the program until the reply has arrived.
76
77     \note If you create a copy of a QDBusPendingCall object, all
78           information will be shared among the many copies. Therefore,
79           QDBusPendingCall is an explicitly-shared object and does not
80           provide a method of detaching the copies (since they refer
81           to the same pending call)
82
83     \sa QDBusPendingReply, QDBusPendingCallWatcher,
84         QDBusAbstractInterface::asyncCall()
85 */
86
87 /*!
88     \class QDBusPendingCallWatcher
89     \inmodule QtDBus
90     \since 4.5
91
92     \brief The QDBusPendingCallWatcher class provides a convenient way for
93     waiting for asynchronous replies
94
95     The QDBusPendingCallWatcher provides the finished() signal that will be
96     emitted when a reply arrives.
97
98     It is usually used like the following example:
99
100     \snippet doc/src/snippets/code/src.qdbus.qdbuspendingcall.cpp 0
101
102     Note that it is not necessary to keep the original QDBusPendingCall
103     object around since QDBusPendingCallWatcher inherits from that class
104     too.
105
106     The slot connected to by the above code could be something similar
107     to the following:
108
109     \snippet doc/src/snippets/code/src.qdbus.qdbuspendingcall.cpp 1
110
111     Note the use of QDBusPendingReply to validate the argument types in
112     the reply. If the reply did not contain exactly two arguments
113     (one string and one QByteArray), QDBusPendingReply::isError() will
114     return true.
115
116     \sa QDBusPendingReply, QDBusAbstractInterface::asyncCall()
117 */
118
119 /*!
120     \fn void QDBusPendingCallWatcher::finished(QDBusPendingCallWatcher *self)
121
122     This signal is emitted when the pending call has finished and its
123     reply is available. The \a self parameter is a pointer to the
124     object itself, passed for convenience so that the slot can access
125     the properties and determine the contents of the reply.
126 */
127
128 void QDBusPendingCallWatcherHelper::add(QDBusPendingCallWatcher *watcher)
129 {
130     connect(this, SIGNAL(finished()), watcher, SLOT(_q_finished()), Qt::QueuedConnection);
131 }
132
133 QDBusPendingCallPrivate::~QDBusPendingCallPrivate()
134 {
135     if (pending) {
136         q_dbus_pending_call_cancel(pending);
137         q_dbus_pending_call_unref(pending);
138     }
139     delete watcherHelper;
140 }
141
142 bool QDBusPendingCallPrivate::setReplyCallback(QObject *target, const char *member)
143 {
144     receiver = target;
145     metaTypes.clear();
146     methodIdx = -1;
147     if (!target)
148         return true;;           // unsetting
149
150     if (!member || !*member) {
151         // would not be able to deliver a reply
152         qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)",
153                  target ? target->metaObject()->className() : "(null)",
154                  member ? member + 1 : "(null)",
155                  target ? qPrintable(target->objectName()) : "no name");
156         return false;
157     }
158
159     methodIdx = QDBusConnectionPrivate::findSlot(target, member + 1, metaTypes);
160     if (methodIdx == -1) {
161         QByteArray normalizedName = QMetaObject::normalizedSignature(member + 1);
162         methodIdx = QDBusConnectionPrivate::findSlot(target, normalizedName, metaTypes);
163     }
164     if (methodIdx == -1) {
165         // would not be able to deliver a reply
166         qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)",
167                  target->metaObject()->className(),
168                  member + 1, qPrintable(target->objectName()));
169         return false;
170     }
171
172     // success
173     // construct the expected signature
174     int count = metaTypes.count() - 1;
175     if (count == 1 && metaTypes.at(1) == QDBusMetaTypeId::message) {
176         // wildcard slot, can receive anything, so don't set the signature
177         return true;
178     }
179
180     if (metaTypes.at(count) == QDBusMetaTypeId::message)
181         --count;
182
183     setMetaTypes(count, count ? metaTypes.constData() + 1 : 0);
184     return true;
185 }
186
187 void QDBusPendingCallPrivate::setMetaTypes(int count, const int *types)
188 {
189     expectedReplyCount = count;
190     if (count == 0) {
191         expectedReplySignature = QLatin1String(""); // not null
192         return;
193     }
194
195     QByteArray sig;
196     sig.reserve(count + count / 2);
197     for (int i = 0; i < count; ++i) {
198         const char *typeSig = QDBusMetaType::typeToSignature(types[i]);
199         if (!typeSig) {
200             qFatal("QDBusPendingReply: type %s is not registered with QtDBus",
201                    QMetaType::typeName(types[i]));
202         }
203         sig += typeSig;
204     }
205
206     expectedReplySignature = QString::fromLatin1(sig);
207 }
208
209 void QDBusPendingCallPrivate::checkReceivedSignature()
210 {
211     // MUST BE CALLED WITH A LOCKED MUTEX!
212
213     if (replyMessage.type() == QDBusMessage::InvalidMessage)
214         return;                 // not yet finished - no message to
215                                 // validate against
216     if (replyMessage.type() == QDBusMessage::ErrorMessage)
217         return;                 // we don't have to check the signature of an error reply
218
219     if (expectedReplySignature.isNull())
220         return;                 // no signature to validate against
221
222     // can't use startsWith here because a null string doesn't start or end with an empty string
223     if (!replyMessage.signature().indexOf(expectedReplySignature) == 0) {
224         QString errorMsg = QLatin1String("Unexpected reply signature: got \"%1\", "
225                                          "expected \"%2\"");
226         replyMessage = QDBusMessage::createError(
227             QDBusError::InvalidSignature,
228             errorMsg.arg(replyMessage.signature(), expectedReplySignature));
229
230     }
231 }
232
233 void QDBusPendingCallPrivate::waitForFinished()
234 {
235     QMutexLocker locker(&mutex);
236
237     if (replyMessage.type() != QDBusMessage::InvalidMessage)
238         return;                 // already finished
239
240     connection->waitForFinished(this);
241 }
242
243 /*!
244     Creates a copy of the \a other pending asynchronous call. Note
245     that both objects will refer to the same pending call.
246 */
247 QDBusPendingCall::QDBusPendingCall(const QDBusPendingCall &other)
248     : d(other.d)
249 {
250 }
251
252 /*!
253     \internal
254 */
255 QDBusPendingCall::QDBusPendingCall(QDBusPendingCallPrivate *dd)
256     : d(dd)
257 {
258 }
259
260 /*!
261     Destroys this copy of the QDBusPendingCall object. If this copy is
262     also the last copy of a pending asynchronous call, the call will
263     be canceled and no further notifications will be received. There
264     will be no way of accessing the reply's contents when it arrives.
265 */
266 QDBusPendingCall::~QDBusPendingCall()
267 {
268     // d deleted by QExplicitlySharedDataPointer
269 }
270
271
272 /*!
273     Creates a copy of the \a other pending asynchronous call and drops
274     the reference to the previously-referenced call. Note that both
275     objects will refer to the same pending call after this function.
276
277     If this object contained the last reference of a pending
278     asynchronous call, the call will be canceled and no further
279     notifications will be received. There will be no way of accessing
280     the reply's contents when it arrives.
281 */
282 QDBusPendingCall &QDBusPendingCall::operator=(const QDBusPendingCall &other)
283 {
284     d = other.d;
285     return *this;
286 }
287
288 /*!
289     \fn bool QDBusPendingCallWatcher::isFinished() const
290
291     Returns true if the pending call has finished processing and the
292     reply has been received.
293
294     Note that this function only changes state if you call
295     waitForFinished() or if an external D-Bus event happens, which in
296     general only happens if you return to the event loop execution.
297
298     \sa QDBusPendingReply::isFinished()
299 */
300 /*!
301     \fn bool QDBusPendingReply::isFinished() const
302
303     Returns true if the pending call has finished processing and the
304     reply has been received. If this function returns true, the
305     isError(), error() and reply() methods should return valid
306     information.
307
308     Note that this function only changes state if you call
309     waitForFinished() or if an external D-Bus event happens, which in
310     general only happens if you return to the event loop execution.
311
312     \sa QDBusPendingCallWatcher::isFinished()
313 */
314
315 bool QDBusPendingCall::isFinished() const
316 {
317     if (!d)
318         return true; // considered finished
319
320     QMutexLocker locker(&d->mutex);
321     return d->replyMessage.type() != QDBusMessage::InvalidMessage;
322 }
323
324 void QDBusPendingCall::waitForFinished()
325 {
326     if (d) d->waitForFinished();
327 }
328
329 /*!
330     \fn bool QDBusPendingReply::isValid() const
331
332     Returns true if the reply contains a normal reply message, false
333     if it contains anything else.
334
335     If the pending call has not finished processing, this function
336     return false.
337 */
338 bool QDBusPendingCall::isValid() const
339 {
340     if (!d)
341         return false;
342     QMutexLocker locker(&d->mutex);
343     return d->replyMessage.type() == QDBusMessage::ReplyMessage;
344 }
345
346 /*!
347     \fn bool QDBusPendingReply::isError() const
348
349     Returns true if the reply contains an error message, false if it
350     contains a normal method reply.
351
352     If the pending call has not finished processing, this function
353     also returns true.
354 */
355 bool QDBusPendingCall::isError() const
356 {
357     if (!d)
358         return true; // considered finished and an error
359     QMutexLocker locker(&d->mutex);
360     return d->replyMessage.type() == QDBusMessage::ErrorMessage;
361 }
362
363 /*!
364     \fn QDBusError QDBusPendingReply::error() const
365
366     Retrieves the error content of the reply message, if it has
367     finished processing. If the reply message has not finished
368     processing or if it contains a normal reply message (non-error),
369     this function returns an invalid QDBusError.
370 */
371 QDBusError QDBusPendingCall::error() const
372 {
373     if (d) {
374         QMutexLocker locker(&d->mutex);
375         return QDBusError(d->replyMessage);
376     }
377
378     // not connected, return an error
379     QDBusError err = QDBusError(QDBusError::Disconnected,
380                                 QLatin1String("Not connected to D-Bus server"));
381     return err;
382 }
383
384 /*!
385     \fn QDBusMessage QDBusPendingReply::reply() const
386
387     Retrieves the reply message received for the asynchronous call
388     that was sent, if it has finished processing. If the pending call
389     is not finished, this function returns a QDBusMessage of type
390     QDBusMessage::InvalidMessage.
391
392     After it has finished processing, the message type will either be
393     an error message or a normal method reply message.
394 */
395 QDBusMessage QDBusPendingCall::reply() const
396 {
397     if (!d)
398         return QDBusMessage::createError(error());
399     QMutexLocker locker(&d->mutex);
400     return d->replyMessage;
401 }
402
403 #if 0
404 /*!
405     Sets the slot \a member in object \a target to be called when the
406     reply arrives. The slot's parameter list must match the reply
407     message's arguments for it to be called.
408
409     It may, optionally, contain a QDBusMessage final parameter. If it
410     is present, the parameter will contain the reply message object.
411
412     The callback will not be called if the reply is an error message.
413
414     This function returns true if it could set the callback, false
415     otherwise. It is not a guarantee that the callback will be
416     called.
417
418     \warning QDBusPendingCall only supports one callback per pending
419              asynchronous call, even if multiple QDBusPendingCall
420              objects are referencing the same pending call.
421 */
422 bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member)
423 {
424     if (!d)
425         return false;
426
427     return d->setReplyCallback(target, member);
428 }
429 #endif
430
431 /*!
432     \since 4.6
433     Creates a QDBusPendingCall object based on the error condition
434     \a error. The resulting pending call object will be in the
435     "finished" state and QDBusPendingReply::isError() will return true.
436
437     \sa fromCompletedCall()
438 */
439 QDBusPendingCall QDBusPendingCall::fromError(const QDBusError &error)
440 {
441     return fromCompletedCall(QDBusMessage::createError(error));
442 }
443
444 /*!
445     \since 4.6
446     Creates a QDBusPendingCall object based on the message \a msg.
447     The message must be of type QDBusMessage::ErrorMessage or
448     QDBusMessage::ReplyMessage (that is, a message that is typical
449     of a completed call).
450
451     This function is useful for code that requires simulating a pending
452     call, but that has already finished.
453
454     \sa fromError()
455 */
456 QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
457 {
458     QDBusPendingCallPrivate *d = 0;
459     if (msg.type() == QDBusMessage::ErrorMessage ||
460         msg.type() == QDBusMessage::ReplyMessage) {
461         d = new QDBusPendingCallPrivate(QDBusMessage(), 0);
462         d->replyMessage = msg;
463     }
464
465     return QDBusPendingCall(d);
466 }
467
468
469 class QDBusPendingCallWatcherPrivate: public QObjectPrivate
470 {
471 public:
472     void _q_finished();
473
474     Q_DECLARE_PUBLIC(QDBusPendingCallWatcher)
475 };
476
477 inline void QDBusPendingCallWatcherPrivate::_q_finished()
478 {
479     Q_Q(QDBusPendingCallWatcher);
480     emit q->finished(q);
481 }
482
483 /*!
484     Creates a QDBusPendingCallWatcher object to watch for replies on the
485     asynchronous pending call \a call and sets this object's parent
486     to \a parent.
487 */
488 QDBusPendingCallWatcher::QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent)
489     : QObject(*new QDBusPendingCallWatcherPrivate, parent), QDBusPendingCall(call)
490 {
491     if (d) {                    // QDBusPendingCall::d
492         QMutexLocker locker(&d->mutex);
493         if (!d->watcherHelper) {
494             d->watcherHelper = new QDBusPendingCallWatcherHelper;
495             if (d->replyMessage.type() != QDBusMessage::InvalidMessage) {
496                 // cause a signal emission anyways
497                 QMetaObject::invokeMethod(d->watcherHelper, "finished", Qt::QueuedConnection);
498             }
499         }
500         d->watcherHelper->add(this);
501     }
502 }
503
504 /*!
505     Destroys this object. If this QDBusPendingCallWatcher object was the
506     last reference to the unfinished pending call, the call will be
507     canceled.
508 */
509 QDBusPendingCallWatcher::~QDBusPendingCallWatcher()
510 {
511 }
512
513 /*!
514     \fn void QDBusPendingCallWatcher::waitForFinished()
515
516     Suspends the execution of the calling thread until the reply is
517     received and processed. After this function returns, isFinished()
518     should return true, indicating the reply's contents are ready to
519     be processed.
520
521     \sa QDBusPendingReply::waitForFinished()
522 */
523 void QDBusPendingCallWatcher::waitForFinished()
524 {
525     if (d) {
526         d->waitForFinished();
527
528         // our signals were queued, so deliver them
529         QCoreApplication::sendPostedEvents(d->watcherHelper, QEvent::MetaCall);
530         QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
531     }
532 }
533 QT_END_NAMESPACE
534
535 #endif // QT_NO_DBUS
536
537 #include "moc_qdbuspendingcall.cpp"