1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "qservicereply.h"
35#include "qservicereply_p.h"
36
37#include <QThread>
38
39#define Q_SERVICE_REPLY_DEBUG 1
40
41#ifdef Q_SERVICE_REPLY_DEBUG
42#include <QDebug>
43#endif
44
45/*!
46 \class QServiceReplyBase
47 \ingroup servicefw
48 \inmodule QtServiceFramework
49 \brief The QServiceReplyBase class tracks non-blocking service framework calls.
50
51 The QServiceReplyBase class is a data-carrying class. Each instance is short-lived
52 and only exists during the lifetime of a QServiceManager call. The QServiceReplyBase
53 instance never owns any of the data it points to, it just serves to carry the payload
54 from the background request back to the caller.
55
56 When an instance is first created, after being returned from QServiceManager::loadInterface(),
57 that instance will return false from both the isRunning() and isFinished() functions.
58 Then the request is started, and it will emit the started() signal. After that, and
59 until the request is completed, the isRunning() function will return true.
60 Finally the request is completed, and it will emit the finished() signal. After that
61 the isRunning() function will return false, and the isFinished() function will return
62 true. At this point client code can access the proxyObject() function to obtain the
63 payload of the service request.
64
65 Typically there should be no reason to construct a QServiceReplyBase (or sub-class)
66 instance: instead simply use the instances returned from the QServiceManager::loadInterface()
67 function.
68
69 The service QObject returned from the proxyObject() function is owned by the caller of
70 the original QServiceManager::loadInterface() function which resulted in the
71 QServiceReplyBase instance. Likewise the QServiceObjectBase instance itself is owned
72 by the caller and after the payload is retrieved, it should be queued for destruction
73 with deleteLater() in the function which handles the finished() signal.
74
75 As a convenience the manager() function will return the QServiceManager associated with
76 the request, and the request() function will return a QString indicating the details of
77 the request itself.
78
79 For performance reasons the QServiceReplyBase object is \bold{not synchronized}, and
80 thread-safety is ensured by observing the following invariant condition:
81 \list
82 \o all calls to non-const methods are serialised
83 \endlist
84 In general client code should never have to worry about this, since the private slots
85 which can modify the reply are called via queued signal-slot connections behind the scenes
86 ensuring that such accesses are serialised.
87
88 In the case of a request based on an interface name, request() will return the interface name;
89 otherwise in the case of a request based on a descriptor it will return the interface name
90 of the descriptor.
91
92 \sa QServiceReplyTyped, QServiceManager
93*/
94
95/*!
96 \class QServiceReplyTyped
97 \ingroup servicefw
98 \inmodule QtServiceFramework
99 \brief The QServiceReplyTyped class tracks typed non-blocking service framework calls.
100
101 This templated sub-class of QServiceReplyBase returns QObjects that are
102 already conveniently cast to the templated type. In all other respects instances of this
103 class function exactly the same as QServiceReplyBase.
104
105 To obtain a typed payload class, rather than just a QObject instance, you can use
106 one of QServiceManager's typed request functions and a typed QServiceReplyTyped
107 instantiation will be returned.
108
109 To obtain the untyped version of the QObject service, call the baseObject() function as
110 for the QServiceReplyBase class.
111
112 \sa QServiceReplyBase, QServiceManager
113*/
114
115/*!
116 Constructs a new QServiceReplyBase object. All values are set to defaults. Generally
117 creating QServiceReplayBase instances should be left to the QServiceManager.
118*/
119QServiceReplyBase::QServiceReplyBase(QObject *parent)
120 : QObject(parent),
121 d(new QServiceReplyPrivate)
122{
123 // nothing to do here
124}
125
126/*!
127 Destroys this object recovering all resources.
128*/
129QServiceReplyBase::~QServiceReplyBase()
130{
131 delete d;
132}
133
134/*!
135 Convenience function that returns an informative string of the request which was
136 issued when this reply was created. This string is not used by the request processor
137 in any way and exists mainly for logging and debugging purposes.
138*/
139QString QServiceReplyBase::request() const
140{
141 return d->request;
142}
143
144/*!
145 Sets the informative \a request string for this reply. This function is called by the
146 QServiceManager object when the request is created. In general client code
147 should not need to call this function.
148*/
149void QServiceReplyBase::setRequest(const QString &request)
150{
151 Q_ASSERT_X(thread() == QThread::currentThread(), Q_FUNC_INFO, "Reply object access violation!");
152 d->request = request;
153}
154
155/*!
156 Returns true if the QServiceReplyBase isNoError completed. When this is true, the
157 baseObject() and proxyObject() functions may be called to retrieve the payload
158 of the reply. Note that you should check the value of the error() function
159 to see if the request completed successfully.
160
161 \sa isRunning(), error()
162*/
163bool QServiceReplyBase::isFinished() const
164{
165 return d->finished;
166}
167
168/*!
169 Returns true if the QServiceReplyBase is being processed. When this is true,
170 the baseObject() and proxyObject() should not be accessed as they are in an
171 undefined state. Instead wait for the finished() signal to be emitted and
172 access those value then.
173
174 \sa isFinished()
175*/
176bool QServiceReplyBase::isRunning() const
177{
178 return d->running;
179}
180
181/*!
182 Returns any error state that may have been set on this reply.
183
184 \sa isFinished()
185*/
186QServiceManager::Error QServiceReplyBase::error() const
187{
188 return d->error;
189}
190
191/*!
192 \internal
193 Sets the error condition of the reply to \a error, indicating that processing of
194 the associated request has encountered a problem.
195
196 Note that this is a private slot, and should be called by a queued connection, so
197 that any data modification is only done in the objects own thread.
198*/
199void QServiceReplyBase::setError(QServiceManager::Error error)
200{
201 Q_ASSERT_X(thread() == QThread::currentThread(), Q_FUNC_INFO, "Reply object access violation!");
202 if (d->error != error) {
203 d->error = error;
204 emit errorChanged();
205 }
206}
207
208/*!
209 \internal
210 Starts the reply, indicating that processing of the associated request has begun.
211
212 Note that this is a private slot, and should be called by a queued connection, so
213 that any data modification is only done in the objects own thread.
214*/
215void QServiceReplyBase::start()
216{
217 Q_ASSERT_X(thread() == QThread::currentThread(), Q_FUNC_INFO, "Reply object access violation!");
218 if (!d->running) {
219 d->running = true;
220 emit started();
221 }
222#ifdef Q_SERVICE_REPLY_DEBUG
223 else
224 {
225 qWarning() << "Starting request that is" << ((d->finished) ? "finished:" : "started:") << d->request;
226 }
227 Q_ASSERT(!d->finished);
228#endif
229}
230
231/*!
232 \internal
233 Finishes the reply, indicating that processing of the associated request has completed.
234
235 Note that this is a private slot, and should be called by a queued connection, so
236 that any data modification is only done in the objects own thread.
237*/
238void QServiceReplyBase::finish()
239{
240 Q_ASSERT_X(thread() == QThread::currentThread(), Q_FUNC_INFO, "Reply object access violation!");
241 if (!d->finished) {
242 d->running = false;
243 d->finished = true;
244 emit finished();
245 }
246#ifdef Q_SERVICE_REPLY_DEBUG
247 else
248 {
249 qWarning() << "Attempt to finish request that has already finished:" << d->request;
250 }
251 Q_ASSERT(!d->running);
252#endif
253}
254

source code of qtsystems/src/serviceframework/qservicereply.cpp