qthighway/xqservice/src/xqserviceprovider.cpp
branchRCL_3
changeset 22 5d007b20cfd0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qthighway/xqservice/src/xqserviceprovider.cpp	Tue Aug 31 16:02:37 2010 +0300
@@ -0,0 +1,758 @@
+/*
+* 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 <xqserviceprovider.h>
+#include <qmetaobject.h>
+#include <QByteArray>
+
+#include <xqserviceadaptor.h>
+//#include <xqserviceservice.h>
+#include <xqserviceutil.h>
+
+/*!
+    \class ServiceAdaptorProxy
+    \brief Proxy class for converting signal and slot members into IPC message names
+*/
+class ServiceAdaptorProxy : public XQServiceAdaptor
+{
+    Q_OBJECT
+
+public:
+    ServiceAdaptorProxy(const QString &channel, QObject *parent=0);
+    virtual ~ServiceAdaptorProxy() ;
+    
+    QString memberToMessage( const QByteArray& member );
+};
+
+ServiceAdaptorProxy::ServiceAdaptorProxy(const QString &channel, QObject *parent) :
+        XQServiceAdaptor(channel, parent) 
+{
+    XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::ServiceAdaptorProxy");
+    XQSERVICE_DEBUG_PRINT("channel: %s", qPrintable(channel));
+}
+
+ServiceAdaptorProxy::~ServiceAdaptorProxy()
+{
+    XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::~ServiceAdaptorProxy");
+}
+
+QString ServiceAdaptorProxy::memberToMessage( const QByteArray& member )
+{
+    XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::memberToMessage");
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+// TO BE CHECKED
+//    return m_channel + "::" + XQServiceAdaptor::memberToMessage( member );
+    return XQServiceAdaptor::memberToMessage( member );
+}
+
+/*!
+    \class XQServiceProvider_Private
+    \inpublicgroup QtBaseModule
+
+    \brief Private implementation of XQServiceProvider
+*/
+class XQServiceProvider_Private
+{
+public:
+    XQServiceProvider_Private(const QString &service);
+
+    ~XQServiceProvider_Private();
+    
+    XQServiceAdaptor *m_adaptor;
+
+    QString m_service;
+    bool m_publishAllCalled;
+    QObject* plugin;
+};
+
+XQServiceProvider_Private::XQServiceProvider_Private(const QString &service) :
+        m_adaptor(NULL),
+        m_service(service),
+        m_publishAllCalled(false),
+		plugin(NULL)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::XQServiceProvider_Private");
+    XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(service));
+    m_adaptor = new ServiceAdaptorProxy(service);
+}
+
+XQServiceProvider_Private::~XQServiceProvider_Private()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::~XQServiceProvider_Private");
+    delete m_adaptor;
+}
+
+/*!
+    \class XQServiceProvider
+    \inpublicgroup QtBaseModule
+
+    \brief The XQServiceProvider class provides an interface to messages on a XQService service
+    which simplifies remote slot invocations
+
+    Service messages consist of a service name, a message name, and a list of parameter values.
+    Qt extension dispatches service messages to the applications associated with the service
+    name, on the application's \c{QPE/Application/appname} channel, where
+    \c{appname} is the application's name.
+
+    <b>Service registration</b> \n
+    Service provider need to register it's service into the system before they can be used by
+    the service client. Registration is done by creating a XML formatted service configuration
+    file and defining the service in the provider's .pro-file. QMake will notice service provider
+    from the .pro-file, with help of the service.prf file, and generate a make file that uses
+    a helper application xqsreg.exe. The helper application sqsreg.exe will generate an application
+    registration resource file ( _reg.rss) from the configuration-file and provider's definitions
+    that include the needed declarations for the services provided.
+    
+    <b>Service Names Allocation</b> \n
+    The harmonize service and interface names the Symba specific names and guidelines can be found
+    from http://s60wiki.nokia.com/S60Wiki/QtFw_for_S60_coding_conventions/Service_name_registry#Service.
+
+    Before implementing a service you need to allocate the name according to the guidelines. Please
+    inform intended service clients (customers) and matti.parnanen@nokia.com.
+    
+    <b>Service Configuration File</b> \n
+    All the service configuration are added to the run-time service registry to make them available
+    for service discovery and creating service requests.
+    \note Only one service element with multiple interface is supported!
+    
+    To support services a new configuration was introduced to qmake and two new variables for
+    that configuration:
+    
+    \code
+        CONFIG = service
+        service.file = <service configuration file path>
+        service.options = <embeddable> (optional, default not embeddable), <hidden> (optional, default not hidden) 
+    \endcode
+    
+    The fornat of the service configuration file is same as XML format used in Qt Service Framework.
+    Example configuration file:
+    
+    \code
+        <?xml version="1.0" encoding="utf-8" ?>
+        <service>
+            <name>Music Fetcher</name>
+            <filepath>No path</filepath>
+            <description>Music Fetcher</description>
+            <interface>
+                <name><b>com.nokia.symbian.IMusicFetch</b></name>
+                <version>1.0</version>
+                <description>Interface for fetching music files</description>
+            </interface>
+        </service>
+    \endcode
+    
+    \code
+        <ELEMENT service ( name, filepath, description?, interface+ ) >
+        <ELEMENT description ( #CDATA ) >
+        <ELEMENT filepath ( #PCDATA ) >
+        <ELEMENT interface ( '''name''', version, description?, capabilities?, customproperty* ) >
+        <ELEMENT capabilities ( #PCDATA ) >
+        <ELEMENT name ( #PCDATA ) >
+        <ELEMENT version ( #PCDATA ) >
+        <ELEMENT customproperty ( #CDATA ) >
+        <ATTLIST customproperty key NMTOKEN #REQUIRED >
+    \endcode
+    
+    Also the old format described below is supported, With old format you can not have custom properties, which
+    for example are used for AIW purposes.
+    \code
+        <ELEMENT service ( description?, interface+ ) >
+        <ATTLIST service name #CDATA  #REQUIRED >
+        <ATTLIST service filepath #CDATA  #REQUIRED >
+        <ELEMENT description ( #CDATA ) >
+        <ELEMENT interface ( description? ) >
+        <ATTLIST interface '''name''' #CDATA  #REQUIRED >
+        <ATTLIST interface version #CDATA  #REQUIRED >
+        <ATTLIST interface capabilities #CDATA  #REQUIRED >
+    \endcode
+    
+    <b>Changing service or interface names</b> \n
+    Before you think about changing the name of the already released and used service implementation, read this
+    http://s60wiki.nokia.com/S60Wiki/QtFw_for_S60_coding_conventions/Service_name_registry#About_changing_service_or_interface_names
+    first.
+    
+    The basic message is the service name, interface name and operation (message) slot signatures for the API. And for API changes you have to apply development time API deprecation process.
+    
+    <b>Service Registration tools</b> \n
+    The needed utility files for service registration:
+    - xqsreg.exe should be in \epoc32\tools or some other directory that can be found from the path
+    - service.prf should be in \epoc32\tools\qt\mkspecs\features\symbian directory.
+    
+    If necessary you can copy those files to target directories from qthighway/bin.
+    
+    Sources for the xqsreg.exe can be found from the qthighway\xqsreg and it is also possible to compile it.
+        - cd \qthighway\xqsreg
+        - qmake -platform win32-mwc
+        - make
+    
+    Usage: \n
+    How to create a simple synchronously working service provider?
+    \code
+        class YourService : public XQServiceProvider
+            {
+            Q_OBJECT
+
+            public:
+                YourService ( ServiceApp *parent = 0 );
+                ~YourService ();
+
+            public slots:
+                void functionName1(); 
+                int functionName2(const QString& number, int times);
+
+            private:
+                ServiceApp *mServiceApp;
+            };
+    \endcode
+    
+    Implementation:
+    \code
+        YourService::YourService(ServiceApp* parent) 
+        : XQServiceProvider(QLatin1String("yourservice.Interface"), parent), mServiceApp(parent)
+            {
+            publishAll();
+            }
+
+        YourService::~YourService() { } 
+
+        void YourService::functionName1() { } 
+
+        int YourService::functionName2(const QString& number, int times)
+            {
+            int returnValue = 1;
+            return returnValue;
+            }
+    \endcode
+    
+    Additions to .pro-file:
+    \code
+        CONFIG += service
+        SERVICE.FILE = service_conf.xml
+        SERVICE.OPTIONS = embeddable
+        SERVICE.OPTIONS += hidden
+    \endcode
+    
+    Service configuration file (service_conf.xml):
+    \code
+    <?xml version="1.0" encoding="utf-8" ?>
+    <service>
+        <name>yourservice</name>
+        <filepath>No path</filepath>
+        <description>Service description</description>
+        <interface>
+            <name>Interface</name>
+            <version>1.0</version>
+            <description>Interface description</description>
+        </interface>
+    </service>
+    \endcode
+    
+    How to create a simple asynchronously working service provider?
+    Header:
+    \code
+        class YourService : public XQServiceProvider
+        {
+
+        Q_OBJECT
+
+        public:
+            YourService ( ServiceApp *parent = 0 );
+            ~YourService ();
+            void compleAsyncFunction();
+
+        public slots:
+            void functionName1(); 
+            int functionName2(const QString& number, int times);
+
+        private:
+            ServiceApp *mServiceApp;
+            int mAsyncRequestIndex;
+            QVariant mReturnValue;
+         
+        };
+    \endcode
+    
+    Implementation:
+    \code
+        YourService::YourService(ServiceApp* parent) 
+        : XQServiceProvider(QLatin1String("yourservice.Interface"), parent), mServiceApp(parent)
+            {
+            publishAll();
+            }
+
+        YourService::~YourService() { } 
+
+        void YourService::compleAsyncFunction()
+            {
+            completeRequest(mAsyncRequestIndex, mReturnValue);
+            }
+
+        void YourService::functionName1() 
+            { 
+            mAsyncRequestIndex = setCurrentRequestAsync();
+            mReturnValue.setValue(0);
+            } 
+
+        int YourService::functionName2(const QString& number, int times)
+            {
+            mAsyncRequestIndex = setCurrentRequestAsync();
+            mReturnValue.setValue(1);
+            return mReturnValue.toInt();
+            }
+    \endcode
+    
+    <b>Examples:</b> \n
+    The use of XQServiceProvider will be demonstrated using the \c{Time}
+    service.  This has a single message called \c{editTime()} which asks
+    the service to pop up a dialog allowing the user to edit the current time.
+    \code
+    class TimeService : public XQServiceProvider
+    {
+        Q_OBJECT
+    public:
+        TimeService( QObject *parent = 0 );
+
+    public slots:
+        void editTime(QTime time);
+    };
+
+    TimeService::TimeService( QObject *parent )
+        : XQServiceProvider( "Time", parent )
+    {
+        publishAll();
+    }
+    \endcode
+
+    The call to publishAll() causes all public slots within \c{TimeService}
+    to be automatically registered as Service messages.  This can be
+    useful if the service has many message types.
+
+    The client can send a request to the service using QtopiaServiceRequest:
+
+    \code
+    XQServiceRequest req( "Time", "editTime()" );
+    req << QTime::currentTime();
+    req.send();
+    \endcode
+    
+    <b>URI viewer</b> \n
+    This is a simple example for implementing out-of-process scheme handlers.
+    - "http", "https" and are handled via standard QDesktopServices::openUrl() function. 
+       This is fire-and-forget launch. The options are ignored and no control and signals available after the launch.
+    - "appto" is routed to Activity Manager for opening the attached activity.
+      This is fire-and-forget launch. The options are ignored and no control and signals available after the launch.
+    - The "file" scheme is handled as the QFile based create below. 
+      So the com.nokia.symbian.IFileView interface is applied as for the QFile.
+    
+    Service application needs to publish support for:
+    - The common interface "com.nokia.symbian.IUriView", and
+    - The scheme(s), like "testo" in the example below. The custom custom property "schemes" contains one or more schemes as comma separated list (CSV)
+    - The slot "view(QString)" to view the URI
+
+    \code
+        <?xml version="1.0" encoding="utf-8" ?>
+        <service>
+          <name>serviceapp</name>
+          <filepath>No path</filepath>
+          <description>Test service</description>
+          <interface>
+             <name>com.nokia.symbian.IUriView</name>
+             <version>1.0</version>
+             <description>Interface for showing URIs</description>
+             <customproperty key="schemes">testto</customproperty>
+           </interface>
+        </service>
+    \endcode
+    
+    An service application that offers support for a scheme implements the common "UriService" with the pre-defined "view" slot:
+    
+    \code
+        class UriService : public XQServiceProvider
+        {
+            Q_OBJECT
+            public:
+                UriService( ServiceApp *parent = 0 );
+                ~UriService();
+                bool asyncAnswer() {return mAsyncAnswer;}
+                void complete(bool ok);
+                
+            public slots:
+                bool view(const QString& uri);
+                
+            private slots:
+                void handleClientDisconnect();
+
+            private:
+                ServiceApp* mServiceApp;
+                bool mAsyncAnswer;
+                int mAsyncReqId;
+                bool mRetValue;
+        };
+    \endcode
+    
+    Client application accesses the service via the URI:
+    
+    \code
+        // Assume in example we have own scheme "testo" but this can be applied to 
+        // "mailto", etc. standard schemes.
+        //
+        // (As mentioned in the documentation, some schemes are CURRENTLY handled specially,
+        // like "http" scheme uses QDesktopServices::openUrl).  
+        // 
+        QUrl url("testto://authority?param1=value1&param1=value2"); 
+
+        // The difference to the previous example is is how request is created
+        // via application mgr.
+
+        request = mAiwMgr.create(url);
+        if (request == NULL)
+        {
+            // No handlers for the URI
+            return;
+         }
+
+        // Set function parameters
+        QList<QVariant> args;
+        args << uri.toSring();
+        request->setArguments(args);
+
+        // Send the request
+        bool res = request.send();
+        if  (!res) 
+        {
+            // Request failed. 
+            int error = request->lastError();
+            // Handle error
+        }
+
+        // If making multiple requests to same service, you can save the request as member variable
+        // In this example all done.
+        delete request;
+    \endcode
+   
+    <b>File viewer</b> \n
+    As for URis, a service application that support viewing a file with a dedicated MIME-type need to publish support for:
+    - The common interface "com.nokia.symbian.IFileView".
+    - The slot "view(QString)" to view the non-data-caged file by file name.
+    - The slot "view(XQSharable)" to view the data-caged file by sharable file handle.
+    - MIME type list (registered in the .pro file).
+    So there are multiple service applications implementing the same interface.
+    
+    In service provider side you need the following entry in XML:
+    
+    \code
+        <interface>
+            <name>com.nokia.symbian.IFileView</name>
+            <version>1.0</version>
+            <description>Interface for showing Files</description>
+        </interface>
+    \endcode
+    
+    The file viewer application shall offer slots both for viewing filename (QString) and viewing sharable file (XQSharable):
+    
+    \code
+    class FileService : public XQServiceProvider
+    {
+        Q_OBJECT
+        public:
+            FileService( ServiceApp *parent = 0 );
+            ~FileService();
+            bool asyncAnswer() {return mAsyncAnswer;}
+            void complete(bool ok);
+
+        public slots:
+            bool view(QString file);
+            bool view(XQSharableFile file);
+            
+        private slots:
+            void handleClientDisconnect();
+
+        private:
+            ServiceApp* mServiceApp;
+            bool mAsyncAnswer;
+            int mAsyncReqId;
+            bool mRetValue;
+    };
+    \endcode
+    
+    In the .pro file the service publishes the supported MIME types, e.g:
+    
+    \code
+        RSS_RULES += \
+          "datatype_list = " \
+          "      {" \
+          "      DATATYPE" \
+          "          {" \
+          "          priority = EDataTypePriorityNormal;" \
+          "          type = \"text/plain\";" \
+          "          }" \
+          "      };" \
+    \endcode
+    
+    In the client side (see the "examples/appmgrclient" and "examples/serviceapp" included in the QtHighway release) access to
+    file:
+    
+    \code
+        // Not data caged file
+        QFile file("C:\\data\\Others\\test.txt");
+
+        request = mAiwMgr.create(file);
+        if (request == NULL)
+        {
+               // No handlers for the URI
+               return;
+         }
+        // By default operation is "view(QString)"
+
+        // Set function parameters
+        QList<QVariant> args;
+        args << file.fileName();
+        request->setArguments(args);
+
+        // Send the request
+        bool res = request.send();
+        if  (!res) 
+        {
+           // Request failed. 
+          int error = request->lastError();
+
+          // Handle error
+        }
+     
+        // If making multiple requests to same service, you can save the request as member variable
+        // In this example all done.
+        delete request;
+    \endcode
+    
+    <b>Sharable file viewer</b> \n
+    The same rules as for file name based view applies, but different argument type (XQSharableFile) used
+    in request. See the "examples/appmgrclient" and "examples/serviceapp" included in the QtHighway release.
+    
+    \code
+        XQSharableFile sf;
+        // Open the file for sharing from own private  directory
+        // If you have handle available, just set it by "setHandle()" function
+        if (!sf.open("c:\\private\\e0022e74\\test.txt"))
+        {
+            // Failed to open sharable file
+            return;
+        }
+
+        // Create request for the sharable file
+        XQAiwreqiuest req = mAiwMgr.create(sf);
+        if (!req)
+        {
+            // No viewer app found for the file
+            // As we opened the handle, we need to close it !
+            sf.close(); 
+            return;  
+        }
+        // By default operation is "view(XQSharableFile)"
+
+        // Set function parameters
+        // Not only one sharable handle supported,  otherwise upon send EArgumentError error occurs
+        QList<QVariant> args;
+        args << qVariantFromValue(sf);  
+        req->setArguments(args);
+
+        // Send the request
+        bool res = request.send();
+        if  (!res) 
+        {
+            // Request failed. 
+            int error = request->lastError();
+            // Handle error
+        }
+
+        // As we opened the handle, we need to close it !
+        sf.close(); 
+
+        // If making multiple requests to same service, you can save the request as member variable
+        // In this example all done.
+        delete request;
+    \endcode
+    
+    <b> Create interface action </b> \n
+    One interface XML may offer one action to be displayed by client application.
+    See the "examples/appmgrclient" and "examples/hbserviceprovider" included in the QtHighway release.
+    
+    \code
+    HbAction* ShareUiPrivate::fetchServiceAction(XQAiwInterfaceDescriptor interfaceDescriptor)
+        {
+        QDEBUG_WRITE("ShareUiPrivate::fetchServiceAction start");
+        // create the request for each descriptor.
+        
+        XQAiwRequest* request = mAppManager.create(interfaceDescriptor,SELECT_OP,false);
+        QAction action = request->createAction());
+        if (!action)
+            return 0;
+
+        // if Orbit widgets do not support QAction
+        // Need to convert QAction to HbAction first
+        HbAction* hbAction = convertAction(action);
+        if(hbAction)
+            {
+            // Connect triggered signals to enable the request to emit triggered 
+            connect(hbAction, SIGNAL(triggered()), action, SIGNAL(triggered()));
+
+            // connect the request's triggered action to the slot in app
+            connect(request, SIGNAL(triggered()), this, SLOT(onTriggered()));
+            }
+            
+        return hbAction;
+        }
+    \endcode
+    
+    In service provider side you need to have the following entries in XML to be converted to QAction by the create:
+    
+    \code
+        <interface>
+            <name>Dialer></name>
+            <version=1.0</version>
+            <description>Dial interface</description>
+            <customproperty key="aiw_action_text_file">hbserviceprovider</customproperty>
+            <customproperty key="aiw_action_text">txt_aiw_action_text</customproperty>
+        </interface>
+    \endcode
+*/
+
+/*!
+    \fn void XQServiceProvider::returnValueDelivered()
+    
+    This signal is emitted when asynchronous request has been completed and its
+    return value has been delivered to the service client.
+*/
+
+/*!
+    \fn void XQServiceProvider::clientDisconnected()
+    
+    This signal is emitted if client accessing a service application terminates.
+    The counterpart in client side (when service application terminates) is
+    the error XQService::EConnectionClosed.
+*/
+
+/*!
+    Construct a remote service object for \a service and attach it to \a parent.
+    \param service Defines the full service name that is implemented. 
+                   The full service name is:
+                   - The name of the service from the service configuration file
+                   - Character *.* (dot)
+                   - The name of the interface from the service configuration file
+    \param parent Parent of this QObject
+*/
+XQServiceProvider::XQServiceProvider( const QString& service, QObject *parent )
+    : QObject( parent )
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceProvider::XQServiceProvider");
+    XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(service));
+    m_data = new XQServiceProvider_Private(service);
+    connect(m_data->m_adaptor, SIGNAL(returnValueDelivered()), this, SIGNAL(returnValueDelivered())); 
+    connect(m_data->m_adaptor, SIGNAL(clientDisconnected()), this, SIGNAL(clientDisconnected())); 
+}
+
+/*!
+    Destroys this service handling object.
+*/
+XQServiceProvider::~XQServiceProvider()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceProvider::~XQServiceProvider");
+    if (m_data)
+        delete m_data;
+}
+
+
+void XQServiceProvider::SetPlugin(QObject* impl_plugin)
+    {
+    m_data->plugin=impl_plugin;
+    }
+
+
+/*!
+    Publishes all slots on this object within subclasses of XQServiceProvider.
+    This is typically called from a subclass constructor.
+*/
+void XQServiceProvider::publishAll()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceProvider::publishAll");
+	if (!m_data->plugin) {
+	    m_data->m_adaptor->publishAll(this,XQServiceProvider::staticMetaObject.methodCount(),XQServiceAdaptor::Slots);
+	}
+    else {
+        m_data->m_adaptor->publishAll(m_data->plugin, 0, XQServiceAdaptor::Slots);
+    } 
+}
+
+/*!
+    Sets current request to asynchronous mode so that provider can complete the
+    request later via the completeRequest() call.
+    \return Request ID which shall be used in the completeRequest() call.
+    \note There can be several clients accessing the same service at the same time. Avoid saving
+          the index to XQServiceProvider instance as member variable as when another new request
+          comes in, it will have different index and you will potentially override the index of
+          the first request. You should ensure the completeRequest() gets the correct index e.g.
+          by attaching the index as user data to data object maintain a map of indexes based on
+          some key.
+*/
+int XQServiceProvider::setCurrentRequestAsync()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceProvider::setCurrentRequestAsync");
+    return m_data->m_adaptor->setCurrentRequestAsync();
+}
+
+/*!
+    \fn bool XQServiceProvider::completeRequest(int index, const T& retValue)
+    
+    Completes asynchronous request.
+    \param index Defines the index of the asynchronous request to complete. 
+    \param retValue defines the return value for the request.
+    \return true if request could be completed successfully, otherwise false.
+    \sa completeRequest()
+*/
+
+/*!
+    Completes the asynchronous request with the given value
+    \param index Request ID got from the setCurrentRequestAsync call.
+    \param retValue Returned value.
+    \return true on success, false if index points to non-existing request.
+    \note <b>You need to check the return value. </b>
+          If false it means connection to client has been lost and the complete will not ever succeed. 
+          So if you have e.g. a code that quits application using the ReturnValueDelived signal only,
+          that signal will never be emitted as request can not be completed.
+*/
+bool XQServiceProvider::completeRequest(int index, const QVariant& retValue)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceProvider::completeRequest");
+    XQSERVICE_DEBUG_PRINT("index: %d, retValue: %s", index, qPrintable(retValue.toString()));
+    return m_data->m_adaptor->completeRequest(index, retValue);
+}
+
+/*!
+    Return additional request information attached to request
+    \return Request info.
+*/
+XQRequestInfo XQServiceProvider::requestInfo() const
+{
+    return m_data->m_adaptor->requestInfo();
+}
+
+#include "xqserviceprovider.moc"