qthighway/xqservice/src/xqservicerequest.cpp
branchRCL_3
changeset 9 5d007b20cfd0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qthighway/xqservice/src/xqservicerequest.cpp	Tue Aug 31 16:02:37 2010 +0300
@@ -0,0 +1,707 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation, version 2.1 of the License.
+* 
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this program.  If not, 
+* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
+*
+* Description:                                                         
+*
+*/
+
+#include "xqservicelog.h"
+
+#include "xqservicerequest.h"
+#include "xqservicethreaddata.h"
+
+#include "xqservicechannel.h"
+#include "xqserviceadaptor.h"
+#include "xqrequestutil.h"
+#include <QStringList>
+#include <xqservicemanager.h>
+
+/*!
+    \class XQServiceRequest_Private
+    \inpublicgroup QtBaseModule
+
+    \ingroup ipc
+    \brief Private implementation of the XQServiceRequest.
+*/
+
+class XQServiceRequest_Private : public XQServiceRequestCompletedAsync
+{
+public:
+    XQServiceRequest_Private(XQServiceRequest* parent)
+        : mSynchronous(true), mParent(parent),mServiceManager(NULL)
+    {    
+        XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::XQServiceRequest_Private(1)");
+        
+    };
+
+    XQServiceRequest_Private(const QString& fullServiceName, 
+                             const QString& message, 
+                             const bool &synchronous, 
+                             XQServiceRequest* parent)
+        : mService(fullServiceName), mMessage(message), mSynchronous(synchronous), mParent(parent),mServiceManager(NULL)
+    {    
+        XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::XQServiceRequest_Private(2)");
+    };
+
+    XQServiceRequest_Private(const XQAiwInterfaceDescriptor &descriptor, 
+                             const QString& message, 
+                             const bool &synchronous, 
+                            XQServiceRequest* parent)
+            : mMessage(message), mSynchronous(synchronous), mParent(parent),mServiceManager(NULL)
+    {
+        XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::XQServiceRequest_Private(3)");
+        
+        // Construct service name understood by the QtHighway FW
+        // (The descriptor has been created from the  XML)
+        mService = descriptor.serviceName() + "." + descriptor.interfaceName();
+        XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private(3)::service=%s", qPrintable(mService));
+
+        // Remember the descriptor
+        mRequestUtil.mDescriptor = descriptor; 
+    };
+    
+    ~XQServiceRequest_Private();
+    // from XQServiceRequestCompletedAsync
+    void requestCompletedAsync(const QVariant &retValue);
+    void requestErrorAsync(int err);
+    
+    QList<QVariant> mArguments;
+    QString mService;
+    QString mMessage;
+    bool mSynchronous;
+    XQServiceRequest* mParent;
+    XQRequestUtil mRequestUtil;
+    XQServiceManager* mServiceManager;
+    QString mUniqueChannelName;
+    
+};
+
+XQServiceRequest_Private::~XQServiceRequest_Private()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::~XQServiceRequest_Private");
+    delete mServiceManager;
+};
+
+void XQServiceRequest_Private::requestCompletedAsync(const QVariant &retValue)
+{    
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::requestCompletedAsync");
+    emit mParent->requestCompleted(retValue);
+}
+
+void XQServiceRequest_Private::requestErrorAsync(int err)
+{    
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::requestErrorAsync");
+    emit mParent->requestError(err);
+}
+
+/*!
+    \class XQServiceRequest
+    \inpublicgroup QtBaseModule
+
+    \ingroup ipc
+    \brief Allows applications to request services from other applications.
+    
+    The XQServiceRequest class allows applications to request services from other applications.
+    A XQServiceRequest encapsulates a service name and the message to be sent to that service.
+    
+    \note One should be using XQApplicationManager and the related XQAiwRequest instead of XQServiceRequest.
+          The XQApplicationManager and related classes encapsulate basic, target-architecture approved
+          support for out-of-process Application Interworking, e.g. support for launching URLs
+          (including activity URLs), normal files, sharable files, etc. (whatever needed).
+    
+    \b Examples: \n
+    
+    How to create synchronous request without parameters and return value? 
+    \note The full name (yourservice.Interface) need to be used (with dot (.) between service name and interface name).
+    
+    \code
+        XQServiceRequest request("yourservice.<b>Interface</b>", "functionName1()");
+        bool res = request.send();
+        if  (!res) {
+            int error = request.latestError();
+        }
+    \endcode
+    
+    How to create synchronous request with several parameters and return value?
+    
+    \code
+        QString parameter1("+3581234567890");
+        int parameter2 = 3;
+        XQServiceRequest request("yourservice.<b>Interface</b>", "functionName2(QString, int)");
+        request << parameter1;
+        request << parameter2;
+        int returnvalue;
+        bool res = request.send(returnvalue);
+        if  (!res) {
+            int error = request.latestError();
+        }
+    \endcode
+    
+    How to create asynchronous request without return value?
+    
+    \code
+        QString parameter1("+3581234567890");
+        int parameter2 = 3;
+        XQServiceRequest request("yourservice.Interface", "functionName2(QString, int)", false);
+        request << parameter1;
+        request << parameter2;
+        bool res = request.send();
+        if (!res) {
+            int error = request.latestError();
+        }
+    \endcode
+    
+    How to create asynchronous request with return value?
+    
+    \code
+        QString parameter1("+3581234567890");
+        int parameter2 = 3;
+        XQServiceRequest request("yourservice.Interface", "functionName2(QString, int)", false);
+        request << parameter1;
+        request << parameter2;
+        connect(request, SIGNAL(requestCompleted(QVariant)), this, SLOT(requestCompleted(QVariant)));
+        bool res = request.send();
+        if (!res) {
+            int error = request.latestError();
+        }
+
+        ...
+
+        void requestCompleted(const QVariant& value)
+        {
+            int returnvalue = value.toInt();
+        }
+    \endcode
+    
+    How to use declare custom type?
+    
+    Header:
+    \code
+        class CustomType 
+        { 
+        public: 
+            CustomType (){}; 
+            virtual ~CustomType(){};
+
+            QString mString1; 
+            QString mString2; 
+            QUuid mUid;
+
+            template <typename Stream> void serialize(Stream &stream) const; 
+            template <typename Stream> void deserialize(Stream &stream); 
+        };
+
+        Q_DECLARE_USER_METATYPE(CustomType)
+    \endcode
+    
+    Implementation:
+    \code        
+        template <typename Stream> void CustomType::serialize(Stream &s) const 
+            { 
+            s << mString1; 
+            s << mString2; 
+            s << mUid; 
+            }
+
+        template <typename Stream> void CustomType::deserialize(Stream &s) 
+            { 
+            s >> mString1; 
+            s >> mString2; 
+            s >> mUid; 
+            }
+
+        Q_IMPLEMENT_USER_METATYPE(CustomType)
+    \endcode
+    
+    How to declare custom type that doesn't need data stream operators?
+    
+    Header:
+    \code
+        typedef QList<CustomType> CustomTypeList;
+
+        Q_DECLARE_USER_METATYPE_NO_OPERATORS(CustomTypeList)
+    \endcode
+    
+    Implementation:
+    \code
+        Q_IMPLEMENT_USER_METATYPE_NO_OPERATORS(CustomTypeList)
+    \endcode
+*/
+
+/*!
+    \fn bool XQServiceRequest::send(T& retValue)
+
+    Sends the request. If the request is synchronous, then client is blocked
+    until service provider completes the request or request fails for some reason.
+    If the request is asynchronous, then client won't be blocked.
+    \param retValue Defines refence to a value service provider will return after service.
+    \return False if there was no application that could service the request, otherwise true.
+*/
+
+/*!
+    \fn XQServiceRequest &XQServiceRequest::operator<< (const T &var)
+
+    Adds \a var to the list of arguments for this service request.
+    \param var Defines the argument value to add to the list of arguments.
+*/
+
+/*!
+    \fn XQServiceRequest &XQServiceRequest::operator<< (const char *var)
+
+    Adds \a var to the list of arguments for this service request.
+    \param var Defines the argument value to add to the list of arguments.
+*/
+
+/*!
+    \fn void XQServiceRequest::requestCompleted(const QVariant& value)
+
+    This signal is emitted when service provider returns a return value asynchronously back to the client.
+    \param value Result of the request.
+*/
+
+/*!
+    \fn void XQServiceRequest::requestError(int err);
+
+    This signal is emitted when error has happened in request handling.
+    \param err Error code as integer value.
+    \sa XQService::ServiceIPCErrors
+*/
+
+/*!
+    \fn void XQServiceRequest::addVariantArg(const QVariant& var)
+
+    Adds the variant value to the list of arguments, so that the variant's
+    value is serialized in send() rather than the variant itself.
+    \param var Value to be added to the list of arguments.
+*/
+
+/*!
+    Construct a null service request.
+    setService() and setMessage() must be called before send(), but the
+    service may be written prior to the calls.
+ */
+XQServiceRequest::XQServiceRequest()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::XQServiceRequest(1)");
+    mData = new XQServiceRequest_Private(this);
+}
+
+/*!
+    Construct a service request that will send \a message to
+    a \a service when send() is called. The service may be written
+    prior to the calls.
+    \param service Defines the full service name to send message. The full name is:
+                   - The name of the service in the service configuration file
+                   - Character *.* (dot)
+                   - The name of the interface from the service XML.
+    \param message Defines the message to send to the service provider i.e. it is
+                 the signature of the service provider function to be called.
+    \param synchronous Defines should message be sent synchronously or asynchronously.
+                     By default message is sent synchronously.
+*/
+XQServiceRequest::XQServiceRequest(const QString& service, const QString& message, const bool &synchronous)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::XQServiceRequest(2)");
+    XQSERVICE_DEBUG_PRINT("service: %s, message: %s, synchronous: %d", qPrintable(service), qPrintable(message), synchronous);
+    mData = new XQServiceRequest_Private(service,message,synchronous,this);
+}
+
+/*!
+    Copy constructor. Any data previously written to the \a orig
+    service will be in the copy.
+    \param orig XQServiceRequest from which data will be copied to this object.
+*/
+XQServiceRequest::XQServiceRequest(const XQServiceRequest& orig)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::XQServiceRequest(3)");
+    mData = new XQServiceRequest_Private(orig.mData->mService,orig.mData->mMessage,orig.mData->mSynchronous,this);
+    mData->mArguments = orig.mData->mArguments;
+}
+
+/*!
+    Construct a service request by service descriptor which contains exact details of the service and interface.
+    The service may be written prior to the calls.
+    \param descriptor Defines details of the service and it's interface.
+    \param message Message to be sent when send() is called.
+    \param synchronous Defines should message be sent synchronously or asynchronously.
+                       By default message is sent synchronously.
+*/
+XQServiceRequest::XQServiceRequest(const XQAiwInterfaceDescriptor &descriptor, const QString& message, const bool &synchronous)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::XQServiceRequest(2)");
+    XQSERVICE_DEBUG_PRINT("service: %s, interface %s, message: %s, synchronous: %d",
+                          qPrintable(descriptor.serviceName()), qPrintable(descriptor.interfaceName()),
+                          qPrintable(message), synchronous);
+    mData = new XQServiceRequest_Private(descriptor,message,synchronous,this);
+}
+
+/*!
+    Assignment operator.
+    Any data previously written to the \a orig
+    service will be in the copy.
+*/
+XQServiceRequest& XQServiceRequest::operator=(const XQServiceRequest& orig)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::operator=");
+    if( &orig == this )
+        return *this;
+
+    mData->mService = orig.mData->mService;
+    mData->mMessage = orig.mData->mMessage;
+    mData->mArguments = orig.mData->mArguments;
+    mData->mRequestUtil = orig.mData->mRequestUtil;
+
+    return *this;
+}
+
+/*!
+    Destroys the service request. Unlike QtopiaIpcEnvelope, the
+    request is not automatically sent.
+*/
+XQServiceRequest::~XQServiceRequest()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::~XQServiceRequest %s", qPrintable(mData->mUniqueChannelName));
+    XQServiceAdaptor::cancelPendingSend(mData->mUniqueChannelName);
+    delete mData;
+}
+
+/*!
+    Checks if request is NULL.
+    \return True if either the service() or message() is not set.
+    \sa service(), message()
+ */
+bool XQServiceRequest::isNull() const
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::isNull");
+    bool ret = mData->mService.isEmpty() || mData->mService.isNull() || mData->mMessage.isNull();
+	XQSERVICE_DEBUG_PRINT("mData->mService.isEmpty() = %d", mData->mService.isEmpty());
+	XQSERVICE_DEBUG_PRINT("mData->mService.isNull() = %d", mData->mService.isNull());
+	XQSERVICE_DEBUG_PRINT("mData->mMessage.isNull() = %d", mData->mMessage.isNull());
+	XQSERVICE_DEBUG_PRINT("return %d", ret);
+	return ret;
+}
+
+/*!
+    Checks if request is synchronous or asynchronous.
+    \return True if request is synchronous, false if request is asynchronous.
+    \sa setSynchronous()
+ */
+bool XQServiceRequest::isSynchronous() const
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::isSynchronous");
+    return mData->mSynchronous;
+}
+
+/*!
+    Sets request to be synchronous or asynchronous.
+    \param synchronous If set to true, request will be synchronous.
+                       If set to false, request will be asynchronous.
+    \sa isSynchronous()
+ */
+void XQServiceRequest::setSynchronous(const bool& synchronous)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setSynchronous");
+    mData->mSynchronous = synchronous;
+}
+/*!
+    Sends the request. If the request is synchronous, then client is blocked
+    until service provider completes the request or request fails for some reason.
+    If the request is asynchronous, then client won't be blocked. If the request
+    is asynchronous and clients wants to receive a return value from the service
+    provider, then clients should connect to the requestCompleted() signal.
+    \return False if there was no application that could service the request, otherwise true.
+*/
+bool XQServiceRequest::send()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::send(1)");
+    QVariant retValue;
+    return send(retValue);
+}
+
+/*!
+    Sends the request. If the request is synchronous, then client is blocked
+    until service provider completes the request or request fails for some reason.
+    If the request is asynchronous, then client won't be blocked.
+    \param retData Defines refence to a value service provider will return after service.
+    \return False if there was no application that could service the request, otherwise true.
+*/
+bool XQServiceRequest::send(QVariant& retData)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::send(2)");
+    if (isNull())
+    {
+        XQSERVICE_DEBUG_PRINT("XQServiceRequest::send error: null request");
+        XQService::serviceThreadData()->setLatestError(XQService::EArgumentError);
+        return false;
+    }
+    
+    // Handle sharable file argument(s), if any
+    if (!handleSharableFileArgs())
+    {
+        XQSERVICE_DEBUG_PRINT("XQServiceRequest::send error:invalid sharable file");
+        XQService::serviceThreadData()->setLatestError(XQService::EArgumentError);
+        return false;
+    }
+    
+    mData->mRequestUtil.setSynchronous(mData->mSynchronous); // Ensure option is set !
+    mData->mRequestUtil.mOperation = mData->mMessage;  // Save the operation name for startup
+    
+    // !!!
+    // Add the info as extra argument to the request
+    // This shall be removed by the server
+    // !!!
+    addArg(qVariantFromValue(mData->mRequestUtil.mInfo));
+       
+    // Pass always the util instance onwards as user data.
+    // It can be utilized by the XQServiceManager::startServer
+    // e.g. to optimize startup of a service server
+
+    // Create unique channel name to separate multiple client requests to same channel name.
+    quint32 handle = (unsigned int)mData;
+    mData->mUniqueChannelName = QString("%1:").arg(handle) + mData->mService;
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::send(2):uniqueChannel=%s", qPrintable(mData->mUniqueChannelName));
+    return XQServiceAdaptor::send(mData->mUniqueChannelName,  message(), mData->mArguments, retData, mData->mSynchronous,mData,
+                                 (const void *)&mData->mRequestUtil);
+}
+/*!
+    Sets the full name of the service to which the request will be sent.
+    \param fullServiceName Full name of the service to send message to. See
+                           XQServiceRequest(const QString& service, const QString& message, const bool &synchronous)
+                           for the full name definition.
+    \sa service()
+ */
+void XQServiceRequest::setService(const QString& fullServiceName)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setService");
+    XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(fullServiceName));
+    mData->mService = fullServiceName;
+    mData->mArguments.clear();
+    mData->mRequestUtil.mDescriptor = XQAiwInterfaceDescriptor(); // Invalid descriptor
+}
+
+/*!
+    Gets the service name to which this request will be sent.
+    \return Full service name to which request will be sent.
+    \sa setService()
+*/
+QString XQServiceRequest::service() const
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::service");
+    XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(mData->mService));
+    return mData->mService;
+}
+
+/*!
+    Sets the \a message to be sent to the service.
+    \param message Defines the message to send to a service provider. The message
+                   is a valid Qt slot signature published by the service provider.
+                   For example, "view(QString)".
+    \sa message()
+*/
+void XQServiceRequest::setMessage(const QString& message)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setMessage");
+    XQSERVICE_DEBUG_PRINT("message: %s", qPrintable(message));
+    mData->mMessage = message;
+    mData->mArguments.clear();
+}
+
+/*!
+    Gets the message set for the request.
+    \return Message of the request as QString.
+    \sa setMessage()
+*/
+QString XQServiceRequest::message() const
+{ 
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::message");
+    XQSERVICE_DEBUG_PRINT("message: %s", qPrintable(mData->mMessage));
+    return mData->mMessage;
+}
+
+/*!
+    Gets the complete list of arguments for this service request.
+    \return List of arguments set to the request.
+    \sa setArguments()
+*/
+const QList<QVariant> &XQServiceRequest::arguments() const 
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::arguments");
+    return mData->mArguments; 
+}
+
+/*!
+    Sets \a arguments for this service request.
+    \param arguments Complete list of arguments for this service request
+                     i.e. the values to be transferred to service provider
+                     function to be called.
+    \sa arguments()
+*/
+void XQServiceRequest::setArguments(const QList<QVariant> &arguments)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setArguments");
+    mData->mArguments = arguments;
+}
+
+/*!
+    Gets the latest error that happened in the request execution.
+    \return The latest error that happened in the request execution.
+            Errors are defined in xqserviceglobal.h. 
+    \sa XQService::ServiceIPCErrors.
+*/
+int XQServiceRequest::latestError()
+    {
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::latestError");
+    return XQServiceAdaptor::latestError();
+    }
+
+/*!
+    Sets additional options for the request, like embedding or start to background.
+    \param info Additional info to be set to the request.
+    \sa info()
+*/
+void XQServiceRequest::setInfo(const XQRequestInfo &info)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setInfo");
+    mData->mRequestUtil.mInfo = info;
+}
+
+/*!
+    Gets current info set for the request.
+    \return Info data set to the request.
+    \sa setInfo()
+*/
+XQRequestInfo XQServiceRequest::info() const
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::info");
+    return mData->mRequestUtil.mInfo;
+}
+
+/*!
+    \internal
+    Adds the variant \a var to the list of arguments, so that the variant's
+    value is serialized in send() rather than the variant itself.
+*/
+void XQServiceRequest::addArg(const QVariant& v)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::addArg %s,%d", v.typeName());
+    XQSERVICE_DEBUG_PRINT("v: %s", qPrintable(v.toString()));
+    mData->mArguments.append(v);
+}
+
+/*!
+    \internal
+    Picks the XQSharableFile argument, if any, into the request util
+    This way scan parameter is listed only once.
+*/
+bool XQServiceRequest::handleSharableFileArgs()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::handleSharableFile");
+
+    bool ret = true;
+    mData->mRequestUtil.mSharableFileArgs.clear();
+    
+    for(int i=0; i < mData->mArguments.size(); i++)
+    {
+        if (QString(mData->mArguments[i].typeName()) == QString("XQSharableFile"))
+        {
+            XQSERVICE_DEBUG_PRINT("XQServiceRequest::sharable file detected");
+            // Pick up the sharable file(s) to utility so that no need to scan any more later
+            XQSharableFile file = mData->mArguments[i].value<XQSharableFile>();
+            if (!file.isValid())
+            {
+                // No point to pass invalid file handle onwards
+                XQSERVICE_DEBUG_PRINT("\t Invalid sharable file");
+                ret = false;
+                break;
+            }
+            if (mData->mRequestUtil.mSharableFileArgs.count() > 0)
+            {
+                XQSERVICE_DEBUG_PRINT("\t Too many sharable files");
+                ret = false;
+                break;
+            }
+            mData->mRequestUtil.mSharableFileArgs.append(file);
+            XQSERVICE_DEBUG_PRINT("XQServiceRequest::sharable file added");
+        }
+    }
+
+    if (!ret)
+    {
+        mData->mRequestUtil.mSharableFileArgs.clear();
+    }
+
+    return ret;
+}
+
+
+/*!
+    Serializes all the arguments from the service request.
+    \param action Defines the request having arguments to be serialized.
+    \return Serialized arguments in byte array.
+*/
+QByteArray XQServiceRequest::serializeArguments(const XQServiceRequest &action)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::serializeArguments");
+    QByteArray ret;
+    QBuffer *buffer = new QBuffer(&ret);
+    buffer->open(QIODevice::WriteOnly);
+    QDataStream stream(buffer);
+    stream << action.mData->mArguments;
+
+    delete buffer;
+    return ret;
+}
+/*!
+    Deserializes all the arguments from the byte array to service request.
+    \param action Defines the request where arguments are deserialized.
+    \param data Defines the byte array of serialized arguments.
+*/
+void XQServiceRequest::deserializeArguments(XQServiceRequest &action,
+        const QByteArray &data)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::deserializeArguments");
+    QDataStream stream(data);
+    stream >> action.mData->mArguments;
+}
+
+/*!
+    Serializes this request to the stream.
+    \param stream Defines stream this request is serialized to.
+*/
+template <typename Stream> void XQServiceRequest::serialize(Stream &stream) const
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::serialize");
+    stream << mData->mArguments;
+    stream << mData->mService;
+    stream << mData->mMessage;
+    stream << mData->mSynchronous;
+}
+
+/*!
+    Deserializes this request from the stream.
+    \param stream Defines the stream this request is deserialized from.
+*/
+template <typename Stream> void XQServiceRequest::deserialize(Stream &stream)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceRequest::deserialize");
+    stream >> mData->mArguments;
+    stream >> mData->mService;
+    stream >> mData->mMessage;
+    stream >> mData->mSynchronous;
+}
+
+Q_IMPLEMENT_USER_METATYPE(XQServiceRequest)